[UE 5.8.2] Render thread crash (null UWorld deref) in FComputeViewExtension::GetFlags() during map travel with HW ray tracing

Summary

Engine: 5.8.2 (source build). The code is unchanged on ue5-main as of Nov 2026.
Platform / RHI: Windows 64-bit, D3D12, Development (packaged game)
Crash GUID: UECC-Windows-2D88016E44A335279D969F99C9934A4D_0000

FComputeViewExtension::GetFlags() (ComputeFramework plugin) runs on the render thread and dereferences the extension’s TWeakObjectPtr<UWorld>. The game thread can destroy that world during LoadMap at the same time. The weak pointer is validated with IsValid() and then dereferenced again through operator->, which calls Get() a second time. If the world is invalidated between those two calls, Get() returns nullptr and the render thread crashes.

Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x0000000000000258

The low address points to a null-pointer member access, consistent with WorldPtr->Scene on a null UWorld*.

Faulty code: Engine/Plugins/Runtime/ComputeFramework/Source/ComputeFramework/Private/ComputeViewExtension.cpp

ESceneViewExtensionFlags FComputeViewExtension::GetFlags() const
{
    const TWeakObjectPtr<UWorld> WorldPtr = GetWorld();

    // Race: IsValid() and operator-> each resolve the weak pointer separately.
    if (const FSceneInterface* Scene = WorldPtr.IsValid() ? WorldPtr->Scene : nullptr)
    {
        ComputeWorkers.Empty(ComputeWorkers.Num());   // mutable member used as scratch buffer
        Scene->GetComputeTaskWorkers(ComputeWorkers);
        ...

PostTLASBuild_RenderThread() uses the same pattern.

There are two problems:

  1. A UWorld is accessed from the render thread while the game thread may be destroying it.
  2. mutable TArray ComputeWorkers is used as a scratch buffer. It is not thread-safe if several view families for the same world call GetFlags() concurrently.

This code path seems to have been introduced in commit 344f81b (“[PCG] Add engine infrastructure for PCG GPU inline ray tracing”, March 26, 2026).

What Type of Bug are you experiencing?

Rendering (Graphics / Niagara)

Steps to Reproduce

  1. Create a project with r.RayTracing=True and the ComputeFramework plugin enabled.
  2. Package a Development build.
  3. Run a loop that calls OpenLevel between three small maps continuously (we use Attract → Round → Outro, one transition every ~3–4 s).
  4. Leave it running. In our case the crash happened after ~9 h (~700 LoadMap calls); the race window is very narrow.

Expected Result

No crash during map travel.

Observed Result

Access violation (reading 0x258) on the render thread in FComputeViewExtension::GetFlags() while the previous world is being torn down in LoadMap.

Affects Versions

5.8

Platform(s)

Windows

For crash reports, include your callstack

Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x0000000000000258

RenderThread:
FComputeViewExtension::GetFlags() Line 53
FDeferredShadingSceneRenderer::SetupRayTracingRenderingData(FRDGBuilder & GraphBuilder, RayTracing::FGatherInstancesTaskData & RayTracingGatherInstancesTaskData) Line 1160
FDeferredShadingSceneRenderer::Render(FRDGBuilder & GraphBuilder, const FSceneRenderUpdateInputs * SceneUpdateInputs) Line 3035
RenderViewFamily_RenderThread(FRDGBuilder & GraphBuilder, FSceneRenderer * Renderer, const FSceneRenderUpdateInputs * SceneUpdateInputs) Line 5232
[Inline Frame] FRendererModule::BeginRenderingViewFamilies::__l130::(FRDGBuilder &) Line 5527
FRendererModule::BeginRenderingViewFamilies::<lambda_invoker_cdecl> Line 5529
FSceneRenderProcessor::Execute::__l32::(FRHICommandListImmediate & RHICmdList) Line 895
ExecuteCommand(…) Line 1534
UE::RenderCommandPipe::FCommandList::ConsumeCommands<…> Line 336
FRenderThreadCommandPipe::EnqueueAndLaunch::__l5::<lambda_1>::operator()() Line 1928
TGraphTask<TFunctionGraphTaskImpl<void __cdecl(void),1>>::ExecuteTask() Line 704
UE::Tasks::Private::FTaskBase::TryExecuteTask() Line 525
FNamedTaskThread::ProcessTasksNamedThread(int QueueIndex, bool bAllowStall) Line 807
FNamedTaskThread::ProcessTasksUntilQuit(int QueueIndex) Line 696
RenderingThreadMain(FEvent * TaskGraphBoundSyncEvent) Line 262
FRenderingThread::Run() Line 390
FRunnableThreadWin::Run() Line 167
FRunnableThreadWin::GuardedRun() Line 87

Log context at time of crash:
LogLoad: LoadMap: /Game/…/MAP_Round01
LogWorld: BeginTearingDown for /Game/…/MAP_Attract
LogWorld: UWorld::CleanupWorld for MAP_Attract, bSessionEnded=true, bCleanupResources=true

Additional Notes

Suggested fix
Do not touch the UWorld from the render thread. FComputeFrameworkSystem::CreateWorkers() already receives the FSceneInterface*, so it can be passed to the extension and cached. The FScene is released through a render command (Scene->Release()), so it stays valid for the duration of any frame already in flight. Replace the mutable member with a local array:

// ComputeSystem.cpp
ViewExtensions.Add(InScene, FSceneViewExtensions::NewExtension<FComputeViewExtension>(World, InScene));

// ComputeViewExtension.cpp
ESceneViewExtensionFlags FComputeViewExtension::GetFlags() const
{
    if (Scene)
    {
        TArray<IComputeTaskWorker*, TInlineAllocator<8>> Workers;
        Scene->GetComputeTaskWorkers(Workers);
        for (IComputeTaskWorker* Worker : Workers)
        {
            if (Worker->HasWork(ComputeTaskExecutionGroup::PostTLASBuild))
            {
                return ESceneViewExtensionFlags::SubscribesToPostTLASBuild
                     | ESceneViewExtensionFlags::RequiresHardwareInlineRayTracing;
            }
        }
    }
    return ESceneViewExtensionFlags::None;
}
// Same change in PostTLASBuild_RenderThread().

Workaround: set r.RayTracing=False. Both call sites of GetFlags() in FDeferredShadingSceneRenderer (lines 1160 and 3314) are behind IsRayTracingEnabled().

Minidump, CrashContext.runtime-xml and the full log are available on request.