diff --git a/source/CJSEngine.cpp b/source/CJSEngine.cpp index 716d9f5be..3de2c513a 100644 --- a/source/CJSEngine.cpp +++ b/source/CJSEngine.cpp @@ -59,7 +59,8 @@ auto CJSEngine::Startup() -> void if (!JS_Init()) { throw new std::runtime_error("Unable to initialise JavaScript engine"); - } + } + jsInitialized = true; runtimeList.push_back( new CJSRuntime( engineMaxBytes )); // Default Runtime //runtimeList.push_back( new CJSRuntime( engineMaxBytes )); // Console Runtime @@ -70,16 +71,30 @@ auto CJSEngine::Startup() -> void //=================================================================== CJSEngine::~CJSEngine() { - // Why? we are shutting down, the process memory will take care of this for us in theory - /* + Shutdown(); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CJSEngine::Shutdown() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Releases all JavaScript runtimes before shutting down SpiderMonkey +//o------------------------------------------------------------------------------------------------o +void CJSEngine::Shutdown( void ) +{ for( RUNTIMELIST_ITERATOR rIter = runtimeList.begin(); rIter != runtimeList.end(); ++rIter ) { - if(( *rIter)) + if(( *rIter ) != nullptr ) { delete ( *rIter ); } } - */ + runtimeList.clear(); + + if( jsInitialized ) + { + JS_ShutDown(); + jsInitialized = false; + } } void CJSEngine::Reload( void ) diff --git a/source/CJSEngine.h b/source/CJSEngine.h index 20abbbd9b..7296df051 100644 --- a/source/CJSEngine.h +++ b/source/CJSEngine.h @@ -94,6 +94,7 @@ class CJSEngine typedef std::vector::const_iterator RUNTIMELIST_CITERATOR; RUNTIMELIST runtimeList; + bool jsInitialized = false; public: @@ -101,6 +102,7 @@ class CJSEngine ~CJSEngine(); auto Startup() -> void; + void Shutdown( void ); JSRuntime * GetRuntime( UI08 runTime ) const; JSContext * GetContext( UI08 runTime ) const; diff --git a/source/CJSMapping.cpp b/source/CJSMapping.cpp index 5af4e70c6..d84a233ac 100644 --- a/source/CJSMapping.cpp +++ b/source/CJSMapping.cpp @@ -39,7 +39,17 @@ CJSMapping::CJSMapping() */ CJSMapping::~CJSMapping() { - //Cleanup(); + Shutdown(); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CJSMapping::Shutdown() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Releases all script mappings and their persistent JavaScript roots +//o------------------------------------------------------------------------------------------------o +void CJSMapping::Shutdown( void ) +{ + Cleanup(); } //o------------------------------------------------------------------------------------------------o diff --git a/source/CJSMapping.h b/source/CJSMapping.h index 522fffeb3..112500316 100644 --- a/source/CJSMapping.h +++ b/source/CJSMapping.h @@ -54,10 +54,10 @@ class CJSMappingSection class CJSMapping { private: - CJSMappingSection * mapSection[SCPT_COUNT]; + CJSMappingSection * mapSection[SCPT_COUNT]{}; - CEnvoke * envokeById; - CEnvoke * envokeByType; + CEnvoke * envokeById = nullptr; + CEnvoke * envokeByType = nullptr; void Cleanup( void ); void Parse( SCRIPTTYPE toParse = SCPT_COUNT ); @@ -67,6 +67,7 @@ class CJSMapping public: CJSMapping() = default; ~CJSMapping(); + void Shutdown( void ); void ResetDefaults( void ); void Reload( UI16 scriptId = 0xFFFF ); diff --git a/source/cScript.cpp b/source/cScript.cpp index 28f22f4fa..a91c7147e 100644 --- a/source/cScript.cpp +++ b/source/cScript.cpp @@ -12,6 +12,7 @@ #include "StringUtility.hpp" #include "osunique.hpp" #include +#include #include #include #include @@ -19,11 +20,28 @@ #include #include #include +#include #include #include static constexpr SI08 RV_NOFUNC = -1; +static bool IsOwnScriptFunction( JSContext *cx, JS::HandleObject scriptObject, const char *functionName ) +{ + if( functionName == nullptr ) + return false; + + bool hasOwnProperty = false; + if( !JS_HasOwnProperty( cx, scriptObject, functionName, &hasOwnProperty ) || !hasOwnProperty ) + return false; + + JS::RootedValue functionValue( cx ); + if( !JS_GetProperty( cx, scriptObject, functionName, &functionValue )) + return false; + + return functionValue.isObject() && JS::IsCallable( &functionValue.toObject() ); +} + //o------------------------------------------------------------------------------------------------o //| File - cScript.cpp //| Date - August 26th, 2000 @@ -519,11 +537,14 @@ void cScript::Stop( void ) bool cScript::InvokeEvent( const char* name, unsigned int argc, const JS::Value* argv, JS::Value* rval ) { + JS::RootedObject rootedObj( targContext, targObject ); + if( !IsOwnScriptFunction( targContext, rootedObj, name )) + return false; + CActiveScriptGuard activeScriptGuard( JSMapping, this ); #if defined UOX_DEBUG_MODE Console.Log( oldstrutil::format( "Triggering event '%s' from script %d", name, GetScriptID() ) ); #endif - JS::RootedObject rootedObj( targContext, targObject ); JS::RootedValueVector rootedArgs( targContext ); if( argc > 0 && !rootedArgs.append( argv, argc )) { @@ -617,13 +638,8 @@ bool cScript::OnStop( void ) //o------------------------------------------------------------------------------------------------o bool cScript::DoesEventExist( const char *eventToFind ) { - JS::RootedValue Func( targContext, JS::NullValue() ); - JS_GetProperty( targContext, targObject, eventToFind, &Func ); - if( Func == JS::UndefinedValue() ) - { - return false; - } - return true; + JS::RootedObject scriptObject( targContext, targObject ); + return IsOwnScriptFunction( targContext, scriptObject, eventToFind ); } //o------------------------------------------------------------------------------------------------o @@ -3970,9 +3986,8 @@ bool cScript::ExistAndVerify( ScriptEvent eventNum, std::string functionName ) if( NeedsChecking( eventNum )) { SetNeedsChecking( eventNum, false ); - JS::RootedValue Func( targContext, JS::NullValue() ); - JS_GetProperty( targContext, targObject, functionName.c_str(), &Func ); - if( Func == JS::UndefinedValue() ) + JS::RootedObject scriptObject( targContext, targObject ); + if( !IsOwnScriptFunction( targContext, scriptObject, functionName.c_str() )) { SetEventExists( eventNum, false ); return false; @@ -3996,9 +4011,8 @@ bool cScript::ScriptRegistration( std::string scriptType ) JS::RootedValue rval( targContext ); // ExistAndVerify() normally sets our Global Object, but not on custom named functions. - JS::RootedValue Func( targContext, JS::NullValue() ); - JS_GetProperty( targContext, targObject, scriptType.c_str(), &Func ); - if( Func == JS::UndefinedValue() ) + JS::RootedObject scriptObject( targContext, targObject ); + if( !IsOwnScriptFunction( targContext, scriptObject, scriptType.c_str() )) { Console.Warning( oldstrutil::format( "Script Number (%u) does not have a %s function", JSMapping->GetScriptId( targObject ), scriptType.c_str() )); return false; diff --git a/source/uox3.cpp b/source/uox3.cpp index 22311ae7c..6cb3a3679 100644 --- a/source/uox3.cpp +++ b/source/uox3.cpp @@ -3400,6 +3400,15 @@ auto Shutdown( SI32 retCode ) -> void cons.join(); } + if( JSMapping != nullptr ) + { + JSMapping->Shutdown(); + } + if( JSEngine != nullptr ) + { + JSEngine->Shutdown(); + } + // don't leave file pointers open, could lead to file corruption Console.PrintSectionBegin();