dawn::wire validate that the generation must be strictly increasing

Bug: chromium:1379634
Change-Id: Iaa067a30ac5992adfb5aac168104163a62f8bf9c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/108549
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Jie A Chen <jie.a.chen@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Austin Eng 2022-11-04 15:29:23 +00:00 committed by Dawn LUCI CQ
parent 6fcc4f3a54
commit dc819c939b
8 changed files with 66 additions and 18 deletions

View File

@ -47,7 +47,7 @@ namespace dawn::wire::server {
{% set Type = member.handle_type.name.CamelCase() %} {% set Type = member.handle_type.name.CamelCase() %}
{% set name = as_varName(member.name) %} {% set name = as_varName(member.name) %}
auto* {{name}}Data = {{Type}}Objects().Allocate(cmd.{{name}}.id); auto* {{name}}Data = {{Type}}Objects().Allocate(cmd.{{name}});
if ({{name}}Data == nullptr) { if ({{name}}Data == nullptr) {
return false; return false;
} }

View File

@ -72,6 +72,47 @@ TEST_F(WireInjectTextureTests, InjectExistingID) {
reservation.deviceGeneration)); reservation.deviceGeneration));
} }
// Test that injecting the same id without a destroy first fails.
TEST_F(WireInjectTextureTests, ReuseIDAndGeneration) {
// Do this loop multiple times since the first time, we can't test `generation - 1` since
// generation == 0.
ReservedTexture reservation;
WGPUTexture apiTexture = nullptr;
for (int i = 0; i < 2; ++i) {
reservation = GetWireClient()->ReserveTexture(device, &placeholderDesc);
apiTexture = api.GetNewTexture();
EXPECT_CALL(api, TextureReference(apiTexture));
ASSERT_TRUE(GetWireServer()->InjectTexture(apiTexture, reservation.id,
reservation.generation, reservation.deviceId,
reservation.deviceGeneration));
// Release the texture. It should be possible to reuse the ID now, but not the generation
wgpuTextureRelease(reservation.texture);
EXPECT_CALL(api, TextureRelease(apiTexture));
FlushClient();
// Invalid to inject with the same ID and generation.
ASSERT_FALSE(GetWireServer()->InjectTexture(apiTexture, reservation.id,
reservation.generation, reservation.deviceId,
reservation.deviceGeneration));
if (i > 0) {
EXPECT_GE(reservation.generation, 1u);
// Invalid to inject with the same ID and lesser generation.
ASSERT_FALSE(GetWireServer()->InjectTexture(
apiTexture, reservation.id, reservation.generation - 1, reservation.deviceId,
reservation.deviceGeneration));
}
}
// Valid to inject with the same ID and greater generation.
EXPECT_CALL(api, TextureReference(apiTexture));
ASSERT_TRUE(GetWireServer()->InjectTexture(apiTexture, reservation.id,
reservation.generation + 1, reservation.deviceId,
reservation.deviceGeneration));
}
// Test that the server only borrows the texture and does a single reference-release // Test that the server only borrows the texture and does a single reference-release
TEST_F(WireInjectTextureTests, InjectedTextureLifetime) { TEST_F(WireInjectTextureTests, InjectedTextureLifetime) {
ReservedTexture reservation = GetWireClient()->ReserveTexture(device, &placeholderDesc); ReservedTexture reservation = GetWireClient()->ReserveTexture(device, &placeholderDesc);

View File

@ -126,8 +126,8 @@ class KnownObjectsBase {
// Allocates the data for a given ID and returns it. // Allocates the data for a given ID and returns it.
// Returns nullptr if the ID is already allocated, or too far ahead, or if ID is 0 (ID 0 is // Returns nullptr if the ID is already allocated, or too far ahead, or if ID is 0 (ID 0 is
// reserved for nullptr). Invalidates all the Data* // reserved for nullptr). Invalidates all the Data*
Data* Allocate(uint32_t id, AllocationState state = AllocationState::Allocated) { Data* Allocate(ObjectHandle handle, AllocationState state = AllocationState::Allocated) {
if (id == 0 || id > mKnown.size()) { if (handle.id == 0 || handle.id > mKnown.size()) {
return nullptr; return nullptr;
} }
@ -135,17 +135,24 @@ class KnownObjectsBase {
data.state = state; data.state = state;
data.handle = nullptr; data.handle = nullptr;
if (id >= mKnown.size()) { if (handle.id >= mKnown.size()) {
mKnown.push_back(std::move(data)); mKnown.push_back(std::move(data));
return &mKnown.back(); return &mKnown.back();
} }
if (mKnown[id].state != AllocationState::Free) { if (mKnown[handle.id].state != AllocationState::Free) {
return nullptr; return nullptr;
} }
mKnown[id] = std::move(data); // The generation should be strictly increasing.
return &mKnown[id]; if (handle.generation <= mKnown[handle.id].generation) {
return nullptr;
}
// update the generation in the slot
data.generation = handle.generation;
mKnown[handle.id] = std::move(data);
return &mKnown[handle.id];
} }
// Marks an ID as deallocated // Marks an ID as deallocated
@ -193,8 +200,8 @@ class KnownObjects<WGPUDevice> : public KnownObjectsBase<WGPUDevice> {
public: public:
KnownObjects() = default; KnownObjects() = default;
Data* Allocate(uint32_t id, AllocationState state = AllocationState::Allocated) { Data* Allocate(ObjectHandle handle, AllocationState state = AllocationState::Allocated) {
Data* data = KnownObjectsBase<WGPUDevice>::Allocate(id, state); Data* data = KnownObjectsBase<WGPUDevice>::Allocate(handle, state);
AddToKnownSet(data); AddToKnownSet(data);
return data; return data;
} }

View File

@ -54,7 +54,7 @@ bool Server::InjectTexture(WGPUTexture texture,
return false; return false;
} }
ObjectData<WGPUTexture>* data = TextureObjects().Allocate(id); ObjectData<WGPUTexture>* data = TextureObjects().Allocate(ObjectHandle{id, generation});
if (data == nullptr) { if (data == nullptr) {
return false; return false;
} }
@ -81,7 +81,7 @@ bool Server::InjectSwapChain(WGPUSwapChain swapchain,
return false; return false;
} }
ObjectData<WGPUSwapChain>* data = SwapChainObjects().Allocate(id); ObjectData<WGPUSwapChain>* data = SwapChainObjects().Allocate(ObjectHandle{id, generation});
if (data == nullptr) { if (data == nullptr) {
return false; return false;
} }
@ -99,7 +99,7 @@ bool Server::InjectSwapChain(WGPUSwapChain swapchain,
bool Server::InjectDevice(WGPUDevice device, uint32_t id, uint32_t generation) { bool Server::InjectDevice(WGPUDevice device, uint32_t id, uint32_t generation) {
ASSERT(device != nullptr); ASSERT(device != nullptr);
ObjectData<WGPUDevice>* data = DeviceObjects().Allocate(id); ObjectData<WGPUDevice>* data = DeviceObjects().Allocate(ObjectHandle{id, generation});
if (data == nullptr) { if (data == nullptr) {
return false; return false;
} }
@ -121,7 +121,7 @@ bool Server::InjectDevice(WGPUDevice device, uint32_t id, uint32_t generation) {
bool Server::InjectInstance(WGPUInstance instance, uint32_t id, uint32_t generation) { bool Server::InjectInstance(WGPUInstance instance, uint32_t id, uint32_t generation) {
ASSERT(instance != nullptr); ASSERT(instance != nullptr);
ObjectData<WGPUInstance>* data = InstanceObjects().Allocate(id); ObjectData<WGPUInstance>* data = InstanceObjects().Allocate(ObjectHandle{id, generation});
if (data == nullptr) { if (data == nullptr) {
return false; return false;
} }

View File

@ -28,7 +28,7 @@ bool Server::DoAdapterRequestDevice(ObjectId adapterId,
return false; return false;
} }
auto* resultData = DeviceObjects().Allocate(deviceHandle.id, AllocationState::Reserved); auto* resultData = DeviceObjects().Allocate(deviceHandle, AllocationState::Reserved);
if (resultData == nullptr) { if (resultData == nullptr) {
return false; return false;
} }

View File

@ -110,7 +110,7 @@ bool Server::DoDeviceCreateBuffer(ObjectId deviceId,
} }
// Create and register the buffer object. // Create and register the buffer object.
auto* resultData = BufferObjects().Allocate(bufferResult.id); auto* resultData = BufferObjects().Allocate(bufferResult);
if (resultData == nullptr) { if (resultData == nullptr) {
return false; return false;
} }

View File

@ -99,7 +99,7 @@ bool Server::DoDeviceCreateComputePipelineAsync(ObjectId deviceId,
} }
auto* resultData = auto* resultData =
ComputePipelineObjects().Allocate(pipelineObjectHandle.id, AllocationState::Reserved); ComputePipelineObjects().Allocate(pipelineObjectHandle, AllocationState::Reserved);
if (resultData == nullptr) { if (resultData == nullptr) {
return false; return false;
} }
@ -143,7 +143,7 @@ bool Server::DoDeviceCreateRenderPipelineAsync(ObjectId deviceId,
} }
auto* resultData = auto* resultData =
RenderPipelineObjects().Allocate(pipelineObjectHandle.id, AllocationState::Reserved); RenderPipelineObjects().Allocate(pipelineObjectHandle, AllocationState::Reserved);
if (resultData == nullptr) { if (resultData == nullptr) {
return false; return false;
} }

View File

@ -29,7 +29,7 @@ bool Server::DoInstanceRequestAdapter(ObjectId instanceId,
return false; return false;
} }
auto* resultData = AdapterObjects().Allocate(adapterHandle.id, AllocationState::Reserved); auto* resultData = AdapterObjects().Allocate(adapterHandle, AllocationState::Reserved);
if (resultData == nullptr) { if (resultData == nullptr) {
return false; return false;
} }