DescriptorHeapVulkan: a second heap-mode Initialize corrupts the slots still held (latent) #172
Labels
No labels
claude:blocked
claude:done
claude:failed
claude:in-progress
claude:ready
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Catcrafts/Crafter.Graphics#172
Loading…
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?
Summary
DescriptorHeapVulkan::Initializesays that in heap mode "a second call simply re-sizes the heap buffers". It also resets the bump pointers, empties the freelists and moves the buffer region, while theImageSlot,BufferSlotandSamplerSlothandles from the first call are still alive. Those handles then alias new allocations and convert to the wrong absolute index. Their slots can also be handed out again past the new capacity, where a descriptor write lands in the implementation's reserved range. Latent: nothing in the tree callsInitializetwice on one heap.Line numbers refer to
interfaces/Crafter.Graphics-DescriptorHeapVulkan.cppmat6e94cc6.What a second call does
:145-156setimageNext,bufferNextandsamplerNextto 0 and clear the freelists. The next allocation hands out slot 0 again while an old handle still owns it, such as aUIRenderer's swapchain image slot.BufferSlotconverts tobufferStartElement + raw(:625) against the new start.Releaseputs its raw slot on the freelist.AllocateBufferSlotspops a freelist entry without checking it against the new capacity (:434), so a slot past the new heap is handed out and written.Example, NVIDIA (32-byte image and 16-byte buffer descriptors):
Initialize(16, 16, 4)while aUIRendererholds buffer slots 0 to 10, thenInitialize(4, 4, 2). That fits the existing allocation, so it resizes in place: the buffers now start at byte 128 and the reserved range at 192. Destroying the handle of raw slot 10 frees it, the nextAllocateBufferSlots(1)returns it, and its descriptor is written atBufferByteOffset(10)= 128 + 160 = 288, inside the reserved range.Descriptor-set mode already refuses a second call (
:176).Window::Renderalso cached its heap-bind structs on the heap pointer, which a reallocating second call left stale; the #163 change removes that cache.Suggested fix
Refuse a second heap-mode
Initializethe wayInitializeSetsdoes, and fix the comment: a heap of another size is a newDescriptorHeapVulkan. If resizing in place is wanted, it has to require that no slot handle is alive, and check it.Found in a code review of the #163 change.