Fix crash on exit when C# code was bound to asset unloading event called after C# shutdown
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
MDomain* MRootDomain = nullptr;
|
MDomain* MRootDomain = nullptr;
|
||||||
MDomain* MActiveDomain = nullptr;
|
MDomain* MActiveDomain = nullptr;
|
||||||
Array<MDomain*, FixedAllocation<4>> MDomains;
|
Array<MDomain*, FixedAllocation<4>> MDomains;
|
||||||
|
bool MCore::Ready = false;
|
||||||
|
|
||||||
MClass* MCore::TypeCache::Void = nullptr;
|
MClass* MCore::TypeCache::Void = nullptr;
|
||||||
MClass* MCore::TypeCache::Object = nullptr;
|
MClass* MCore::TypeCache::Object = nullptr;
|
||||||
@@ -301,6 +302,11 @@ bool MProperty::IsStatic() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MCore::OnManagedEventAfterShutdown(const char* eventName)
|
||||||
|
{
|
||||||
|
LOG(Error, "Found a binding leak on '{}' event used by C# scripting after shutdown. Ensure to unregister scripting events from objects during disposing.", ::String(eventName));
|
||||||
|
}
|
||||||
|
|
||||||
MDomain* MCore::GetRootDomain()
|
MDomain* MCore::GetRootDomain()
|
||||||
{
|
{
|
||||||
return MRootDomain;
|
return MRootDomain;
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ public:
|
|||||||
static void UnloadScriptingAssemblyLoadContext();
|
static void UnloadScriptingAssemblyLoadContext();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Utility for guarding against using C# scripting runtime after shutdown (eg. when asset delegate is not properly disposed).
|
||||||
|
static bool Ready;
|
||||||
|
static void OnManagedEventAfterShutdown(const char* eventName);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Utilities for C# object management.
|
/// Utilities for C# object management.
|
||||||
|
|||||||
@@ -316,7 +316,8 @@ bool MCore::LoadEngine()
|
|||||||
|
|
||||||
char* buildInfo = CallStaticMethod<char*>(GetStaticMethodPointer(TEXT("GetRuntimeInformation")));
|
char* buildInfo = CallStaticMethod<char*>(GetStaticMethodPointer(TEXT("GetRuntimeInformation")));
|
||||||
LOG(Info, ".NET runtime version: {0}", ::String(buildInfo));
|
LOG(Info, ".NET runtime version: {0}", ::String(buildInfo));
|
||||||
MCore::GC::FreeMemory(buildInfo);
|
GC::FreeMemory(buildInfo);
|
||||||
|
Ready = true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -327,6 +328,7 @@ void MCore::UnloadEngine()
|
|||||||
return;
|
return;
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
CallStaticMethod<void>(GetStaticMethodPointer(TEXT("Exit")));
|
CallStaticMethod<void>(GetStaticMethodPointer(TEXT("Exit")));
|
||||||
|
Ready = false;
|
||||||
MDomains.ClearDelete();
|
MDomains.ClearDelete();
|
||||||
MRootDomain = nullptr;
|
MRootDomain = nullptr;
|
||||||
ShutdownHostfxr();
|
ShutdownHostfxr();
|
||||||
|
|||||||
@@ -2043,6 +2043,7 @@ namespace Flax.Build.Bindings
|
|||||||
contents.Append(')').AppendLine();
|
contents.Append(')').AppendLine();
|
||||||
contents.Append(" {").AppendLine();
|
contents.Append(" {").AppendLine();
|
||||||
contents.Append(" static MMethod* method = nullptr;").AppendLine();
|
contents.Append(" static MMethod* method = nullptr;").AppendLine();
|
||||||
|
contents.AppendFormat(" if (!MCore::Ready) {{ MCore::OnManagedEventAfterShutdown(\"{0}.{1}\"); return; }}", classTypeNameManaged, eventInfo.Name).AppendLine();
|
||||||
contents.AppendFormat(" if (!method) {{ method = {1}::TypeInitializer.GetClass()->GetMethod(\"Internal_{0}_Invoke\", {2}); CHECK(method); }}", eventInfo.Name, classTypeNameNative, paramsCount).AppendLine();
|
contents.AppendFormat(" if (!method) {{ method = {1}::TypeInitializer.GetClass()->GetMethod(\"Internal_{0}_Invoke\", {2}); CHECK(method); }}", eventInfo.Name, classTypeNameNative, paramsCount).AppendLine();
|
||||||
contents.Append(" MObject* exception = nullptr;").AppendLine();
|
contents.Append(" MObject* exception = nullptr;").AppendLine();
|
||||||
if (paramsCount == 0)
|
if (paramsCount == 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user