We’ve been seeing asserts and crashes related to OwnerLastRenderTimePtr. We’ve traced this to the mentioned pointer ending up dangling after using UActorComponent::Rename() on primitive components to reuse/reparent them, for example:
WeaponMeshComponent->Rename(nullptr, WeaponActor);
where:
- WeaponMeshComponent is derived from PrimitiveComponent
- WeaponActor is a newly created actor
- The previous owner of WeaponMeshComponent is being destroyed
The problem is that WeaponMeshComponent’s SceneData.OwnerLastRenderTimePtr pointer still points to the old parent object being destroyed. The code in UPrimitiveComponent::ReleaseSceneProxy() that accesses this pointer can crash directly or corrupt mem elsewhere via the atomic operation on SceneData.OwnerLastRenderTimePtr->NumAlwaysVisibleComponents. We trapped this with stomp malloc.
Potential fix that has eliminated lots of the random crashes in our testing so far is to add this PostRename method.
`void UPrimitiveComponent::PostRename(UObject* OldOuter, const FName OldName)
{
Super::PostRename(OldOuter, OldName);
FActorLastRenderTime* OldLastRenderTimePtr = SceneData.OwnerLastRenderTimePtr;
FActorLastRenderTime* NewLastRenderTimePtr = FActorLastRenderTime::GetPtr(GetOwner());
if (OldLastRenderTimePtr &&
OldLastRenderTimePtr != NewLastRenderTimePtr)
{
SceneData.OwnerLastRenderTimePtr = NewLastRenderTimePtr;
// Update the Number of visible components on the new owner if we are always visible,
// otherwise we’ll assert later due to this count being off when releasing the sceneproxy
if (SceneData.bAlwaysVisible && SceneData.OwnerLastRenderTimePtr)
{
SceneData.OwnerLastRenderTimePtr->NumAlwaysVisibleComponents.fetch_add(1, std::memory_order_relaxed);
}
}
}`