Fixes since 4.27 for crashes due to garbage collection invalidating actors pointed to by soft-object references in Details panel UI?

We have a some persistent recurring editor crashes in UE4.27 - I am guessing it is something that has since been fixed, and wondering if it might be a fix I can integrate into our engine.

Basically, we have some blueprints that have as variables some Soft Pointers to objects in the level. When those blueprints are selected, the details panel shows the name of the object pointed to by the variable.

When we start a PIE session, startup code can sometimes destroy and recreate these objects pointed to. If garbage collection happens then, the editor will crash. We can avoid the crash by not having the object selection, so that it isn’t trying to display the value - but people forget to do that.

Anyone know of any fixes that went into UE5 to fix this issue, and if it would be something I could bring into our version of 4.27?

Steps to Reproduce

Hey Bob,

apologies for the wait, this has been bouncing around internally a bit until we found someone with more context regarding 4.27.

I’ve assigned to the Editor team now and we’ll hopefully be able to give you an answer soon!

Kind Regards,

Sebastian

Hello Bob!

It looks like the StaticFindObject function is being called while GC is happening, which will fire a crash. I have a possible solution for you that should fix it as it won’t allow the UI to refresh while GC is taking place in this case. In the file: USDStageActor.cpp add !IsGarbageCollecting() at the given lines to look like the following:

1140 if ( GIsEditor && GEditor && !IsGarbageCollecting() ) // Make sure we're not in standalone either``1541 if ( GIsEditor && GEditor && !IsGarbageCollecting() )``1595 if ( GEditor && !IsGarbageCollecting() )``2358 if ( GIsEditor && GEditor && !IsGarbageCollecting() )I hope this fixes the problem, but if this doesn’t work, please provide a log and repro steps so I can better diagnose the issue!

Best,

Jayden

Thanks for the update! Are they still getting the exact same error log/call stack?

Thanks Jayden, I will try this!

Unfortunately he still gets the crash - Illegal call to Static Find Object while collecting garbage.

Maybe there are some other places that need that same check?

Hi Bob, looking at the callstack this spot seems odd:

SActorDetails::SetObjects(const TArray<…> &, bool) SActorDetails.cpp:237 SLevelEditor::OnActorSelectionChanged(const TArray<…> &, bool) SLevelEditor.cpp:1765SLevelEditor::OnActorSelectionChanged forwards a selection change notification to the active editor modes, but I do not see that in the callstack provided. It’s possible it was optimized out, so I’m curious if your group is using any custom U/FEditorModes that may be active that are causing the details panel to try to refresh in this way, that may be holding stale pointers. One other question is if there are local engine modifications within that SLevelEditor function, those should be removed or updated to not fire until the selection is updated for the PIE world using the PIE start/end delegates.

No, that function should process entirely on the main thread.

The only other thing I can think of is that the details panel is locked to the editor world view of the object, but this also doesn’t align to the callstack that is posted. The objects should also be entirely separate between the editor world and game world, the game world should recreate the entire world state for the PIE world, without impacting the editor world. It seems odd that the editor world objects would be getting recreated as part of PIE init.

Hello Jayden, sorry for the long delay. We are still getting the crash - I’m attaching a callstack. Please let me know if you have any other suggestions? For now I have implemented a thing to automatically deselect everything when starting PIE, but it’s not ideal…

[Inlined] FindObject(UObject *, const wchar_t *, bool) UObjectGlobals.h:1301

FSoftObjectPath::ResolveObjectInternal(const wchar_t *) SoftObjectPath.cpp:506

FSoftObjectPath::ResolveObjectInternal() SoftObjectPath.cpp:500

FSoftObjectPath::ResolveObject() SoftObjectPath.cpp:482

[Inlined] FSoftObjectPtr::Get() SoftObjectPtr.h:99

FSoftObjectProperty::GetObjectPropertyValue(const void *) PropertySoftObjectPtr.cpp:202

FObjectPropertyNode::GetReadAddressUncached(const FPropertyNode &, bool, FReadAddressListData *, bool, bool, bool) ObjectPropertyNode.cpp:362

FPropertyNode::InitNode(const FPropertyNodeInitParams &) PropertyNode.cpp:163

FCategoryPropertyNode::InitChildNodes() CategoryPropertyNode.cpp:106

FPropertyNode::RebuildChildren() PropertyNode.cpp:246

FPropertyNode::InitNode(const FPropertyNodeInitParams &) PropertyNode.cpp:223

FObjectPropertyNode::InternalInitChildNodes(FName) ObjectPropertyNode.cpp:649

FObjectPropertyNode::InitChildNodes() ObjectPropertyNode.cpp:458

FPropertyNode::RebuildChildren() PropertyNode.cpp:246

FPropertyNode::InitNode(const FPropertyNodeInitParams &) PropertyNode.cpp:223

SDetailsView::PostSetObject(const TArray<…> &) SDetailsView.cpp:872

SDetailsView::SetObjectArrayPrivate(const TArray<…> &) SDetailsView.cpp:646

SDetailsView::SetObjects(const TArray<…> &, bool, bool) SDetailsView.cpp:416

SActorDetails::SetObjects(const TArray<…> &, bool) SActorDetails.cpp:237

SLevelEditor::OnActorSelectionChanged(const TArray<…> &, bool) SLevelEditor.cpp:1765

[Inlined] Invoke(void (SLevelEditor::*)(const TArray<…> &, bool), SLevelEditor *&, const TArray<…> &, bool &) Invoke.h:65

[Inlined] UE4Tuple_Private::TTupleBase::ApplyAfter(void (SLevelEditor::*&)(const TArray<…> &, bool), SLevelEditor *&, const TArray<…> &, bool &) Tuple.h:306

TBaseSPMethodDelegateInstance::ExecuteIfSafe(const TArray<…> &, bool) DelegateInstancesImpl.h:307

[Inlined] TMulticastDelegate::Broadcast(const TArray<…> &, bool) DelegateSignatureImpl.inl:955

FLevelEditorModule::BroadcastActorSelectionChanged(const TArray<…> &, bool) LevelEditor.cpp:456

UUnrealEdEngine::UpdateFloatingPropertyWindowsFromActorList(const TArray<…> &, bool) EditorHook.cpp:63

UUnrealEdEngine::UpdateFloatingPropertyWindows(bool) EditorHook.cpp:55

UUnrealEdEngine::NoteSelectionChange(bool) EditorSelectUtils.cpp:414

FUsdStageActorImpl::DeselectActorsAndComponents(AUsdStageActor *) USDStageActor.cpp:151

AUsdStageActor::UnloadUsdStage() USDStageActor.cpp:1560

AUsdStageActor::PostUnregisterAllComponents() USDStageActor.cpp:1950

AActor::UnregisterAllComponents(bool) Actor.cpp:4600

AActor::BeginDestroy() Actor.cpp:670

UObject::ConditionalBeginDestroy() Obj.cpp:970

UnhashUnreachableObjects(bool, float) GarbageCollection.cpp:2153

CollectGarbageInternal(EObjectFlags, bool) GarbageCollection.cpp:2087

CollectGarbage(EObjectFlags, bool) GarbageCollection.cpp:2199

UEngine::TrimMemory() UnrealEngine.cpp:13506

UCheckpointSubsystem::HandleResumeFromGameInstanceCheckpoint() CheckpointSubsystem.cpp:454

UCheckpointSubsystem::StartPlay() CheckpointSubsystem.cpp:109

APiloSingleplayerGameMode::StartPlay() PiloSingleplayerGameMode.cpp:77

UWorld::BeginPlay() World.cpp:4545

UGameInstance::StartPlayInEditorGameInstance(ULocalPlayer *, const FGameInstancePIEParameters &) GameInstance.cpp:485

UEditorEngine::CreateInnerProcessPIEGameInstance(FRequestPlaySessionParams &, const FGameInstancePIEParameters &, int) PlayLevel.cpp:2972

UEditorEngine::OnLoginPIEComplete_Deferred(int, bool, FString, FPieLoginStruct) PlayLevel.cpp:1520

UEditorEngine::CreateNewPlayInEditorInstance(FRequestPlaySessionParams &, const bool, EPlayNetMode) PlayLevel.cpp:1768

UEditorEngine::StartPlayInEditorSession(FRequestPlaySessionParams &) PlayLevel.cpp:2738

UEditorEngine::StartQueuedPlaySessionRequestImpl() PlayLevel.cpp:1116

UEditorEngine::StartQueuedPlaySessionRequest() PlayLevel.cpp:1028

UEditorEngine::Tick(float, bool) EditorEngine.cpp:1629

UUnrealEdEngine::Tick(float, bool) UnrealEdEngine.cpp:423

FEngineLoop::Tick() LaunchEngineLoop.cpp:4938

[Inlined] EngineTick() Launch.cpp:62

GuardedMain(const wchar_t *) Launch.cpp:180

LaunchWindowsStartup(HINSTANCE__ *, HINSTANCE__ *, char *, int, const wchar_t *) LaunchWindows.cpp:262

WinMain(HINSTANCE__ *, HINSTANCE__ *, char *, int) LaunchWindows.cpp:320

Brooke, thanks for the reply. We don’t have any modifications in that function or in the SLevelEditor file. I’m not aware of any custom editor modes we are using… Could the notification be happening on another thread and that’s why it isn’t in the callstack?