Announcement

Collapse
No announcement yet.

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

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

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

    For some odd reason, UE4 keeps crashing when this is called:
    Code:
    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 attachedPassives
    Code:
    UPROPERTY()
    TArray<UBasicPassive*> attachedPassives;
    This is how RegisterPassive is called
    Code:
    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:

    Code:
    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
    Code:
    Access violation - code c0000005 (first/second chance not available)
    
    UE4Editor_Core!rml::internal::reallocAligned() [l:\dev\partner-intel\engine\source\thirdparty\inteltbb\inteltbb-4.4u3\src\tbbmalloc\frontend.cpp:2346]
    UE4Editor_Core!scalable_realloc() [l:\dev\partner-intel\engine\source\thirdparty\inteltbb\inteltbb-4.4u3\src\tbbmalloc\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\taskscomponent.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!
    C++ is awesome

    #2
    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
    | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

    Comment


      #3
      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)
      Code:
      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.
      C++ is awesome

      Comment


        #4
        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?

        Comment


          #5
          I haven't tested on a standalone build yet, so I don't know if this only happens in the editor.
          UEntityAttribute is a default subobject of my player, I create it in my player's constructor using

          Code:
          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 UObjects that should be default subobjects?

          UEntityAttribute is also an FTickableGameObject, if that's somehow relevant.
          C++ is awesome

          Comment


            #6
            If you had symbols installed and ran it stepping through code in Visual Studio you'd have this solved already by now :|
            | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

            Comment


              #7
              Originally posted by BrUnO XaVIeR View Post
              If you had symbols installed and ran it stepping through code in Visual Studio you'd have this solved already by now :|
              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 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...

              C++ is awesome

              Comment


                #8
                Did you try yet to verify that the allocated NewObject is valid before adding to the array?
                Because ResizeGrow() is where your crash happens...
                ​​​​​
                | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                Comment


                  #9
                  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).
                  Able Ability System - A high performance, robust ability system for UE4. Now Available!

                  Comment


                    #10
                    Yeah, it's valid, but I think I know where the problem is.

                    The problem occurs on RegisterPassive, when this is called:

                    Code:
                    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)
                    Code:
                    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 prop->ContainerPtrToValuePtr<UObject>(targetEntity) wasn't a UEntityAttribute.

                    After finding this I could fix the problem, here's how I get targetAttribute now
                    Code:
                    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 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)
                    C++ is awesome

                    Comment

                    Working...
                    X