[5.8.3][Linux][Vulkan] Uniform buffer use-after-free at GC purge with runtime PCG generation (assert VulkanUniformBuffer.cpp:64)

Summary

In -game (packaged-style standalone launch), a World Partition map using runtime-generated, partitioned PCG (instanced static mesh output; cells generated and cleaned up as the camera moves) crashes on the RHI thread at a garbage-collection purge after cells have been cleaned up. Looks like a uniform buffer is freed at purge while still referenced by cached/parallel draw commands on the Vulkan bindless path.

Environment: UE 5.8.3 (CL 58210709, installed build), Linux (Arch-based, kernel 7.2), NVIDIA RTX 5090, driver 610.57.04, Vulkan SM6, BindlessConfiguration=All (engine default for Linux), hardware ray tracing on, Nanite and Lumen on.

Two alternating stacks:

  1. Assertion failed: Allocation.Size >= (16u*1024u) at Runtime/VulkanRHI/Private/VulkanUniformBuffer.cpp:64
    FVulkanUniformBuffer::SetupUniformBufferView ← BindUniformBuffer ← SetShaderParametersOnBinder ← FVulkanCommandListContext::RHISetShaderParameters ← FRHICommandSetShaderParameters::Execute
  2. SIGSEGV in libnvidia-eglcore ← FVulkanBindlessDescriptorManager::RegisterUniformBuffers ← UpdateBindlessDescriptors ← RHIDrawIndexedPrimitiveIndirect

GPU breadcrumbs: PrePass DDM_AllOpaqueNoVelocity (Forced by Nanite) / ParallelDraw, also Lumen DirectLighting, BuildHZB, VSM.

SetupUniformBufferView references UniformViewSRV->GetBuffer()->GetCurrentAllocation() with no lifetime guard (next to the in-source comment “//Adjust Allocation.Size ???”).

Isolation (crashes / runs):

  • gc.TimeBetweenPurgingPendingKillObjects=1800: 0/8 (masks it until a purge happens; memory grows to 23 GiB in 300 s)
  • r.Vulkan.NumFramesToWaitForResourceDelete=16: 0/6 in 60 s runs, but a 300 s run still crashed at the 3rd purge
  • r.Vulkan.NumFramesToWaitForResourceDelete=8: 1/6
  • Keeping PCG cells alive longer (hysteresis): 1/6
  • Non-incremental BeginDestroy: 1/6
  • PCG pooling off: 3/8
  • All ecology meshes Nanite: 3/6

Callstacks for both crashes are in the callstack field below; full engine logs available on request.

What Type of Bug are you experiencing?

Rendering (Graphics / Niagara)

Steps to Reproduce

  1. On Linux with an NVIDIA RTX GPU, use the default Vulkan SM6 RHI (BindlessConfiguration=All), with hardware ray tracing, Nanite and Lumen enabled.
  2. Create a World Partition level with several runtime-generated, partitioned PCG components (Generation Trigger = Generate At Runtime, partitioned grid, instanced static mesh spawner output, several grid sizes / ranges), using a PCG World Actor so cells generate and clean up around the player.
  3. Launch standalone with -game.
  4. Move the camera or pawn continuously through the level at ~13 m/s so that many PCG cells are generated and then cleaned up as they leave range.
  5. Wait for garbage-collection purges (default gc.TimeBetweenPurgingPendingKillObjects = 61 s).

Expected Result

PCG cells are generated and cleaned up as the camera moves, garbage-collection purges complete, and rendering continues without crashing.

Observed Result

The RHI thread crashes at the 2nd or 3rd GC purge (~124 s or ~184 s after launch) in about 1/3 to 2/3 of 60 s runs (~25 runs total): either the assert at VulkanUniformBuffer.cpp:64 (Allocation.Size >= 16KB) in SetupUniformBufferView, or a SIGSEGV in libnvidia-eglcore under FVulkanBindlessDescriptorManager::RegisterUniformBuffers. Deferring GC purges avoids it until the next purge; longer Vulkan resource-delete delays reduce it but do not remove it.

Affects Versions

5.8

Platform(s)

Linux

For crash reports, include your callstack

— Crash A (assert) —
Assertion failed: Allocation.Size >= (16u1024u) [File:./Runtime/VulkanRHI/Private/VulkanUniformBuffer.cpp] [Line: 64]
libUnrealEditor-Core.so!FDebug::CheckVerifyFailedImpl2
libUnrealEditor-VulkanRHI.so!FVulkanUniformBuffer::SetupUniformBufferView() [VulkanUniformBuffer.cpp:64]
libUnrealEditor-VulkanRHI.so!BindUniformBuffer(FVulkanCommandListContext&, FVulkanCommonPipelineDescriptorState&, FVulkanShader const
, EShaderFrequency, ShaderStage::EStage, …)
libUnrealEditor-VulkanRHI.so!SetShaderParametersOnBinder(FVulkanResourceBinder&, …)
libUnrealEditor-VulkanRHI.so!FVulkanCommandListContext::RHISetShaderParameters(FRHIGraphicsShader*, …)
libUnrealEditor-RHI.so!FRHICommandSetShaderParameters::Execute(FRHICommandListBase&)
libUnrealEditor-Engine.so!FRHICommand<FRHICommandSetShaderParameters, …>::ExecuteAndDestruct
libUnrealEditor-RHI.so!FRHICommandListBase::Execute() [RHICommandList.cpp:546]
libUnrealEditor-RHI.so!FRHICommandListExecutor::FTranslateState::Translate_ExecuteCommandList
libUnrealEditor-RHI.so!FRHICommandListExecutor::FTaskPipe::Execute
libUnrealEditor-Core.so!TGraphTask<…>::ExecuteTask()
libUnrealEditor-Core.so!LowLevelTasks::FScheduler::ExecuteTask

— Crash B (segfault) —
Unhandled Exception: SIGSEGV: unaligned memory access at address 0x0000000000000000
libnvidia-eglcore.so.610.57.04!UnknownFunction(0xc873b1)
libnvidia-eglcore.so.610.57.04!UnknownFunction(0xc8898c)
libUnrealEditor-VulkanRHI.so!FVulkanBindlessDescriptorManager::RegisterUniformBuffers(FVulkanCommandListContext&, unsigned int, TArrayView<VkWriteDescriptorSet const, int>)
libUnrealEditor-VulkanRHI.so!FVulkanGraphicsPipelineDescriptorState::UpdateBindlessDescriptors(FVulkanCommandListContext&)
libUnrealEditor-VulkanRHI.so!FVulkanPendingGfxState::PrepareForDraw(FVulkanCommandListContext&)
libUnrealEditor-VulkanRHI.so!FVulkanCommandListContext::RHIDrawIndexedPrimitiveIndirect(FRHIBuffer*, FRHIBuffer*, unsigned int)
libUnrealEditor-Renderer.so!FRHICommand<FRHICommandDrawIndexedPrimitiveIndirect, …>::ExecuteAndDestruct
libUnrealEditor-RHI.so!FRHICommandListBase::Execute() [RHICommandList.cpp:546]
libUnrealEditor-RHI.so!FRHICommandListExecutor::FTranslateState::Translate_ExecuteCommandList
libUnrealEditor-RHI.so!FRHICommandListExecutor::FTaskPipe::Execute
libUnrealEditor-Core.so!LowLevelTasks::FScheduler::WorkerLoop
libUnrealEditor-Core.so!FRunnableThreadPThread::Run()

Additional Notes

Every crash lines up with a GC purge after PCG runtime cleanup has released instanced static mesh components, so the suspected cause is a primitive/uniform buffer lifetime issue between component destruction at purge and draw commands still in flight on the Vulkan bindless path. Not yet tested: -norhithread, and BindlessConfiguration=Disabled (which would also disable Vulkan ray tracing). Full engine logs for both crashes are available on request. Happy to test a patch or CVar.