Hello,
We are migrating from 5.5.4 to 5.6.0 and encountered a crash during the destruction of a skeletal mesh component that is attached via a socket to a parent skeletal mesh component. The crash occurs when we trace the parent skeletal mesh in the same tick as the child is destroyed.
The crash appears related to the Weld system. The `WeldToImplementation`` call on attach works correctly, but during \``UnWeldFromParent`` there is no fallback to resolve the socket name into a bone name when looking up the
BodyInstance`, which results in a null dereference.
We fixed the crash by transferring the fallback logic from WeldToImplementation
into UnWeldFromParent
, specifically resolving the BoneName
from the socket if the original BodyInstance
lookup fails. Here’s the relevant fix (look to code block).
This ensures that the component properly unwelds when destroyed mid-tick, even if it’s still involved in a physics trace.
Regards Igor.
`void UPrimitiveComponent::UnWeldFromParent()
{
FBodyInstance* NewRootBI = GetBodyInstance(NAME_None, false);
UWorld* CurrentWorld = GetWorld();
if (NewRootBI == NULL || NewRootBI->WeldParent == nullptr || CurrentWorld == nullptr || CurrentWorld->GetPhysicsScene() == nullptr || !IsValidChecked(this) || IsUnreachable())
{
return;
}
// If we’re purging (shutting down everything to kill the runtime) don’t proceed
// to make new physics bodies and weld them, as they’ll never be used.
if(GExitPurge)
{
return;
}
SCOPE_CYCLE_COUNTER(STAT_UnweldPhysics);
FName SocketName;
UPrimitiveComponent * RootComponent = GetRootWelded(this, GetAttachSocketName(), &SocketName);
if (RootComponent)
{
//start fix
FBodyInstance* RootBI = RootComponent->GetBodyInstance(SocketName, false);
FName BoneName = SocketName;
//If initial lookup fails, check if we need to lookup the bone from the socket instead
if (!RootBI && RootComponent->IsA())
{
USkeletalMeshComponent* RootSkeletal = Cast(RootComponent);
if (const USkeletalMeshSocket* Socket = RootSkeletal->GetSocketByName(SocketName))
{
BoneName = Socket->BoneName;
RootBI = RootComponent->GetBodyInstance(BoneName, false);
}
}
if (RootBI)
{
//end fix
bool bRootIsBeingDeleted = !IsValidChecked(RootComponent) || RootComponent->IsUnreachable();
const FBodyInstance* PrevWeldParent = NewRootBI->WeldParent;`