[4.12.3] Crash with PostInitProperties() and RTTI

Hi all,

I am trying to integrate our messaging framework into UE4 as a plugin. A message subscriber/publisher is implemented as an ActorComponent and uses Google Protobuf for data serialization. With Binary 4.12.2 it runs stable for a first prototype. So now its time to move on to to also target Android tablets.

Therefore I had to switch from Binary to Source version (4.12.3) and change the bUseRTTI-Flag in UBT as well as add a Compiler-Flag “/wd4125” in VCToolchain.cs to disable warnings originating from Google Protobuf. The whole engine is now built with RTTI enabled. Before being able to build Android, I need to get into the Engine Editor again to launch on Android from there. But now, after successfully compiling, the Windows target crashes (on two different machines) even after complete rebuild around Line 2612 in UObjectGlobals.cpp:

failed to route PostInitProperties. Call Super::PostInitProperties() in UMsgFwReceiver::PostInitProperties()

It basically says what to change, but adding this function didn’t fix the issue. What am I missing?

Cheers

ActorComponent.h:

UCLASS(Blueprintable, ClassGroup=("MsgFw Receiver"), meta=(BlueprintSpawnableComponent) )
class MSGFWPLUGIN_API UMsgFwReceiver : public UActorComponent
{
	GENERATED_BODY()
public:	
  	UMsgFwReceiver();
	~UMsgFwReceiver();
          	
	virtual void BeginPlay() override;
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason);
    virtual void PostInitProperties() override; // just added according to error message, same situation with and without
	
    /** Delegate */
	DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(F_ProtobufTestMsg_Delegate, F_ProtobufTestMsg, ProtobufTestMsg);
	UPROPERTY(BlueprintAssignable, Category = "MsgFw|Receiver|Event", meta=(DisplayName = "ProtobufTestMsg received"))
		F_ProtobufTestMsg_Delegate EventProtobufTestMsgReceived;
	UFUNCTION(BlueprintCallable, Category = "MsgFw|Receiver|GetMessage", meta=(DisplayName = "Get TestMsg message"))
		F_ProtobufTestMsg &GetMessage();
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="MsgFw")
	FString TopicName;

	/** Unreal Message representation of proto-file - custom generator to unreal C-Structs euqivalent */
	UPROPERTY(BlueprintReadOnly, Category="MsgFw")
	F_ProtobufTestMsg Message;
	
private:
	void OnProtobufTestMsg(FString TopicName, const class protobuf::message::type::TestTopic& ProtobufTestMsg);
	MsgFw::ProtoSubscriber<protobuf::message::type::TestTopic> Subscriber;
	std::mutex MessageMutex;
};

ActorComponent.cpp:

UMsgFwReceiver::UMsgFwReceiver()
{
  PrimaryComponentTick.bCanEverTick = true;
  MsgFw::Initialize("Unreal Node");
  TopicName = "TestTopic";
}

UMsgFwReceiver::~UMsgFwReceiver()
{
  MsgFw::Finalize();
}

void UMsgFwReceiver::BeginPlay()
{
  Super::BeginPlay();
  if (!MsgFw::IsInitialized())
  {
    UE_LOG(LogTemp, Error, TEXT("MsgFw not initiliazed, no TestTopic Subscriber created!"));
    return;
  }
  else
  {
    auto topic = TCHAR_TO_UTF8(*TopicName);
    Subscriber.Create(topic);
    auto Callback = std::bind(&UMsgFwReceiver::OnTestTopic, this, std::placeholders::_1, std::placeholders::_2);
    Subscriber.AddReceiveCallback(Callback);
    UE_LOG(LogTemp, Log, TEXT("MsgFw initiliazed, subscribing to TestTopic"));
  }
}

void UMsgFwReceiver::PostInitProperties()
{
  Super::PostInitProperties();
}

void UMsgFwReceiver::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
  Subscriber.RemReceivMsgFwCallback();
}

F_UnrealMsgType& UMsgFwReceiver::GetMessage()
{
  std::lock_guard<std::mutex> lock(MessageMutex);
  return Message;
}

// protobuf to unreal struct conversion on message receive
void UMsgFwReceiver::OnTestTopic(FString TopicName, const class protobuf::message::type::TestTopic& ProtobufTestMsg)
{
  F_UnrealMsgType NewMessage;
  unreal_conv::convert(TestTopic,NewMessage);
  SetTestTopic(NewMessage);
  EventProtobufTestMsgReceived.Broadcast(Message);
}

void UMsgFwReceiver::SetTestTopic(F_UnrealMsgType& NewMsg)
{
	Message = NewMsg;
}

I ran into the same problem and stumbled upon your question. The problem is that enabling RTTI changes the layout of the classes being compiled. The vtable of the UObject in the RTTI module is not what the code in the non-RTTI Engine expects. As a result, the call to PostInitProperties() actually ends up calling PreSaveRoot() (or possibly some other function, depending on Engine version) with bogus function parameters.

The bottom line is that you cannot enable RTTI in modules that contain UObjects, because those objects won’t be compatible with the rest of the Engine. I worked around this by creating a separate wrapper module that isolates the SDK from the Engine by exposing the RTTI-based API with a straightforward C API (you can also use a C++ class as long as it doesn’t contain any virtual functions).