[infra] Fence-keyed deferred resource-deletion queue (UAF since #40; unblocks #63/#66) #101
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Catcrafts/Crafter.Graphics#101
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Subsystem: Device / VulkanBuffer — resource lifetime
Impact: Correctness (live UAF since #40 landed) + enabler · Effort: Medium
Prerequisite-for / unblocks: #63 (Resize destroys old buffer immediately), #66 (scratch release), #62/#67 (pool recycling)
Problem
Since #40 (per-frame fences, no per-frame
vkQueueWaitIdle) landed, frames are pipelined: a resource the CPU is "done" with may still be read by the GPU for up tonumFrames-1more frames. ButVulkanBuffer::Clear()/Resize()(interfaces/Crafter.Graphics-VulkanBuffer.cppm:123-153) destroy + free immediately.Resize's destroy-and-recreate path is now a live use-after-free whenever an in-flight frame still references the old buffer (the #63 hazard, no longer masked by wait-idle).Fix — fence-keyed deferred deletion queue
Device(all-inline staticsingleton) gains:Window::Render: after the existingvkWaitForFences(waitFences[currentBuffer])(Window.cpp:786) callDevice::ReclaimDeletions(); bumpframeCounteronce per frame; setframesInFlightat init; callDrainDeletions()on the resize/teardown wait-idle paths.VulkanBuffer::DeferredClear()hands{buffer, memory}toEnqueueDeletionand nulls the handle (mapped memory is implicitly unmapped byvkFreeMemory).Resize()usesDeferredClear()instead ofClear().Decisions
~VulkanBufferkeepsClear()); onlyResize()+ explicitDeferredClear()defer. Callers destroying objects mid-flight remain responsible (unchanged from today).DeferredClear, and convertResizeto use it (closes #63). #66 scratch release is a follow-up on top.Correctness
An entry tagged at frame F is freed only once the fence for frame F has been waited (at F+framesInFlight); single-queue submission order then guarantees all <=F GPU work is complete. The one-shot immediate submits that still
vkQueueWaitIdle(Window.cpp:1077/1102/1267) are synchronous and may keep immediateClear().