Crash on compiling saving blueprint after undo

This question was created in reference to: [Crash on compiling saving blueprint after [Content removed]

Hi guys,

Apologies for not following up on the last thread. I made the suggested changed to the proejct (setting the rootcomponent), and ensured that there were no hot reload files.

I’m afraid we haven’t managed to narrow down a repro project that isn’t our project, but we can repro it with a simple custom actor with that code reliably. We’re unsure on next steps and could do with help narrowing it down.

Thanks!

Steps to Reproduce
See referenced thread, we have a repro that you couldn’t re-repro

Hi Donal,

No problem, we will continue where we left off.

Ok, let me try to get a better understanding of the situation. Would you kindly provide the following information?

- Are you running the vanilla UE 5.5 Editor, or are you building from source? In the latter case, are there any possibly relevant engine modifications in place?

- In your project, does the crash happen if you follow the steps exactly as provided before? Creating a new C++ actor with that code and only that code, then creating a BP actor based on it and otherwise empty, and performing the operations you mentioned without even adding the Actor to any level? Also, please mention a specific change (any one) you make to the BP in the second step.

- I have attached a tiny C++ plugin which contains the basic setup you described before. Can you please unzip the file in your project’s root directory, regenerate project files, compile, run, and test with the contained BP asset? Does the crash repro with it?

Meanwhile, I am also taking a better look at the ensures and the crash callstack you provided before.

Best regards,

Vitor

Hey Vitor

Thanks for following up. We’re building from Source, with P4. We do have engine modifications, which I have started going through but don’t see anything notable (yet). I will continue going through our engine mods.

I have reproduced this with exactly the steps before, except I have also set `RootComponent = SphereComponent` after I created the RootComponent.

“Modify the blueprint” -> I added a Print node to the event graph.

The callstack of the ensure is:

``StaticAllocateObjectErrorTests’::96'::<lambda_2>::operator()() UObjectGlobals.cpp:3362 StaticAllocateObjectErrorTests(const UClass *, UObject *, FName, EObjectFlags) UObjectGlobals.cpp:3362 StaticAllocateObject(const UClass *, UObject *, FName, EObjectFlags, EInternalObjectFlags, bool, bool *, UPackage *) UObjectGlobals.cpp:3403 StaticConstructObject_Internal(const FStaticConstructObjectParameters &) UObjectGlobals.cpp:4527 StaticDuplicateObjectEx(FObjectDuplicationParameters &) UObjectGlobals.cpp:3081 [Inlined] StaticDuplicateObject(const UObject *, UObject *, FName, EObjectFlags, UClass *, Type, EInternalObjectFlags) UObjectGlobals.cpp:3015 DuplicateObject_Internal(UClass *, const UObject *, UObject *, FName) UObjectGlobals.cpp:4483 [Inlined] DuplicateObject(const UObject *, UObject *, FName) UObjectGlobals.h:1857 FixSubObjectReferencesPostUndoRedo(UObject *) BlueprintEditorModule.cpp:129 FixSubObjectReferencesPostUndoRedo(UObject *) BlueprintEditorModule.cpp:120 FixSubObjectReferencesPostUndoRedo(const FTransaction *) BlueprintEditorModule.cpp:171 UEditorEngine::BroadcastPostUndoRedo(const FTransactionContext &, bool) EditorServer.cpp:5342 UEditorEngine::HandleTransactorRedoUndo(const FTransactionContext &, bool, bool) EditorServer.cpp:1178 [Inlined] Invoke(void (UEditorEngine::*)(const FTransactionContext &, bool), UEditorEngine *&, const FTransactionContext &, bool &&) Invoke.h:66 [Inlined] UE::Core::Private::Tuple::TTupleBase::ApplyAfter(void (UEditorEngine::*&)(const FTransactionContext &, bool), UEditorEngine *&, const FTransactionContext &, bool &&) Tuple.h:317 TBaseUObjectMethodDelegateInstance::ExecuteIfSafe(const FTransactionContext &, bool) DelegateInstancesImpl.h:667 [Inlined] TMulticastDelegateBase::Broadcast(const FTransactionContext &, bool) MulticastDelegateBase.h:257 [Inlined] TMulticastDelegate::Broadcast(const FTransactionContext &, bool) DelegateSignatureImpl.inl:1079 UTransBuffer::Undo(bool) EditorTransaction.cpp:1625 UEditorEngine::UndoTransaction(bool) EditorServer.cpp:1303 [Inlined] Invoke(void (FBlueprintEditor::*)(), FBlueprintEditor *&) Invoke.h:66 [Inlined] UE::Core::Private::Tuple::TTupleBase::ApplyAfter(void (FBlueprintEditor::*&)(), FBlueprintEditor *&) Tuple.h:317 TBaseSPMethodDelegateInstance::ExecuteIfSafe() DelegateInstancesImpl.h:299 [Inlined] TDelegate::ExecuteIfBound() DelegateSignatureImpl.inl:634 FUIAction::Execute() UIAction.h:139 FUICommandList::ConditionalProcessCommandBindings(FKey, bool, bool, bool, bool, bool) UICommandList.cpp:235 FUICommandList::ProcessCommandBindings(const FKeyEvent &) UICommandList.cpp:178 FBaseToolkit::ProcessCommandBindings(const FKeyEvent &) BaseToolkit.cpp:68 SStandaloneAssetEditorToolkitHost::OnKeyDown(const FGeometry &, const FKeyEvent &) SStandaloneAssetEditorToolkitHost.cpp:424 [Inlined] FSlateApplication::ProcessKeyDownEvent::__l22::<lambda_2>::operator()(const FArrangedWidget &, const FKeyEvent &) SlateApplication.cpp:4828 FEventRouter::Route<FReply,FEventRouter::FBubblePolicy,FKeyEvent,FSlateApplication::ProcessKeyDownEvent’::22'::<lambda_2> >(FSlateApplication *,FBubblePolicy,FKeyEvent,const <lambda_2> &,ESlateDebuggingInputEvent) SlateApplication.cpp:461 [Inlined] FEventRouter::RouteAlongFocusPath(FSlateApplication *, FBubblePolicy, FKeyEvent, const <lambda_2> &, ESlateDebuggingInputEvent) SlateApplication.cpp:430 FSlateApplication::ProcessKeyDownEvent(const FKeyEvent &) SlateApplication.cpp:4824 FSlateApplication::OnKeyDown(const int, const unsigned int, const bool) SlateApplication.cpp:4735 FWindowsApplication::ProcessDeferredMessage(const FDeferredWindowsMessage &) WindowsApplication.cpp:2102 FWindowsApplication::DeferMessage(TSharedPtr<…> &, HWND__ *, unsigned int, unsigned long long, long long, int, int, unsigned int) WindowsApplication.cpp:2783 FWindowsApplication::ProcessMessage(HWND__ *, unsigned int, unsigned long long, long long) WindowsApplication.cpp:1944 [Inlined] WindowsApplication_WndProc(HWND__ *, unsigned int, unsigned long long, long long) WindowsApplication.cpp:939 FWindowsApplication::AppWndProc(HWND__ *, unsigned int, unsigned long long, long long) WindowsApplication.cpp:944 <unknown> 0x00007ffb75bbd159 <unknown> 0x00007ffb75bbb152 [Inlined] WinPumpMessages() WindowsPlatformApplicationMisc.cpp:116 FWindowsPlatformApplicationMisc::PumpMessages(bool) WindowsPlatformApplicationMisc.cpp:145 FEngineLoop::Tick() LaunchEngineLoop.cpp:5792 [Inlined] EngineTick() Launch.cpp:69 GuardedMain(const wchar_t *) Launch.cpp:190 LaunchWindowsStartup(HINSTANCE__ *, HINSTANCE__ *, char *, int, const wchar_t *) LaunchWindows.cpp:266 WinMain(HINSTANCE__ *, HINSTANCE__ *, char *, int) LaunchWindows.cpp:317 [Inlined] invoke_main() 0x00007ff7695cf0ba __scrt_common_main_seh() 0x00007ff7695cf099 <unknown> 0x00007ffb757ce8d7 <unknown> 0x00007ffb7683c34c`Object NavArea_Obstacle of class /Script/CoreUObject.Class with ClassWithin of /Script/CoreUObject.Package was created in invalid Outer /Script/Engine.SphereComponent!` is the ensure message

Taking that plugin, opening the Blueprint in it, adding a Print node, saving + undo’ing trips the ensure (and then the crash).

Thanks!

Also, can you try placing a breakpoint at the point of the ensure() that is called in function StaticAllocateObjectErrorTests(), on file [Engine\Source\Runtime\CoreUObject\Private\UObject\UObjectGlobals.cpp:3362], and then copy the Call Stack from that point and paste it here?

Hi Donal,

I followed along the callstack of the ensure on my vanilla UE 5.5 to see where the execution flow diverged. It happens in file [BlueprintEditorModule.cpp] on the first call to function FixSubObjectReferencesPostUndoRedo():

[Engine\Source\Editor\Kismet\Private\BlueprintEditorModule.cpp] [:92] void FixSubObjectReferencesPostUndoRedo(UObject* InObject) [:93] { [:94] // Post undo/redo, these may have the correct Outer but are not referenced by the CDO's UProperties [:95] TArray<UObject*> SubObjects; [:96] GetObjectsWithOuter(InObject, SubObjects, false); [:97] [:98] // Post undo/redo, these may have the in-correct Outer but are incorrectly referenced by the CDO's UProperties [:99] TSet<FInstancedSubObjRef> PropertySubObjectReferences; [:100] UClass* ObjectClass = InObject->GetClass(); [:101] FFindInstancedReferenceSubobjectHelper::GetInstancedSubObjects(InObject, PropertySubObjectReferences); [:102] [:103] TMap<UObject*, UObject*> OldToNewInstanceMap; [:104] for (UObject* PropertySubObject : PropertySubObjectReferences) [:105] { [....] //(...) [:135] } [:136] [:137] FArchiveReplaceObjectRef<UObject> Replacer(InObject, OldToNewInstanceMap); [:138] }In my case: On line 96, GetObjectsWithOuter() returns only “SphereComp”. On line 101, GetInstancedSubObjects() returns an empty set. And on line 104, the loop is never entered.

In your case, the call stack goes deeper with a call that happens inside the loop on line 104, which means that GetInstancedSubObjects() is not returning an empty set.

I stepped into GetInstancedSubObjects() and forced it to return “SphereComp” as well. This made the code enter the loop on line 104 and call FixSubObjectReferencesPostUndoRedo() recursively on it, which appears to be the behavior in your case. On that recursive call, GetInstancedSubObjects() returns empty here once more, which again seems different from your case. So, I stepped into GetInstancedSubobjects() again and forced it to return “AreaClass”, which is a UClass* property of UShapeComponent, the base class of USphereComponent. As a result, DuplicateObject() was called on line 130 with “NavArea_Obstacle”, which is the default class configured for the “AreaClass” property, and with the sphere component as the outer. This reproed your ensure message and call stack exactly.

Note that DuplicateSubobject() on line 130 should only be called if we are undoing the deletion of a BP subobject, so that the deleted subobject can be recreated and references to it can be relinked.

As a next step, I examined the code inside function GetInstancedSubObjects(), which is behaving differently in your engine and the vanilla one from the launcher. This function iterates over all properties of the parent object searching for properties that contain references to subobjects. It uses the helper function FFindInstancedReferenceSubobjectHelper::ForEachInstancedSubObject(), which filters out properties that do not represent components of the required type. Specifically, it filters out properties that are not flagged as “CPF_InstancedReference” (component references in general) and “CPF_PersistentInstance” (components that must be duplicated for each actor by the reflection system, which should not include native component references such as “SphereComp”).

Ok. What I would recommend now:

1) Place a breakpoint on function FixSubObjectReferencesPostUndoRedo() and check if it is misbehaving according to my guesses above

2) Check if your engine’s implementation of FixSubObjectReferencesPostUndoRedo(), FFindInstancedReferenceSubobjectHelper::GetInstancedSubObjects(), and FFindInstancedReferenceSubobjectHelper::ForEachInstancedSubObject() is not changed in any way that could affect the correct behavior as described above.

3) Check if “SphereComp” and “SphereComp.AreaClass” are getting flagged with “CPF_PersistentInstance” (they should not be). If they are, investigate the reason for that.

Let me know if this helps!

Kind regards,

Vitor

Hey Vitor

I can confirm that `GetInstancedSubObjects` is in fact returning the SphereCompe.

I added a loop into this function to check the object and the referenced objects properties, and none of them have the CPF_PersistentInstance flag.

> Check if your engine’s implementation of

Interestingly, our implementation of this differs from your snippet. We appear to have a problematic version of these functions, at CL 37201310. I’ve replaced

TArray<UObject*> PropertySubObjectReferences; FReferenceFinder(PropertySubObjectReferences).FindReferences(InObject);with

TSet<FInstancedSubObjRef> PropertySubObjectReferences; FFindInstancedReferenceSubobjectHelper::GetInstancedSubObjects(InObject, PropertySubObjectReferences);(from CL 37252171 ) and the crash has gone away.

I’m investigating how we’ve ended up here at the moment.

Hey Vitor,

I just want to follow up here. I’ve done a full comparison of our modifications against //UE5/Release-5.5/[Content removed] and I found a handful of files which are slightly different - seemingly grabbed from two different windows of time in October and August last year. I’ve applied the obvious ones to bring us back to parity and can confirm that the issue has been resolved. I’m going through the remaining missing files and comparing against the other… odd issues that we’ve reported in the last 6 months to see if we can figure these out too.

Thanks for the pointer here, I know it seems obvious but it never crossed my mind that a botched engine update would be our root cause here.

That surely sounds like a tricky issue to catch and which could cause a chain of other odd behaviors. I’m glad we’ve been able to discover the probable root cause and that you now seem to be on the right track to completely normalizing the situation!

I’m going to close this topic now, but feel free to reopen it if needed, or to create a new ticket mentioning it for other related issues.

All the best,

Vitor