Download

UE4 crashes when calling Add on a TArray ('UE4Editor_Core!rml::internal::reallocAligned()')

For some odd reason, UE4 keeps crashing when this is called:



void UEntityAttribute::RegisterPassive(UBasicPassive* passive)
{
    attachedPassives.Add(passive);
}


But the thing is, it only crashes on the second time I play on PIE. When I open the engine and play, the engine doesn’t crash when this line is executed. However, if I click stop playing and then click play again the game crashes when this line is reached.

I have no idea why this might be happening, if anyone could shed some light on this I’d be very glad.

This is how I declare [FONT=courier new]attachedPassives



UPROPERTY()
TArray<UBasicPassive*> attachedPassives;


This is how RegisterPassive is called



void UBasicPassive::OnInitialize()
{
    Super::OnInitialize();

    //Some irrelevant code

    targetAttribute->RegisterPassive(this); //targetAttribute can't be null because I do a null check after setting it.
}


And this is how UBasicPassive is created:



UPassiveTaskBase* UTasksComponent::AddPassiveTask(TSubclassOf<UPassiveTaskBase> passive)
{
    currentPassives.Add(NewObject<UPassiveTaskBase>(this, passive)); //currentPassives is a UPROPERTY btw
    UPassiveTaskBase* passiveInstance = currentPassives.Last(); //I did this because I thought that maybe TArray would change the address of the instance

    passiveInstance->target = this;
    passiveInstance->OnInitialize();


    return passiveInstance;
}


This is the crash log



Access violation - code c0000005 (first/second chance not available)

UE4Editor_Core!rml::internal::reallocAligned() [l:\dev\partner-intel\engine\source	hirdparty\inteltbb\inteltbb-4.4u3\src	bbmalloc\frontend.cpp:2346]
UE4Editor_Core!scalable_realloc() [l:\dev\partner-intel\engine\source	hirdparty\inteltbb\inteltbb-4.4u3\src	bbmalloc\frontend.cpp:2900]
UE4Editor_Core!FMallocTBB::Realloc() [d:\build\++ue4\sync\engine\source\runtime\core\private\hal\malloctbb.cpp:123]
UE4Editor_Core!FMemory::Realloc() [d:\build\++ue4\sync\engine\source\runtime\core\public\hal\fmemory.inl:48]
UE4Editor_Hivaneph_7524!TArray<UBasicPassive *,FDefaultAllocator>::ResizeGrow() [c:\program files\epic games\ue_4.20\engine\source\runtime\core\public\containers\array.h:2453]
UE4Editor_Hivaneph_7524!UEntityAttribute::RegisterPassive() [c:\users\lucas\dev-projects\ue4\hivaneph\hivaneph\source\hivaneph\entityattribute.cpp:9]
UE4Editor_Hivaneph_7524!UBasicPassive::OnInitialize() [c:\users\lucas\dev-projects\ue4\hivaneph\hivaneph\source\hivaneph\passives\basicpassive.cpp:30]
UE4Editor_Hivaneph_7524!UTasksComponent::AddPassiveTask() [c:\users\lucas\dev-projects\ue4\hivaneph\hivaneph\source\hivaneph\actions	askscomponent.cpp:115]
UE4Editor_Hivaneph_7524!UAbilitySystemComponent::ApplyPassives() [c:\users\lucas\dev-projects\ue4\hivaneph\hivaneph\source\hivaneph\abilitysystem\abilitysystemcomponent.cpp:108]
UE4Editor_Hivaneph_7524!UAbilitySystemComponent::UseAbility() [c:\users\lucas\dev-projects\ue4\hivaneph\hivaneph\source\hivaneph\abilitysystem\abilitysystemcomponent.cpp:139]
UE4Editor_Hivaneph_7524!UAbilitySystemComponent::UseSelectedAbility() [c:\users\lucas\dev-projects\ue4\hivaneph\hivaneph\source\hivaneph\abilitysystem\abilitysystemcomponent.cpp:202]

---> I cut the callstack here because there's no need for you to see all of it <---


Thanks!

Launch UEditor from within Visual Studio and run it while VS is debugging to see where it takes you to when the crash happens…

I bet it’s going to bring you to currentPassives.Add(NewObject<> … but see what happens :wink:

I can’t run UE4 from within VS, but I attached VS debugger to UE4 and it took me to MallocTBB.cpp:
(scroll down a bit and you’ll see the exact line)



void* FMallocTBB::Realloc( void* Ptr, SIZE_T NewSize, uint32 Alignment )
{
    IncrementTotalReallocCalls();

#if !UE_BUILD_SHIPPING
    uint64 LocalMaxSingleAlloc = MaxSingleAlloc.Load(EMemoryOrder::Relaxed);
    if (LocalMaxSingleAlloc != 0 && NewSize > LocalMaxSingleAlloc)
    {
        FPlatformMemory::OnOutOfMemory(NewSize, Alignment);
        return nullptr;
    }
#endif

    MEM_TIME(MemTime -= FPlatformTime::Seconds())
#if UE_BUILD_DEBUG
    SIZE_T OldSize = 0;
    if (Ptr)
    {
        OldSize = scalable_msize(Ptr);
        if (NewSize < OldSize)
        {
            FMemory::Memset((uint8*)Ptr + NewSize, DEBUG_FILL_FREED, OldSize - NewSize);
        }
    }
#endif
    void* NewPtr = NULL;
#if PLATFORM_MAC
    // macOS expects all allocations to be aligned to 16 bytes, but TBBs default alignment is 8, so on Mac we always have to use scalable_aligned_realloc
    Alignment = AlignArbitrary(FMath::Max((uint32)16, Alignment), (uint32)16);
    NewPtr = scalable_aligned_realloc(Ptr, NewSize, Alignment);
#else
    if (Alignment != DEFAULT_ALIGNMENT)
    {
        Alignment = FMath::Max(NewSize >= 16 ? (uint32)16 : (uint32)8, Alignment);
        NewPtr = scalable_aligned_realloc(Ptr, NewSize, Alignment);
    }
    else
    {
        NewPtr = scalable_realloc(Ptr, NewSize); //<---------------------------------------- Right here
    }
#endif
#if UE_BUILD_DEBUG
    if (NewPtr && NewSize > OldSize )
    {
        FMemory::Memset((uint8*)NewPtr + OldSize, DEBUG_FILL_NEW, NewSize - OldSize);
    }
#endif
    if( !NewPtr && NewSize )
    {
        OutOfMemory(NewSize, Alignment);
    }
    MEM_TIME(MemTime += FPlatformTime::Seconds())
    return NewPtr;
}


If the problem was on *currentPassives.Add() *we wouldn’t even get to UEntityAttribute::RegisterPassive() (and we do, as you can see in the callstack), which is where I call Add on attachedPassives and the crash happens.

You say this only occurs when you play a game in editor for the second time, which leads me to think UEntityAttribute isn’t being cleaned up properly. Where does UEntityAttribute exist?

I haven’t tested on a standalone build yet, so I don’t know if this only happens in the editor.
[FONT=courier new]UEntityAttribute is a default subobject of my player, I create it in my player’s constructor using



npAttribute = CreateDefaultSubobject<UEntityAttribute>(TEXT("npAttribute"));


So it exists in the editor as well as in-game. Is there some sort of specific initialization I should do on [FONT=courier new]UObjects that should be default subobjects?

[FONT=courier new]UEntityAttribute is also an [FONT=courier new]FTickableGameObject, if that’s somehow relevant.

If you had symbols installed and ran it stepping through code in Visual Studio you’d have this solved already by now :expressionless:

I did, that’s the first thing I ever do (and I also made a post saying that I did it and it took me to MallocTBB.cpp). I’ve spent more than 2 hours trying to solve this already.

Whenever I get to [FONT=courier new]attachedPassives.Add(passive)UE4 crashes. Sometimes it crashes earlier for some weird reason, I’ve stepped through code a billion times and there’s stuff happening that just doesn’t make any sense. For example: a crash happened a few times in which the callstack said the Tick function of an object called function A of that object, even though Tick never calls A. When I went stepping through code, a for loop in Tick (the “declaration” of the for loop) was jumping to the “declaration” of a for loop in A. This doesn’t make any sense. I tried cleaning binaries, regenerating the project file, everything I could possibly think of.

Ever since I started playing around with creating a custom details panel UE4 has been very weird…

Did you try yet to verify that the allocated NewObject is valid before adding to the array?
Because ResizeGrow() is where your crash happens…
​​​​​

Just to take hardware out of the equation, have you tried running a memory test? https://www.memtest.org/ Is a great tool to just verify that your RAM isn’t dying on you (rare, but it happens).

Yeah, it’s valid, but I think I know where the problem is.

The problem occurs on RegisterPassive, when this is called:



targetAttribute->RegisterPassive(this);


But I thought that targetAttribute was valid, and it seems it isn’t. Here’s the code I omitted from UBasicPassive::OnInitialize (I thought it wasn’t relevant for this post)



void UBasicPassive::OnInitialize()
{
    Super::OnInitialize();

    targetEntity = Cast<ABaseEntity>(target->GetOwner());

    if (UProperty* prop = targetClass->FindPropertyByName(targetAttributeName))
    {
        targetAttribute = (UEntityAttribute*)prop->ContainerPtrToValuePtr<UObject>(targetEntity);

        if (targetAttribute == nullptr)
        {
            //Log Error
            return;
        }
    }
    else
    {
        //Log Error
        return;
    }

    targetAttribute->RegisterPassive(this);
}


As you can see, targetAttribute is never null, but it doesn’t mean the pointer is valid. So when I call RegisterPassive, I’m calling it on an invalid object and everything goes to hell. After I did a Cast instead of a C-Style cast, UE4 crashed because the pointer returned by [FONT=courier new]prop->ContainerPtrToValuePtr(targetEntity) wasn’t a [FONT=courier new]UEntityAttribute.

After finding this I could fix the problem, here’s how I get [FONT=courier new]targetAttribute now



if (UObjectProperty* prop = Cast<UObjectProperty>(targetClass->FindPropertyByName(targetAttributeName)))
{
    targetAttribute = Cast<UEntityAttribute>(prop->GetObjectPropertyValue_InContainer(targetEntity, 0));
...


Now everything works fine. The issue was caused because the C-Style cast can only fail at compile-time, so if the object isn’t a [FONT=courier new]UEntityAttribute I get no errors but the pointer is invalid.

Ok, lesson learned, always prefer UE4’s Cast function or C++ casts (dynamic_cast, static_cast) over C-Style casting.

Thanks for your help!

(■■■■ I feel stupid)