Slate tab creation with virtual function crashes editor

While I have experience with both UE4, and UDK, I come from Unity and I am currently working on a Plugin that will facilitate a designer-friendly Attribute System (including the creation of new Attributes, Modifiers, and Statblocks on the fly) as a means to get my programming level in UE4 up to par with my programming level in Unity.

Thus far I managed to create a Main Toolbar button for the Plugin and a Menu entry that comes with a Sub-Menu entry for each new class that inherits from my base Class.

Initially, I had a simple function to create a Tab when any of the sub-menu entries are clicked, and that works fine, but, my intention is to turn that function into a virtual function that each child class can override to implement the type of interface that specific menu would need - sadly, the Editor does not like this approach, and crashes if I attempt to create the Tab with a virtual function.

Attached below are the snippets of code relevant to the issue, as well as the crash report message. Keep in mind however, that declaring the same function as a non-virtual function does not cause the editor to crash.

I would truly appreciate if someone could explain why the Editor crashes like this, and I’d be specially grateful if anyone could point me towards the right direction in solving it. Thank you :slight_smile:

Relevant code in StartUpModule

/* Register Tab Management */
	TSharedRef<class FGlobalTabmanager> TabManager = FGlobalTabmanager::Get();
	TabManager->RegisterNomadTabSpawner(AttributeSystemTabName, FOnSpawnTab::CreateRaw(this, &FAttributeSystemModule::SpawnTab))
		.SetDisplayName(FText::FromString(TEXT("Attribute System")));

Triggering the Sub-Menu

/* SubMenus Click Action */
void FAttributeSystemModule::TriggerDatabase(UClass* ATSDBClass) {
	
	TSharedRef<class FGlobalTabmanager> TabManager = FGlobalTabmanager::Get();
	TabManager->InvokeTab(AttributeSystemTabName);
	
}

The call to the function

TSharedRef<class SDockTab> FAttributeSystemModule::SpawnTab(const FSpawnTabArgs& SpawnTabArgs) {
	
	return DatabaseClass->CustomizeTab(SpawnTabArgs);
}

Function Declaration in UATSDatabase

virtual TSharedRef<class SDockTab> CustomizeTab(const FSpawnTabArgs& SpawnTabArgs);

Function Implementation

TSharedRef<class SDockTab> UATSDatabase::CustomizeTab(const FSpawnTabArgs & SpawnTabArgs) {

	TSharedRef<SDockTab> SpawnedTab = SNew(SDockTab)
		.TabRole(ETabRole::NomadTab)
		[
			SNew(SButton)
			.Text(FText::FromString(TEXT("Hi")))
		.ContentPadding(3)
		];

	return SpawnedTab;
}

Crash Report

MachineId:197F04144AB00EC29DAE44B8C7027891
EpicAccountId:f07e4091e17a4e64b3f9954e2515a4d5

Access violation - code c0000005 (first/second chance not available)

UE4Editor_AttributeSystem!FAttributeSystemModule::SpawnTab() [c:\users\\documents\unreal projects\prototypes\pluginlibrary\plugins\attributesystem\source\attributesystem\private\attributesystem.cpp:161]
UE4Editor_AttributeSystem!TMemberFunctionCaller<FAttributeSystemModule,TSharedRef<SDockTab,0> (__cdecl FAttributeSystemModule::*)(FSpawnTabArgs const & __ptr64) __ptr64>::operator()<FSpawnTabArgs const & __ptr64>() [c:\program files (x86)\epic games\4.13\engine\source\runtime\core\public\delegates\delegateinstanceinterface.h:161]
UE4Editor_AttributeSystem!TTupleImpl<TIntegerSequence<unsigned int> >::ApplyAfter<TMemberFunctionCaller<FAttributeSystemModule,TSharedRef<SDockTab,0> (__cdecl FAttributeSystemModule::*)(FSpawnTabArgs const & __ptr64) __ptr64>,FSpawnTabArgs const & __ptr64>() [c:\program files (x86)\epic games\4.13\engine\source\runtime\core\public\delegates\tuple.h:115]
UE4Editor_AttributeSystem!TBaseRawMethodDelegateInstance<0,FAttributeSystemModule,TSharedRef<SDockTab,0> __cdecl(FSpawnTabArgs const & __ptr64)>::Execute() [c:\program files (x86)\epic games\4.13\engine\source\runtime\core\public\delegates\delegateinstancesimpl.h:546]
UE4Editor_Slate!TBaseDelegate<TSharedRef<SDockTab,0>,FSpawnTabArgs const & __ptr64>::Execute() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\core\public\delegates\delegatesignatureimpl.inl:521]
UE4Editor_Slate!FTabManager::SpawnTab() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\slate\private\framework\docking\tabmanager.cpp:1291]
UE4Editor_Slate!FTabManager::InvokeTab_Internal() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\slate\private\framework\docking\tabmanager.cpp:1013]
UE4Editor_Slate!FTabManager::InvokeTab() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\slate\private\framework\docking\tabmanager.cpp:954]
UE4Editor_AttributeSystem!FAttributeSystemModule::TriggerDatabase() [c:\users\\documents\unreal projects\prototypes\pluginlibrary\plugins\attributesystem\source\attributesystem\private\attributesystem.cpp:95]
UE4Editor_AttributeSystem!TBaseStaticDelegateInstance<void __cdecl(void),UClass * __ptr64>::ExecuteIfSafe() [c:\program files (x86)\epic games\4.13\engine\source\runtime\core\public\delegates\delegateinstancesimpl.h:1017]
UE4Editor_Slate!SMenuEntryBlock::OnClicked() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\slate\private\framework\multibox\smenuentryblock.cpp:1036]
UE4Editor_Slate!SMenuEntryBlock::OnMenuItemButtonClicked() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\slate\private\framework\multibox\smenuentryblock.cpp:987]
UE4Editor_Slate!TMemberFunctionCaller<SMenuEntryBlock,FReply (__cdecl SMenuEntryBlock::*)(void) __ptr64>::operator()<>() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\core\public\delegates\delegateinstanceinterface.h:161]
UE4Editor_Slate!TTupleImpl<TIntegerSequence<unsigned int> >::ApplyAfter<TMemberFunctionCaller<SMenuEntryBlock,FReply (__cdecl SMenuEntryBlock::*)(void) __ptr64> >() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\core\public\delegates\tuple.h:115]
UE4Editor_Slate!TBaseSPMethodDelegateInstance<0,SMenuEntryBlock,0,FReply __cdecl(void)>::Execute() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\core\public\delegates\delegateinstancesimpl.h:317]
UE4Editor_Slate!TBaseDelegate<FReply>::Execute() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\core\public\delegates\delegatesignatureimpl.inl:521]
UE4Editor_Slate!SButton::OnMouseButtonUp() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\slate\private\widgets\input\sbutton.cpp:278]
UE4Editor_Slate!SMenuEntryButton::OnMouseButtonUp() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\slate\private\framework\multibox\smenuentryblock.cpp:385]
UE4Editor_Slate!<lambda_8d0e9a1da76abd0a756a3a9d775f5ed1>::operator()() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\slate\private\framework\application\slateapplication.cpp:4901]
UE4Editor_Slate!FEventRouter::Route<FReply,FEventRouter::FToLeafmostPolicy,FPointerEvent,<lambda_8d0e9a1da76abd0a756a3a9d775f5ed1> >() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\slate\private\framework\application\slateapplication.cpp:215]
UE4Editor_Slate!FSlateApplication::RoutePointerUpEvent() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\slate\private\framework\application\slateapplication.cpp:4890]
UE4Editor_Slate!FSlateApplication::ProcessMouseButtonUpEvent() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\slate\private\framework\application\slateapplication.cpp:5348]
UE4Editor_Slate!FSlateApplication::OnMouseUp() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\slate\private\framework\application\slateapplication.cpp:5328]
UE4Editor_Core!FWindowsApplication::ProcessDeferredMessage() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\core\private\windows\windowsapplication.cpp:1584]
UE4Editor_Core!FWindowsApplication::DeferMessage() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\core\private\windows\windowsapplication.cpp:1930]
UE4Editor_Core!FWindowsApplication::ProcessMessage() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\core\private\windows\windowsapplication.cpp:747]
UE4Editor_Core!FWindowsApplication::AppWndProc() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\core\private\windows\windowsapplication.cpp:669]
user32
user32
UE4Editor_Core!FWindowsPlatformMisc::PumpMessages() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\core\private\windows\windowsplatformmisc.cpp:905]
UE4Editor!FEngineLoop::Tick() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\launch\private\launchengineloop.cpp:2788]
UE4Editor!GuardedMain() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\launch\private\launch.cpp:156]
UE4Editor!GuardedMainWrapper() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:126]
UE4Editor!WinMain() [d:\build\++ue4+release-4.13+compile\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:202]
UE4Editor!__scrt_common_main_seh() [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:264]
kernel32
ntdll

While I still do not understand how it was working with a non-virtual function, I solved this issue.

There was a problem with my casting of UClass* into my UATSDatabase* class, and the code was trying to access a null pointer. It didn’t occur to me earlier because there wasn’t any problem accessing the non-virtual version of this function from the very same pointer (so I thought I couldn’t possibly be null in that case).

Out of all the methods I tried to successfully cast UClass* into UATSDatabase* the one that worked for me was

for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt) {
		
		UClass* Class = *ClassIt;

		if (!Class->HasAnyClassFlags(CLASS_Deprecated | CLASS_NewerVersionExists | CLASS_Abstract)) {

			if (Class->IsChildOf(UATSDatabase::StaticClass())) {

				DatabaseClass = Cast<UATSDatabase>(Class->GetDefaultObject(true));

/*
// Bunch of irrelevant code 
*/

        }
    }
}