Garbage collection has undergone a couple rewrites during 5.0s lifetime at this point. During one of those rewrites rather useful functionality was lost where Garbage Collection could call out UPROPERTYed object pointers that pointed to invalid objects (almost always caused by a gameplay bug of some kind- such as copying dangling raw pointers into a UPROPERTYed raw pointer, or USTRUCTs with UPROPERTY raw pointers that don’t initialize the pointers, etc). This code wasn’t perfect but it was generally good enough/incredibly useful when it did catch issues.
This output (as reproed in the attached UE4 project) would look like this:
Fatal error: [File:D:/Build/++UE4/Sync/Engine/Source/Runtime/CoreUObject/Private/UObject/GarbageCollection.cpp] [Line: 961] Invalid object in GC: 0x000001ff287a56c0, ReferencingObject: ActorWithBadGCRefs /Game/UEDPIE_0_Map.Map:PersistentLevel.ActorWithBadGCRefs_1, ReferencingObjectClass: Class /Script/UE4GCObjTest.ActorWithBadGCRefs, Property Name: Ref, Offset: 760, TokenIndex: 36
UE4Editor_CoreUObject!TFastReferenceCollector<FGCReferenceProcessor<1>,FGCCollector<1>,FGCArrayPool,1>::ProcessObjectArray() [D:\Build\++UE4\Sync\Engine\Source\Runtime\CoreUObject\Public\UObject\FastReferenceCollector.h:751]
UE4Editor_CoreUObject!TFastReferenceCollector<FGCReferenceProcessor<1>,FGCCollector<1>,FGCArrayPool,1>::FCollectorTaskQueue::DoTask() [D:\Build\++UE4\Sync\Engine\Source\Runtime\CoreUObject\Public\UObject\FastReferenceCollector.h:403]
Now, however, in more recent versions of the engine these issues are no longer called out- and not only are they no longer called out but the callstacks where this will cause a crash are incredibly cryptic and lack the context needed to debug the problem because references are queued without being checked and we don’t crash until the queue is processed- at which point the context of what object/property added the reference is long gone.
Assertion failed: IsValidIndex(Index) [File:D:\build\++UE5\Sync\Engine\Source\Runtime\CoreUObject\Public\UObject\UObjectArray.h] [Line: 812]
IsValidIndex(362619)
UnrealEditor_Core!FDebug::CheckVerifyFailedImpl2() [D:\build\++UE5\Sync\Engine\Source\Runtime\Core\Private\Misc\AssertionMacros.cpp:728]
UnrealEditor_CoreUObject!UE::GC::TBatchDispatcher<UE::GC::TReachabilityProcessor<5> >::FlushQueuedReferences() [D:\build\++UE5\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\GarbageCollection.cpp:3142]
UnrealEditor_CoreUObject!UE::GC::TFastReferenceCollector<UE::GC::TReachabilityProcessor<5>,UE::GC::TReachabilityCollector<5> >::ProcessObjectArray() [D:\build\++UE5\Sync\Engine\Source\Runtime\CoreUObject\Public\UObject\FastReferenceCollector.h:945]
UnrealEditor_CoreUObject!`UE::GC::FRealtimeGC::CollectReferencesForGC<UE::GC::TReachabilityCollector<5>,UE::GC::TReachabilityProcessor<5> >'::`3'::<lambda_1>::<lambda_invoker_cdecl>() [D:\build\++UE5\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\GarbageCollection.cpp:4014]
UnrealEditor_CoreUObject!UE::Tasks::Private::TExecutableTaskBase<`UE::GC::FRealtimeGC::BeginInitialReferenceCollection'::`5'::<lambda_1>,void,void>::ExecuteTask() [D:\build\++UE5\Sync\Engine\Source\Runtime\Core\Public\Tasks\TaskPrivate.h:904]
We have improved this locally by adding the following checks to the engine that objects are valid as they are added as unvalidated references to the reference batcher (which I’m sure is against a lot of what the reference batcher is trying to do for performance since this requires we read the uobject on push/queue)- but a more robust check for invalid objects like previous versions of GC used to have would be much appreciated (even if only in certain builds/development builds- this could even be done as a pre-GC verification step).
[Image Removed]
[Image Removed]
Any improvements here would be appreciated! Thanks!