Fix StaticDuplicateObject when Source and Destination classes are different

StaticDuplicateObject makes use of FDuplicateDataWriter and FDuplicateDataReader

to do a deep copy of UObjects.

Starting in UE5.4 FDuplicateDataWriter and FDuplicateDataReader switched to using Unversioned Property Serialization (UPS) as the serialization method because UPS is faster than Tagged Property Serialization (TPS). Unfortunately UPS can not be used in the case that the caller of StaticDuplicateObject specifies a class that is different from the Source object’s class because UPS assumes that both sets of serialized properties are the same

What happens in my test is that because we serialize -1 from the Base object and then we will read that -1 as the size of DerivedArray when serializing the -1 from the archive into the Derived object. And boom. We crash.

I have created a PR with my proposed fix here Fix StaticDuplicateObject when Source Object class and Destination class are different by KeithRare · Pull Request #13450 · EpicGames/UnrealEngine. The idea is just to force TPS when the source and destination classes differ. Nothing too fancy.

I have tried a number of other methods to get around this issue since upgrading to UE5.4, and none quite work. So I felt that the easiest thing to do was just to fix `StaticDuplicateObject` so that it behaves like it did pre-UE5.4.

If there is an easier solution than this fix, however, I will happily try it :slight_smile:

Cheers,

Keith

Steps to Reproduce
Given the following header:

`#pragma once

include “Containers/Array.h”
include “UObject/Object.h”

include “StaticDuplicateObjectTests.generated.h”

UCLASS()
class UBaseClass
: public UObject
{
GENERATED_BODY()
public:

UPROPERTY()
int32 A;
};

UCLASS()
class UDerivedClass
: public UBaseClass
{
GENERATED_BODY()
public:

UPROPERTY()
TArray< int32 > DerivedArray;
};`And this test:

`#include “StaticDuplicateObjectTests.h”

include “CQTest.h”

include UE_INLINE_GENERATED_CPP_BY_NAME(StaticDuplicateObjectTests)

TEST_CLASS(StaticDuplicateObjectTests, GenerateTestDirectory)
{
TEST_METHOD(GIVEN_SourceIsBaseOfDestination_WHEN_StaticDuplicateObjectCalled_THEN_Crash)
{
auto* Source = NewObject< UBaseClass >();
Source->A = -1;

auto* Copy = StaticDuplicateObject(Source, Source->GetOuter(), NAME_None, RF_AllFlags, UDerivedClass::StaticClass());
}
};`You will crash.

Hello [mention removed]​,

Thanks for your report. I’ve reproduced this error in UE versions 5.4 through 5.6 including a source build from Main at CL (40574608).

I also confirmed that the crash does not occur in UE 5.3 due to the previous serialization method used.

I’ve escalated this regression to the internal engine team and created a JIRA report. The issue will soon be visible on the public Unreal issue tracker at:

Please note that Epic ultimately determines whether the issue will be made publicly accessible, and the process may take a few days. The tracking link might not work immediately.

As a temporary workaround, your proposed fix remains valid. I’ve included a link to your pull request in the bug description so the developers can review and consider it directly.

I’ll go ahead and close this case for now, but feel free to reply if you have anything else to add.

Best,

Francisco