'Source/GlobalEventSystem/Public/GESHandlerDataTypes.h' defines UObject* FGESMinimalEventListener.ReceiverWCO, which points to UObjects in the scene, but Listener.ReceiverWCO->IsValidLowLevelFast() seems to fail regarding deleted objects.
Spawning and deleting objects rapidly while triggering events leads to crashes:
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION 0x0000008000000000
UnrealEditor_GlobalEventSystem!<lambda_62c3eddd4239e5a48e9e4bb3fd487051>::operator()() [...\Plugins\GlobalEventSystem-Unreal-0.12.0\Source\GlobalEventSystem\Private\GESHandler.cpp:907]
UnrealEditor_GlobalEventSystem!FGESHandler::EmitToListenerWithData() [...\Plugins\GlobalEventSystem-Unreal-0.12.0\Source\GlobalEventSystem\Private\GESHandler.cpp:552]
UnrealEditor_GlobalEventSystem!FGESHandler::EmitToListenersWithData() [...\Plugins\GlobalEventSystem-Unreal-0.12.0\Source\GlobalEventSystem\Private\GESHandler.cpp:492]
UnrealEditor_GlobalEventSystem!FGESHandler::EmitEvent() [...\Plugins\GlobalEventSystem-Unreal-0.12.0\Source\GlobalEventSystem\Private\GESHandler.cpp:842]
UnrealEditor_GlobalEventSystem!UGlobalEventSystemBPLibrary::GESEmitEvent() [...\Plugins\GlobalEventSystem-Unreal-0.12.0\Source\GlobalEventSystem\Private\GlobalEventSystemBPLibrary.cpp:131]
UnrealEditor_GlobalEventSystem!UGlobalEventSystemBPLibrary::execGESEmitEvent() [...\Plugins\GlobalEventSystem-Unreal-0.12.0\Intermediate\Build\Win64\UnrealEditor\Inc\GlobalEventSystem\UHT\GlobalEventSystemBPLibrary.gen.cpp:132]
UnrealEditor_CoreUObject
UnrealEditor_CoreUObject
UnrealEditor_CoreUObject
UnrealEditor_CoreUObject
UnrealEditor_CoreUObject
UnrealEditor_CoreUObject
UnrealEditor_CoreUObject
UnrealEditor_CoreUObject
UnrealEditor_CoreUObject
UnrealEditor_CoreUObject
UnrealEditor_CoreUObject
UnrealEditor_Engine
UnrealEditor_Engine
UnrealEditor_Engine
UnrealEditor_Engine
UnrealEditor_Engine
UnrealEditor_Engine
UnrealEditor_Engine
UnrealEditor_Core
UnrealEditor_Core
UnrealEditor_Core
UnrealEditor_Engine
UnrealEditor_Engine
UnrealEditor_Engine
UnrealEditor_Engine
UnrealEditor_UnrealEd
UnrealEditor_UnrealEd
UnrealEditor
UnrealEditor
UnrealEditor
UnrealEditor
UnrealEditor
UnrealEditor
kernel32
ntdll
In a first try I changed ReceiverWCO to a TWeakObjectPtr, which does not extend the lifetime of an object, but gets properly notified, when it gets deleted:
diff --git a/GlobalEventSystem-Unreal-0.12.0/Source/GlobalEventSystem/Private/GESHandler.cpp b/GlobalEventSystem-Unreal-0.12.0/Source/GlobalEventSystem/Private/GESHandler.cpp
index 1d82c3a..f0c8920 100644
--- a/GlobalEventSystem-Unreal-0.12.0/Source/GlobalEventSystem/Private/GESHandler.cpp
+++ b/GlobalEventSystem-Unreal-0.12.0/Source/GlobalEventSystem/Private/GESHandler.cpp
@@ -35,7 +35,7 @@ bool FGESHandler::FirstParamIsSubclassOf(UFunction* Function, FFieldClass* Class
FString FGESHandler::ListenerLogString(const FGESEventListener& Listener)
{
- return Listener.ReceiverWCO->GetName() + TEXT(":") + Listener.FunctionName;
+ return Listener.ReceiverWCO.Get()->GetName() + TEXT(":") + Listener.FunctionName;
}
FString FGESHandler::EventLogString(const FGESEvent& Event)
@@ -154,12 +154,12 @@ void FGESHandler::AddListener(const FString& Domain, const FString& EventName, c
Minimal.ReceiverWCO = Listener.ReceiverWCO;
ListenContext.Listener = Minimal;
- if (!ReceiverMap.Contains(Listener.ReceiverWCO))
+ if (!ReceiverMap.Contains(Listener.ReceiverWCO.Get()))
{
TArray<FGESEventListenerWithContext> Array;
- ReceiverMap.Add(Listener.ReceiverWCO, Array);
+ ReceiverMap.Add(Listener.ReceiverWCO.Get(), Array);
}
- ReceiverMap[Listener.ReceiverWCO].Add(ListenContext);
+ ReceiverMap[Listener.ReceiverWCO.Get()].Add(ListenContext);
//if it's pinned re-emit it immediately to this listener
if (Event.bPinned)
@@ -333,14 +333,14 @@ void FGESHandler::RemoveListener(const FString& Domain, const FString& Event, co
EventMap[KeyString].Listeners.Remove(Listener);
//Remove matched entry in receiver map
- if (ReceiverMap.Contains(Listener.ReceiverWCO))
+ if (ReceiverMap.Contains(Listener.ReceiverWCO.Get()))
{
FGESEventListenerWithContext ContextListener;
ContextListener.Domain = Domain;
ContextListener.Event = Event;
ContextListener.Listener.FunctionName = Listener.FunctionName;
ContextListener.Listener.ReceiverWCO = Listener.ReceiverWCO;
- ReceiverMap[Listener.ReceiverWCO].Remove(ContextListener);
+ ReceiverMap[Listener.ReceiverWCO.Get()].Remove(ContextListener);
}
}
diff --git a/GlobalEventSystem-Unreal-0.12.0/Source/GlobalEventSystem/Public/GESHandlerDataTypes.h b/GlobalEventSystem-Unreal-0.12.0/Source/GlobalEventSystem/Public/GESHandlerDataTypes.h
index d7abac6..285baf1 100644
--- a/GlobalEventSystem-Unreal-0.12.0/Source/GlobalEventSystem/Public/GESHandlerDataTypes.h
+++ b/GlobalEventSystem-Unreal-0.12.0/Source/GlobalEventSystem/Public/GESHandlerDataTypes.h
@@ -32,7 +32,7 @@ struct FGESDynamicArg
//Minimal definition to define a listener (for removal)
struct FGESMinimalEventListener
{
- UObject* ReceiverWCO; //WorldContextObject
+ TWeakObjectPtr<UObject> ReceiverWCO; //WorldContextObject
FString FunctionName;
bool operator ==(FGESMinimalEventListener const& Other)
With these changes I'm not able to reproduce the crashes, but I'm sure if it's really thread-safe or the way Epic intended. Here are some resources I found about this topic:
'Source/GlobalEventSystem/Public/GESHandlerDataTypes.h' defines
UObject* FGESMinimalEventListener.ReceiverWCO, which points to UObjects in the scene, butListener.ReceiverWCO->IsValidLowLevelFast()seems to fail regarding deleted objects.Spawning and deleting objects rapidly while triggering events leads to crashes:
In a first try I changed
ReceiverWCOto a TWeakObjectPtr, which does not extend the lifetime of an object, but gets properly notified, when it gets deleted:With these changes I'm not able to reproduce the crashes, but I'm sure if it's really thread-safe or the way Epic intended. Here are some resources I found about this topic: