"FPrimitiveSceneInfo::StaticMeshRelevances" is invalid, causing crashes in various rendering callstacks.

Hello,

We’re in the process of upgrading from UE 5.4 to UE 5.7. We DID NOT take any intermediate engine versions.

There’s an issue we’re running into pretty consistently where “FPrimitiveSceneInfo::StaticMeshRelevances” are invalid.

We’ve hit the same issue across multiple callstacks, and it’s happened with various meshes in the game, non of which seem to be broken.

When this occurs:

  • It seems to happen with StatisMeshComponents
  • The Owning Actor hasn’t had BeginPlay called yet
  • The level is not visible either (ULevel::bVisible = false).

This is happening in Cooked / Staged builds.

We are using World Partition, if that makes a difference.

[Image Removed]

[Attachment Removed]

Steps to Reproduce
N/A

[Attachment Removed]

Hello,

Are you running into these issues with HLODs? It looks like the mesh in the image is non-Nanite, but I’m wondering if you are running into an issue that may be fallout from a change described here: [Content removed]

With 5.5 there was a change to FSceneProxyBase::DrawStaticElementsInternal() where the implementation was removed (https://github.com/EpicGames/UnrealEngine/commit/5739cb4af91a567636130f3e834340688ce64f81#diff-f40cf666070ac7a046890af0c957a44e9d339333c98708b037434702d9133aeb). This means that the FPrimitiveSceneInfo structure for nanite-enabled HLODs no longer have their StaticMeshes and StaticMeshRelevances properties set.

We have an issue tracking this but it hasn’t been resolved yet https://issues.unrealengine.com/issue/UE-256684

If you can easily reproduce the crash, it might be helpful to reproduce with -stompmalloc to see if it can identify a memory stomp.

[Attachment Removed]

Hi,

I have tried running with double the Double Free Finder malloc and Stomp Malloc, and neither have crashed on / reported anything obvious.

Did it catch any invalid writes? I’d be especially interested if the invalid write was in FStaticMeshSceneProxy::DrawStaticElements with an invalid RenderData.

When I did, I hit a crash in `FInstanceCullingLoadBalancerBase`

The InstanceDataOffset being invalid could be from heap corruption.

I wonder if its possible that the offset being invalid is causing a memory overwrite?

This is unlikely, at least of the CPU memory. It’s possible a nearby write caused the FPrimitiveSceneInfo for that LandscapeComponentSceneProxy to be corrupted.

When you upgraded to 5.7 did you have any custom engine code changes that you had to integrate/resolve or does all this code match the engine’s vanilla 5.7 code?

If you’re able to reproduce this crash in a simplified scene or in vanilla 5.7 that could help narrow things down.

[Attachment Removed]

Alex,

Here is another example call stack:

TMallocBinnedCommon::QuantizeSizeCommon(unsigned long long, unsigned int, const FMallocBinned2 &) MallocBinnedCommon.h:869
[Inlined] DefaultCalculateSlackReserve(int, unsigned long long, bool, unsigned int) ContainerAllocationPolicies.h:229
[Inlined] TSizedHeapAllocator::ForAnyElementType::CalculateSlackReserve(int, unsigned long long, unsigned int) ContainerAllocationPolicies.h:756
UE::Core::Private::ReallocTo<…>(unsigned int, unsigned int, int, TSizedHeapAllocator<…>::ForAnyElementType &, int, int &) Array.h:589
[Inlined] TArray::Shrink() Array.h:1283
`FPrimitiveSceneInfo::AddStaticMeshes'::`3'::<lambda_1>::operator()(int) PrimitiveSceneInfo.cpp:1552
[Inlined] ParallelForImpl::CallBody(const <lambda_1> &, const TArrayView<…> &, int, int) ParallelFor.h:81
`ParallelForImpl::ParallelForInternal<`FPrimitiveSceneInfo::AddStaticMeshes'::`3'::<lambda_1>,`ParallelForTemplate<`FPrimitiveSceneInfo::AddStaticMeshes'::`3'::<lambda_1> >'::`2'::<lambda_1>,std::nullptr_t>'::`2'::FParallelExecutor::operator()(const bool) ParallelFor.h:360
[Inlined] LowLevelTasks::FTask::Init::__l13::<lambda_1>::operator()(const bool) Task.h:499
[Inlined] Invoke(LowLevelTasks::FTask::<lambda_1> &, bool &) Invoke.h:47
[Inlined] LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<`LowLevelTasks::FTask::Init<`ParallelForImpl::ParallelForInternal<`FPrimitiveSceneInfo::AddStaticMeshes'::`3'::<lambda_1>,`ParallelForTemplate<`FPrimitiveSceneInfo::AddStaticMeshes'::`3'::<lambda_1> >'::`2'::<lambda_1>,std::nullptr_t>'::`2'::FParallelExecutor>'::`13'::<lambda_1>,0>::Call(void *,bool) TaskDelegate.h:162
LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<`LowLevelTasks::FTask::Init<`ParallelForImpl::ParallelForInternal<`FPrimitiveSceneInfo::AddStaticMeshes'::`3'::<lambda_1>,`ParallelForTemplate<`FPrimitiveSceneInfo::AddStaticMeshes'::`3'::<lambda_1> >'::`2'::<lambda_1>,std::nullptr_t>'::`2'::FParallelExecutor>'::`13'::<lambda_1>,0>::CallAndMove(LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48> &,void *,unsigned int,bool) TaskDelegate.h:171
[Inlined] LowLevelTasks::TTaskDelegate::CallAndMove(LowLevelTasks::TTaskDelegate<…> &, bool) TaskDelegate.h:309
LowLevelTasks::FTask::ExecuteTask() Task.h:627
[Inlined] FCpuProfilerTrace::FEventScope::{ctor}(unsigned int &,const char *,bool,const char *,unsigned int) CpuProfilerTrace.h:197
LowLevelTasks::FScheduler::ExecuteTask(LowLevelTasks::FTask *) Scheduler.cpp:396
[Inlined] LowLevelTasks::FScheduler::TryExecuteTaskFrom(LowLevelTasks::Private::FWaitEvent *, LowLevelTasks::Private::TLocalQueueRegistry<…>::TLocalQueue *, LowLevelTasks::Private::FOutOfWork &, bool) Scheduler.cpp:698
LowLevelTasks::FScheduler::WorkerLoop(LowLevelTasks::Private::FWaitEvent *, LowLevelTasks::Private::TLocalQueueRegistry<…>::TLocalQueue *, unsigned int, bool) Scheduler.cpp:757
[Inlined] LowLevelTasks::FScheduler::WorkerMain(LowLevelTasks::Private::FWaitEvent *, LowLevelTasks::Private::TLocalQueueRegistry<…>::TLocalQueue *, unsigned int, bool) Scheduler.cpp:816
`LowLevelTasks::FScheduler::CreateWorker'::`2'::<lambda_1>::operator()() Scheduler.cpp:220
[Inlined] UE::Core::Private::Function::TFunctionRefBase::operator()() Function.h:414
FThreadImpl::Run() Thread.cpp:66
FRunnableThreadWin::Run() WindowsRunnableThread.cpp:156
FRunnableThreadWin::GuardedRun() WindowsRunnableThread.cpp:79

I have tried running with double the Double Free Finder malloc and Stomp Malloc, and neither have crashed on / reported anything obvious.

This happens to both Nanite and non-Nanite meshes.

Would there be an easy way to tell in the debugger if the mesh in question was an HLOD?

[Attachment Removed]

Alex,

Maybe another data point. I decided to try running the game in `Debug` mode.

When I did, I hit a crash in `FInstanceCullingLoadBalancerBase`. Specifically this check:

checkSlow(InstanceDataOffset < (1U << (32U - NumInstancesItemBits)));

I added a similar check in `FMeshPassProcessor::GetDrawCommandPrimitiveId` to try and see what Mesh(es) may be causing it.

This was for a `LandscapeComponentSceneProxy` if it matters.

It’s happening in a similar callstack (`FScene::Update`). I’m not that familiar with how this code is supposed to work, but I wonder if its possible that the offset being invalid is causing a memory overwrite?

[Image Removed]

[Attachment Removed]