Crash in FNiagaraWorldManager during OnWorldBeginTearDown

FNiagaraWorldManager is a child of FGCObject and lives in a static TMap. It is responsible for registering its UObjects via AddReferencedObjects. However, if AddReferencedObjects is called after an Engine exit has been requested, UObject registration will not occur — this is known FGCObject behavior. If a LoadMap completes after Engine exit was requested, a new FNiagaraWorldManager would be created but would be unable to register its UObjects through AddReferencedObjects. A garbage collection pass will result in dangling pointers. Any access to these UObjects would then cause a crash. This access happens in FNiagaraWorldManager::OnWorldBeginTearDown() when the FNiagaraWorldManager is deferencing the component pool pointer.

[Attachment Removed]

Steps to Reproduce
After an engine exit was request, a map is loaded. During the loading, FNiagaraWorldManager is created, but because we requested an engine exit, the call of FNiagaraWorldManager to AddReferencedObjects is doing nothing. After the loading, the garbage collector can be called and create dangling pointers in the FNiagaraWorldManager. This will result in a crash during the world teardown.

To reproduce the crash, we need those 4 steps to happen:

  1. Engine Exit Request
  2. LoadMap
  3. GarbageCollect
  4. UnloadMap

To fix the issue, our tentative fix is to add in void FNiagaraWorldManager::OnWorldInit(UWorld* World, const UWorld::InitializationValues IVS):

void FNiagaraWorldManager::OnWorldInit(UWorld* World, const UWorld::InitializationValues IVS)
{
  if (IsEngineExitRequested())
  {		
    return;
  }
  ...

to avoid the creation of a FNiagaraWorldManager when an engine exit is requested.

[Attachment Removed]

Hi,

Thanks for the report, your tentative fix seems fine to me as we should handle a WM not being created for a world.

Thanks,

Stu

[Attachment Removed]