Fix use-after-free if BindGroup is the last owner of its BindGroupLayout
Destruction of the BindGroup needs to ensure that the BindGroupLayout is destroyed after the BindGroup. This is done by using a custom deleter which first creates an extra reference to the BGL before deleting the BindGroup. Bug: dawn:355 Change-Id: I819bbce13473ee4738eaa304f6dac90e0501302a Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/19060 Commit-Queue: Austin Eng <enga@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
parent
6574f92747
commit
26b7d8f6d7
|
@ -257,6 +257,14 @@ namespace dawn_native {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BindGroupBase::DeleteThis() {
|
||||||
|
// Add another ref to the layout so that if this is the last ref, the layout
|
||||||
|
// is destroyed after the bind group. The bind group is slab-allocated inside
|
||||||
|
// memory owned by the layout (except for the null backend).
|
||||||
|
Ref<BindGroupLayoutBase> layout = mLayout;
|
||||||
|
RefCounted::DeleteThis();
|
||||||
|
}
|
||||||
|
|
||||||
BindGroupBase::BindGroupBase(DeviceBase* device, ObjectBase::ErrorTag tag)
|
BindGroupBase::BindGroupBase(DeviceBase* device, ObjectBase::ErrorTag tag)
|
||||||
: ObjectBase(device, tag), mBindingData() {
|
: ObjectBase(device, tag), mBindingData() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ namespace dawn_native {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BindGroupBase(DeviceBase* device, ObjectBase::ErrorTag tag);
|
BindGroupBase(DeviceBase* device, ObjectBase::ErrorTag tag);
|
||||||
|
void DeleteThis() override;
|
||||||
|
|
||||||
Ref<BindGroupLayoutBase> mLayout;
|
Ref<BindGroupLayoutBase> mLayout;
|
||||||
BindGroupLayoutBase::BindingDataPointers mBindingData;
|
BindGroupLayoutBase::BindingDataPointers mBindingData;
|
||||||
|
|
|
@ -72,8 +72,12 @@ namespace dawn_native {
|
||||||
// memory barrier, when an acquire load on mRefCount (using the `ldar` instruction)
|
// memory barrier, when an acquire load on mRefCount (using the `ldar` instruction)
|
||||||
// should be enough and could end up being faster.
|
// should be enough and could end up being faster.
|
||||||
std::atomic_thread_fence(std::memory_order_acquire);
|
std::atomic_thread_fence(std::memory_order_acquire);
|
||||||
delete this;
|
DeleteThis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RefCounted::DeleteThis() {
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
|
|
@ -33,7 +33,10 @@ namespace dawn_native {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~RefCounted() = default;
|
virtual ~RefCounted() = default;
|
||||||
|
// A Derived class may override this if they require a custom deleter.
|
||||||
|
virtual void DeleteThis();
|
||||||
|
|
||||||
|
private:
|
||||||
std::atomic_uint64_t mRefCount;
|
std::atomic_uint64_t mRefCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -876,4 +876,23 @@ TEST_P(BindGroupTests, ArbitraryBindingNumbers) {
|
||||||
DoTest(red, black, blue, RGBA8(64, 0, 255, 0));
|
DoTest(red, black, blue, RGBA8(64, 0, 255, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a regression test for crbug.com/dawn/355 which tests that destruction of a bind group
|
||||||
|
// that holds the last reference to its bind group layout does not result in a use-after-free. In
|
||||||
|
// the bug, the destructor of BindGroupBase, when destroying member mLayout,
|
||||||
|
// Ref<BindGroupLayoutBase> assigns to Ref::mPointee, AFTER calling Release(). After the BGL is
|
||||||
|
// destroyed, the storage for |mPointee| has been freed.
|
||||||
|
TEST_P(BindGroupTests, LastReferenceToBindGroupLayout) {
|
||||||
|
wgpu::BufferDescriptor bufferDesc;
|
||||||
|
bufferDesc.size = sizeof(float);
|
||||||
|
bufferDesc.usage = wgpu::BufferUsage::Uniform;
|
||||||
|
wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
|
||||||
|
|
||||||
|
wgpu::BindGroup bg;
|
||||||
|
{
|
||||||
|
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
|
||||||
|
device, {{0, wgpu::ShaderStage::Vertex, wgpu::BindingType::UniformBuffer}});
|
||||||
|
bg = utils::MakeBindGroup(device, bgl, {{0, buffer, 0, sizeof(float)}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DAWN_INSTANTIATE_TEST(BindGroupTests, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend());
|
DAWN_INSTANTIATE_TEST(BindGroupTests, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend());
|
||||||
|
|
Loading…
Reference in New Issue