Hi,
Whenever a designer
- Starts the game in PIE
- Edits a field using the widget reflector
- End the game
We get a GC related crash.
We’re creating widgets via UUserWidget::CreateWidgetInstance and CreateWidget on the UserWidget themselves.
The best i can tell, what’s happening is
- All UserWidgets are RF_Transactional by default
- SWidgetReflector passes widget to details panel
- Editing fields in details panels triggers a transaction
- ref to widget get’s stored in transaction system
- ref isn’t considered transient, so GC blows up at game end
EditorTransaction has some guards around objects being PIE, but it doesn’t seem to be catching these. I believe because CreateWidget really wants to make the GameInstance the outer for the widget, even if you pass in World or PlayerController.
I was able to work around the issue by adding, or by forcing RF_TRANSACTIONAL off for the widgets, or by creating the widget without using the CreateWidget function. All these feel kind of wrong though.
bool FTransaction::FObjectRecord::ContainsPieObject() const
{
auto IsObjectPIEScoped =
(const UObject* Obj) → bool
{
if (!Obj)
{
return false;
}
if (Obj->GetOutermost()->HasAnyPackageFlags(PKG_PlayInEditor))
{
return true;
}
if (const UWorld* World = Obj->GetWorld(); IsValid(World) && World->IsPlayInEditor())
{
return true;
}
return false;
};
if (IsObjectPIEScoped(Object.Get()))
{
return true;
}
// Rest of code...
Engine Version: 5.6
Trace and GC error log:
Assertion failed: false [File:G:\j\de_ugs\Engine\Source\Editor\UnrealEd\Private\PlayLevel.cpp] [Line: 544]
Object ‘BP_CLASS_THAT_EXTENDS_OUR_GAME_INSTANCE_C /Engine/Transient.UnrealEdEngine_0:BP_CLASS_THAT_EXTENDS_OUR_GAME_INSTANCE_C_0’ from PIE level still referenced. Shortest path from root: (root) UnrealEdEngine /Engine/Transient.UnrealEdEngine_0
→ TObjectPtr UEditorEngine::Trans = TransBuffer /Engine/Transient.TransBuffer_0
→ TransBuffer /Engine/Transient.TransBuffer_0::AddReferencedObjects((Garbage) BP_CLASS_THAT_EXTENDS_OUR_GAME_INSTANCE_C /Engine/Transient.UnrealEdEngine_0:BP_CLASS_THAT_EXTENDS_OUR_GAME_INSTANCE_C_0)
^ UE::ReferenceChainSearch::FReferenceInfoSearch::HandleObjectReference()
^ UE::ReferenceChainSearch::TReferenceSearchBaseUE::ReferenceChainSearch::FReferenceInfoSearch::FCollector<1>::HandleObjectReference()
^ UE::Transaction::FPersistentObjectRef::AddReferencedObjects()
^ FTransaction::FObjectRecord::AddReferencedObjects()
^ FTransaction::AddReferencedObjects()
^ UTransBuffer::AddReferencedObjects()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^ This reference is preventing the old BP_CLASS_THAT_EXTENDS_OUR_GAME_INSTANCE from being GC’d ^
0x00007ffcf4db3458 UnrealEditor-Core.dll!FDebug::CheckVerifyFailedImpl2()
0x00007ffcf19e2b1a UnrealEditor-UnrealEd.dll!UEditorEngine::EndPlayMap()
0x00007ffcf12a0980 UnrealEditor-UnrealEd.dll!UEditorEngine::Tick()
0x00007ffcf1f713f6 UnrealEditor-UnrealEd.dll!UUnrealEdEngine::Tick()
0x00007ff7c1e29ce4 UnrealEditor.exe!FEngineLoop::Tick()
0x00007ff7c1e4e5ac UnrealEditor.exe!GuardedMain()
0x00007ff7c1e4e6ba UnrealEditor.exe!GuardedMainWrapper()
0x00007ff7c1e5209e UnrealEditor.exe!LaunchWindowsStartup()
0x00007ff7c1e64e44 UnrealEditor.exe!WinMain()
0x00007ff7c1e680fa UnrealEditor.exe!__scrt_common_main_seh()
0x00007ffdf717e957 KERNEL32.DLL!UnknownFunction