From 079fe1577a16fc7ef623c634f3092902c7175609 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sat, 8 Aug 2026 13:16:13 -0500 Subject: [PATCH] Improved SpiderMonkey startup validation Improved SpiderMonkey startup validation so UOX3 cannot continue with an incomplete JavaScript environment. UOX3 now checks context creation, standard classes, prototypes, global objects, skill wrappers, and property registration. If any required step fails, the server reports the problem and stops cleanly instead of silently loading partial bindings. This also resolves the ignored JS_DefineProperty() compiler warning. Normal JavaScript behavior remains unchanged. --- source/CJSEngine.cpp | 59 +++++++++++++++++++++++++++++++++++++------- source/CJSEngine.h | 2 +- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/source/CJSEngine.cpp b/source/CJSEngine.cpp index eb5604714..716d9f5be 100644 --- a/source/CJSEngine.cpp +++ b/source/CJSEngine.cpp @@ -186,11 +186,20 @@ void CJSEngine::ReleaseObject( IUEEntries iType, void *index ) //====================================================================================================== CJSRuntime::CJSRuntime( UI32 engineSize ) { - JS::RealmOptions options; + JS::RealmOptions options; realmGuard = nullptr; jsContext = JS_NewContext( engineSize ); + if( jsContext == nullptr ) + { + Console.Error( "Unable to create JavaScript context" ); + Shutdown( FATAL_UOX3_JAVASCRIPT ); + } - JS::InitSelfHostedCode(jsContext); + if( !JS::InitSelfHostedCode( jsContext )) + { + Console.Error( "Unable to initialize JavaScript self-hosted code" ); + Shutdown( FATAL_UOX3_JAVASCRIPT ); + } JS::RootedObject rootedGlobal( jsContext, JS_NewGlobalObject( jsContext, &global_class, nullptr, JS::FireOnNewGlobalHook, options )); if( rootedGlobal == nullptr ) @@ -199,9 +208,17 @@ CJSRuntime::CJSRuntime( UI32 engineSize ) } jsGlobal.init( jsContext, rootedGlobal ); realmGuard = new JSAutoRealm( jsContext, jsGlobal ); - JS::InitRealmStandardClasses( jsContext ); + if( !JS::InitRealmStandardClasses( jsContext )) + { + Console.Error( "Unable to initialize standard JavaScript classes" ); + Shutdown( FATAL_UOX3_JAVASCRIPT ); + } - InitializePrototypes(); + if( !InitializePrototypes() ) + { + Console.Error( "Unable to initialize JavaScript classes and global objects" ); + Shutdown( FATAL_UOX3_JAVASCRIPT ); + } JS::SetWarningReporter( jsContext, UOX3EngineWarningReporter ); } @@ -319,17 +336,26 @@ bool ResolveCreateEntryCollection( JSContext *cx, JS::HandleObject obj, JS::Hand } -void CJSRuntime::InitializePrototypes() +bool CJSRuntime::InitializePrototypes() { JSContext *cx = jsContext; JS::RootedObject obj(jsContext, jsGlobal); protoList = new JS::RootedObjectVector( cx ); - protoList->resize( JSP_COUNT ); + if( !protoList->resize( JSP_COUNT )) + { + return false; + } (*protoList)[JSP_BASE] .set( rootClass( cx, obj, &UOXBase_class, nullptr, CBaseObjectProps, CBaseObject_Methods ) ); + if(( *protoList )[JSP_BASE] == nullptr ) + return false; (*protoList)[JSP_CHAR] .set( rootInheritedClass( cx, obj, &UOXChar_class, nullptr, CCharacterProps, CChar_Methods, (*protoList)[JSP_BASE] ) ); + if(( *protoList )[JSP_CHAR] == nullptr ) + return false; (*protoList)[JSP_ITEM] .set( rootInheritedClass( cx, obj, &UOXItem_class, nullptr, CItemProps, CItem_Methods, (*protoList)[JSP_BASE] ) ); + if(( *protoList )[JSP_ITEM] == nullptr ) + return false; (*protoList)[JSP_SPELL] .set( rootClass( cx, obj, &UOXSpell_class, nullptr, CSpellProperties, nullptr ) ); (*protoList)[JSP_SPELLS] .set( rootClass( cx, obj, &UOXSpells_class, nullptr, nullptr, nullptr ) ); (*protoList)[JSP_GLOBALSKILL] .set( rootClass( cx, obj, &UOXGlobalSkill_class, nullptr, CGlobalSkillProperties, nullptr ) ); @@ -351,6 +377,11 @@ void CJSRuntime::InitializePrototypes() (*protoList)[JSP_GUMP] .set( rootClass( cx, obj, &UOXGump_class, Gump, nullptr, nullptr ) ); (*protoList)[JSP_FILE] .set( rootClass( cx, obj, &UOXFile_class, UOXCFile, nullptr, nullptr ) ); (*protoList)[JSP_SCRIPT] .set( rootClass( cx, obj, &uox_class, nullptr, CScriptProperties, nullptr ) ); + for( size_t i = JSP_SPELL; i < JSP_COUNT; ++i ) + { + if(( *protoList )[i] == nullptr ) + return false; + } JS::RootedObject spellsObj( cx, defineSingleton( cx, obj, "Spells", &UOXSpells_class, ( *protoList )[JSP_SPELLS] ) ); JS::RootedObject skillsObj( cx, defineSingleton( cx, obj, "Skills", &UOXGlobalSkills_class, ( *protoList )[JSP_GLOBALSKILLS] ) ); JS::RootedObject accountsObj( cx, defineSingleton( cx, obj, "Accounts", &UOXAccount_class, ( *protoList )[JSP_ACCOUNTS] ) ); @@ -358,6 +389,12 @@ void CJSRuntime::InitializePrototypes() JS::RootedObject createEntriesObj( cx, defineSingleton( cx, obj, "CreateEntries", &UOXCreateEntries_class, ( *protoList )[JSP_CREATEENTRIES] ) ); JS::RootedObject timerObj( cx, defineSingleton( cx, obj, "Timer", &UOXTimer_class, ( *protoList )[JSP_TIMER] ) ); JS::RootedObject scriptObj( cx, defineSingleton( cx, obj, "SCRIPT", &uox_class, ( *protoList )[JSP_SCRIPT] ) ); + if( spellsObj == nullptr || skillsObj == nullptr || accountsObj == nullptr || + consoleObj == nullptr || createEntriesObj == nullptr || timerObj == nullptr || + scriptObj == nullptr ) + { + return false; + } // clang-format on JS::RootedObject skillsCollection( cx, skillsObj ); @@ -367,14 +404,18 @@ void CJSRuntime::InitializePrototypes() JS::RootedObject skillObject( cx, JS_NewObjectWithGivenProto( cx, &UOXGlobalSkill_class, skillPrototype )); if( skillObject == nullptr ) - continue; + return false; JS_SetReservedSlot( skillObject, 0, JS::PrivateValue( &cwmWorldState->skill[skillId] )); std::string propertyName = std::to_string( skillId ); - JS_DefineProperty( cx, skillsCollection, propertyName.c_str(), skillObject, - JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT ); + if( !JS_DefineProperty( cx, skillsCollection, propertyName.c_str(), skillObject, + JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT )) + { + return false; + } } + return true; } JSRuntime *CJSRuntime::GetRuntime( void ) const diff --git a/source/CJSEngine.h b/source/CJSEngine.h index 610e0c1c6..20abbbd9b 100644 --- a/source/CJSEngine.h +++ b/source/CJSEngine.h @@ -67,7 +67,7 @@ class CJSRuntime JSObject * MakeNewObject( IUEEntries iType ); void Cleanup( void ); - void InitializePrototypes( void ); + bool InitializePrototypes( void ); public: CJSRuntime(); CJSRuntime( UI32 engineSize );