Hiya!
I’m making a custom component interface for branching structures and basing the implementation on SplineComponentVisualizer. Generally things work as expected but I’m stumped by this bug - occasionally I get a crash when interacting with the Primitive Drawing Interface via Hit Proxies.
I can’t reproduce it consistently - sometimes it happens almost immediately, sometimes I have to click around alot.
I can see that the UActorComponent pointer references my object but it is marked as TRASH and tagged with RF_MirroredGarbage. This then results in a null pointer further down the call stack.
I’ve tried activating garbage collection every frame (gc.CollectGarbageEveryFrame 1) with no effect.
The component is attached to a clean Actor blueprint & I’ve replicated this with another blueprint.
Here’s the full call stack:
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x0000000000000008
UnrealEditor_Engine!UEngineElementsLibrary::CreateComponentElement() [D:\build\++UE5\Sync\Engine\Source\Runtime\Engine\Private\Elements\Framework\EngineElementsLibrary.cpp:440]
UnrealEditor_Engine!UE::Core::Private::Function::TFunctionRefCaller<TTypedElementOwner<FComponentElementData> (__cdecl*)(UActorComponent const * __ptr64),TTypedElementOwner<FComponentElementData> __cdecl(UActorComponent const * __ptr64)>::Call() [D:\build\++UE5\Sync\Engine\Source\Runtime\Core\Public\Templates\Function.h:396]
UnrealEditor_Engine!UE::Core::Private::Function::TFunctionRefCaller<`EngineElementsLibraryUtil::AcquireEditorTypedElementHandle<UActorComponent,FComponentElementData>'::`5'::<lambda_1>,TTypedElementOwner<FComponentElementData> __cdecl(void)>::Call() [D:\build\++UE5\Sync\Engine\Source\Runtime\Core\Public\Templates\Function.h:396]
UnrealEditor_Engine!TTypedElementOwnerStore<FComponentElementData,UActorComponent const * __ptr64>::FindOrRegisterElementOwner() [D:\build\++UE5\Sync\Engine\Source\Runtime\TypedElementFramework\Public\Elements\Framework\TypedElementOwnerStore.h:177]
UnrealEditor_Engine!EngineElementsLibraryUtil::AcquireEditorTypedElementHandle<UActorComponent,FComponentElementData>() [D:\build\++UE5\Sync\Engine\Source\Runtime\Engine\Private\Elements\Framework\EngineElementsLibrary.cpp:66]
UnrealEditor_Engine!UEngineElementsLibrary::AcquireEditorComponentElementHandle() [D:\build\++UE5\Sync\Engine\Source\Runtime\Engine\Private\Elements\Framework\EngineElementsLibrary.cpp:470]
UnrealEditor_Graph3DEditor_Win64_DebugGame!HComponentVisProxy::GetElementHandle() [C:\Program Files\Epic Games\UE_5.4\Engine\Source\Editor\UnrealEd\Public\ComponentVisualizer.h:56]
UnrealEditor_UnrealEd!FLevelEditorViewportClient::ProcessClick() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\LevelEditorViewport.cpp:2820]
UnrealEditor_UnrealEd!FEditorViewportClient::ProcessClickInViewport() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\EditorViewportClient.cpp:3343]
UnrealEditor_UnrealEd!FEditorViewportClient::Internal_InputKey() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\EditorViewportClient.cpp:3125]
UnrealEditor_UnrealEd!FLevelEditorViewportClient::InputKey() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\LevelEditorViewport.cpp:3545]
UnrealEditor_Engine!FSceneViewport::OnMouseButtonUp() [D:\build\++UE5\Sync\Engine\Source\Runtime\Engine\Private\Slate\SceneViewport.cpp:651]
UnrealEditor_Slate!SViewport::OnMouseButtonUp() [D:\build\++UE5\Sync\Engine\Source\Runtime\Slate\Private\Widgets\SViewport.cpp:247]
UnrealEditor_Slate!TArray<TSharedRef<SWindow,1>,TSizedDefaultAllocator<32> >::RemoveAll<`TArray<TSharedRef<SWindow,1>,TSizedDefaultAllocator<32> >::Remove'::`2'::<lambda_1> >() [D:\build\++UE5\Sync\Engine\Source\Runtime\Slate\Private\Framework\Application\SlateApplication.cpp:442]
UnrealEditor_Slate!FSlateApplication::RoutePointerUpEvent() [D:\build\++UE5\Sync\Engine\Source\Runtime\Slate\Private\Framework\Application\SlateApplication.cpp:5279]
UnrealEditor_Slate!FSlateApplication::ProcessMouseButtonUpEvent() [D:\build\++UE5\Sync\Engine\Source\Runtime\Slate\Private\Framework\Application\SlateApplication.cpp:5857]
UnrealEditor_Slate!FSlateApplication::OnMouseUp() [D:\build\++UE5\Sync\Engine\Source\Runtime\Slate\Private\Framework\Application\SlateApplication.cpp:5813]
UnrealEditor_ApplicationCore!FWindowsApplication::ProcessDeferredMessage() [D:\build\++UE5\Sync\Engine\Source\Runtime\ApplicationCore\Private\Windows\WindowsApplication.cpp:2243]
UnrealEditor_ApplicationCore!FWindowsApplication::DeferMessage() [D:\build\++UE5\Sync\Engine\Source\Runtime\ApplicationCore\Private\Windows\WindowsApplication.cpp:2750]
UnrealEditor_ApplicationCore!FWindowsApplication::ProcessMessage() [D:\build\++UE5\Sync\Engine\Source\Runtime\ApplicationCore\Private\Windows\WindowsApplication.cpp:1919]
UnrealEditor_ApplicationCore!FWindowsApplication::AppWndProc() [D:\build\++UE5\Sync\Engine\Source\Runtime\ApplicationCore\Private\Windows\WindowsApplication.cpp:929]
user32
user32
UnrealEditor_ApplicationCore!FWindowsPlatformApplicationMisc::PumpMessages() [D:\build\++UE5\Sync\Engine\Source\Runtime\ApplicationCore\Private\Windows\WindowsPlatformApplicationMisc.cpp:145]
UnrealEditor_Win64_DebugGame!FEngineLoop::Tick() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\LaunchEngineLoop.cpp:5850]
UnrealEditor_Win64_DebugGame!GuardedMain() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Launch.cpp:180]
UnrealEditor_Win64_DebugGame!GuardedMainWrapper() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:118]
UnrealEditor_Win64_DebugGame!LaunchWindowsStartup() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:258]
UnrealEditor_Win64_DebugGame!WinMain() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:298]
UnrealEditor_Win64_DebugGame!__scrt_common_main_seh() [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288]
kernel32
ntdll
Here are the functions for handling clicks and creating the hit proxies:
bool FGraph3DVisualizer::VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, const FViewportClick& Click)
{
if (VisProxy && VisProxy->Component.IsValid())
{
SelectionState->Modify();
SelectionState->SetComponentPropertyPath(FComponentPropertyPath((UGraph3DComponent*)VisProxy->Component.Get()));
if (!DeselectedInEditorDelegateHandle.IsValid())
{
DeselectedInEditorDelegateHandle = GetEditedGraphComponent()->OnDeselectedInEditor.AddRaw(this, &FGraph3DVisualizer::OnDeselectedInEditor);
}
if (Click.GetKey() == EKeys::RightMouseButton) return true;
const HGraph3DNodeVisProxy* NodeProxy = (HGraph3DNodeVisProxy*)VisProxy;
if (NodeProxy->IsA(HGraph3DNodeVisProxy::StaticGetType()) && NodeProxy)
{
SelectionType = Node;
SelectedEdges.Empty();
if (InViewportClient->IsCtrlPressed()) {
SelectedNodes.AddUnique(NodeProxy->NodeIndex);
} else {
SelectedNodes.Empty();
SelectedNodes.AddUnique(NodeProxy->NodeIndex);
}
GEditor->RedrawLevelEditingViewports(true);
return true;
}
const HGraph3DEdgeVisProxy* EdgeProxy = (HGraph3DEdgeVisProxy*)VisProxy;
if (EdgeProxy->IsA(HGraph3DEdgeVisProxy::StaticGetType()) && EdgeProxy)
{
SelectionType = Edge;
SelectedNodes.Empty();
if (InViewportClient->IsCtrlPressed()) {
SelectedEdges.AddUnique(EdgeProxy->EdgeIndex);
} else {
SelectedEdges.Empty();
SelectedEdges.AddUnique(EdgeProxy->EdgeIndex);
}
GEditor->RedrawLevelEditingViewports(true);
return true;
}
}
SelectionState->SetComponentPropertyPath(FComponentPropertyPath());
return false;
}
void FGraph3DVisualizer::DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI)
{
const UGraph3DComponent* Graph = Cast<const UGraph3DComponent>(Component);
if (!Graph) return;
if (!Component->IsValidLowLevel()) {
UE_LOGFMT(LogTemp, Log, "Invalid Graph Component");
return;
}
//draw edges
for(int32 i = 0; i < Graph->Edges.Num(); i++)
{
PDI->SetHitProxy(NULL);
PDI->SetHitProxy(new HGraph3DEdgeVisProxy(Component, i));
const FVector Start = Graph->Nodes[Graph->Edges[i].Start].Position + Graph->GetComponentLocation();
const FVector End = Graph->Nodes[Graph->Edges[i].End].Position + Graph->GetComponentLocation();
//PDI->DrawLine(Start, End, FColor::Emerald, SDPG_Foreground, 3,0,true);
FLinearColor Color = FColor::MakeRandomSeededColor(i);
FVector Direction = End - Start;
const float Offset = Graph->NodeScale;
float Length = Direction.Length() - (Offset * 2);
float Width = 12.f;
float Thickness = 2.5f;
if (SelectedEdges.Contains(i)) Thickness *= 2;
Direction = Direction.GetUnsafeNormal();
FMatrix Matrix = FScaleRotationTranslationMatrix(FVector::One(), Direction.Rotation(), Start + (Direction * Offset));
DrawDirectionalArrow(PDI, Matrix, Color, Length, Width, SDPG_Foreground, Thickness);
PDI->SetHitProxy(NULL);
}
//draw nodes
for (int32 i = 0; i < Graph->Nodes.Num(); i++)
{
PDI->SetHitProxy(NULL);
PDI->SetHitProxy(new HGraph3DNodeVisProxy(Component, i));
FVector Position = Graph->Nodes[i].Position + Graph->GetComponentLocation();
float Scale = Graph->NodeScale;
FColor Color = FColor::White;
if (SelectedNodes.Contains(i))
{
Scale *= 1.5;
Color = FColor::Yellow;
}
PDI->DrawPoint(Position, Color, Scale, SDPG_Foreground);
PDI->SetHitProxy(NULL);
}
}
I would really appreciate any insight into how my component is being garbage collected or what I could be doing wrong. Thanks!
P.S. This is my first time using C++ so pre-emtive apologies for my ignorance