From 5bbec8bdd9bd67a22b266c482cdd42529318e801 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 3 Apr 2024 18:30:57 +0200 Subject: [PATCH] VScript: properly implement 'sq_getstring' and 'sq_getinteger' + more sq_getstring and sq_getinteger are now properly implemented (code matches squirrel code, and generated assembly matches that of the game). Adjusted call sites to accommodate the new implementation and added a few extra checks. Also added: * sq_getfloat * sq_getbool * sq_getthread --- src/game/client/vscript_client.cpp | 91 +++++++++++++------ src/game/server/liveapi/liveapi.cpp | 11 ++- src/game/server/vscript_server.cpp | 84 +++++++++++++---- .../languages/squirrel_re/include/sqobject.h | 4 +- .../languages/squirrel_re/include/squirrel.h | 8 +- .../languages/squirrel_re/include/sqvm.h | 4 +- .../languages/squirrel_re/squirrel/sqapi.cpp | 48 ++++++++-- .../squirrel_re/squirrel/sqdebug.cpp | 2 +- 8 files changed, 190 insertions(+), 62 deletions(-) diff --git a/src/game/client/vscript_client.cpp b/src/game/client/vscript_client.cpp index 4d8de6b3..81e451b8 100644 --- a/src/game/client/vscript_client.cpp +++ b/src/game/client/vscript_client.cpp @@ -60,7 +60,7 @@ static ConCommand script_ui("script_ui", SQVM_UIScript_f, "Run input code as UI //----------------------------------------------------------------------------- // Purpose: checks if the server index is valid, raises an error if not //----------------------------------------------------------------------------- -static SQBool Script_CheckServerIndex(HSQUIRRELVM v, SQInteger iServer) +static SQBool Script_CheckServerIndexAndFailure(HSQUIRRELVM v, SQInteger iServer) { SQInteger iCount = static_cast(g_ServerListManager.m_vServerList.size()); @@ -69,6 +69,11 @@ static SQBool Script_CheckServerIndex(HSQUIRRELVM v, SQInteger iServer) v_SQVM_RaiseError(v, "Index must be less than %i.\n", iCount); return false; } + else if (iServer == -1) // If its still -1, then 'sq_getinteger' failed + { + v_SQVM_RaiseError(v, "Invalid argument type provided.\n"); + return false; + } return true; } @@ -108,10 +113,13 @@ namespace VScriptCode //----------------------------------------------------------------------------- SQRESULT GetHiddenServerName(HSQUIRRELVM v) { - SQChar* privateToken = sq_getstring(v, 1); + const SQChar* privateToken = nullptr; - if (!VALID_CHARSTAR(privateToken)) - SCRIPT_CHECK_AND_RETURN(v, SQ_OK); + if (SQ_FAILED(sq_getstring(v, 2, &privateToken)) || VALID_CHARSTAR(privateToken)) + { + v_SQVM_ScriptError("Empty or null private token"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } string hiddenServerRequestMessage; NetGameServer_t serverListing; @@ -154,9 +162,11 @@ namespace VScriptCode SQRESULT GetServerName(HSQUIRRELVM v) { AUTO_LOCK(g_ServerListManager.m_Mutex); - SQInteger iServer = sq_getinteger(v, 1); - if (!Script_CheckServerIndex(v, iServer)) + SQInteger iServer = -1; + sq_getinteger(v, 2, &iServer); + + if (!Script_CheckServerIndexAndFailure(v, iServer)) SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); const string& serverName = g_ServerListManager.m_vServerList[iServer].name; @@ -171,9 +181,11 @@ namespace VScriptCode SQRESULT GetServerDescription(HSQUIRRELVM v) { AUTO_LOCK(g_ServerListManager.m_Mutex); - SQInteger iServer = sq_getinteger(v, 1); - if (!Script_CheckServerIndex(v, iServer)) + SQInteger iServer = -1; + sq_getinteger(v, 2, &iServer); + + if (!Script_CheckServerIndexAndFailure(v, iServer)) SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); const string& serverDescription = g_ServerListManager.m_vServerList[iServer].description; @@ -188,9 +200,11 @@ namespace VScriptCode SQRESULT GetServerMap(HSQUIRRELVM v) { AUTO_LOCK(g_ServerListManager.m_Mutex); - SQInteger iServer = sq_getinteger(v, 1); - if (!Script_CheckServerIndex(v, iServer)) + SQInteger iServer = -1; + sq_getinteger(v, 2, &iServer); + + if (!Script_CheckServerIndexAndFailure(v, iServer)) SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); const string& svServerMapName = g_ServerListManager.m_vServerList[iServer].map; @@ -205,9 +219,11 @@ namespace VScriptCode SQRESULT GetServerPlaylist(HSQUIRRELVM v) { AUTO_LOCK(g_ServerListManager.m_Mutex); - SQInteger iServer = sq_getinteger(v, 1); - if (!Script_CheckServerIndex(v, iServer)) + SQInteger iServer = -1; + sq_getinteger(v, 2, &iServer); + + if (!Script_CheckServerIndexAndFailure(v, iServer)) SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); const string& serverPlaylist = g_ServerListManager.m_vServerList[iServer].playlist; @@ -222,9 +238,11 @@ namespace VScriptCode SQRESULT GetServerCurrentPlayers(HSQUIRRELVM v) { AUTO_LOCK(g_ServerListManager.m_Mutex); - SQInteger iServer = sq_getinteger(v, 1); - if (!Script_CheckServerIndex(v, iServer)) + SQInteger iServer = -1; + sq_getinteger(v, 2, &iServer); + + if (!Script_CheckServerIndexAndFailure(v, iServer)) SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); const SQInteger playerCount = g_ServerListManager.m_vServerList[iServer].numPlayers; @@ -239,9 +257,11 @@ namespace VScriptCode SQRESULT GetServerMaxPlayers(HSQUIRRELVM v) { AUTO_LOCK(g_ServerListManager.m_Mutex); - SQInteger iServer = sq_getinteger(v, 1); - if (!Script_CheckServerIndex(v, iServer)) + SQInteger iServer = -1; + sq_getinteger(v, 2, &iServer); + + if (!Script_CheckServerIndexAndFailure(v, iServer)) SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); const SQInteger maxPlayers = g_ServerListManager.m_vServerList[iServer].maxPlayers; @@ -265,7 +285,10 @@ namespace VScriptCode PromoRightDesc }; - R5RPromoData ePromoIndex = static_cast(sq_getinteger(v, 1)); + SQInteger idx = 0; + sq_getinteger(v, 2, &idx); + + R5RPromoData ePromoIndex = static_cast(idx); const char* pszPromoKey; switch (ePromoIndex) @@ -339,11 +362,19 @@ namespace VScriptCode //----------------------------------------------------------------------------- SQRESULT ConnectToServer(HSQUIRRELVM v) { - SQChar* ipAddress = sq_getstring(v, 1); - SQChar* cryptoKey = sq_getstring(v, 2); + const SQChar* ipAddress = nullptr; + if (SQ_FAILED(sq_getstring(v, 2, &ipAddress))) + { + v_SQVM_ScriptError("Missing ip address"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } - if (!VALID_CHARSTAR(ipAddress) || VALID_CHARSTAR(cryptoKey)) - SCRIPT_CHECK_AND_RETURN(v, SQ_OK); + const SQChar* cryptoKey = nullptr; + if (SQ_FAILED(sq_getstring(v, 3, &cryptoKey))) + { + v_SQVM_ScriptError("Missing encryption key"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } Msg(eDLL_T::UI, "Connecting to server with ip address '%s' and encryption key '%s'\n", ipAddress, cryptoKey); g_ServerListManager.ConnectToServer(ipAddress, cryptoKey); @@ -357,9 +388,11 @@ namespace VScriptCode SQRESULT ConnectToListedServer(HSQUIRRELVM v) { AUTO_LOCK(g_ServerListManager.m_Mutex); - SQInteger iServer = sq_getinteger(v, 1); - if (!Script_CheckServerIndex(v, iServer)) + SQInteger iServer = -1; + sq_getinteger(v, 2, &iServer); + + if (!Script_CheckServerIndexAndFailure(v, iServer)) { SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); } @@ -377,15 +410,19 @@ namespace VScriptCode //----------------------------------------------------------------------------- SQRESULT ConnectToHiddenServer(HSQUIRRELVM v) { - SQChar* privateToken = sq_getstring(v, 1); + const SQChar* privateToken = nullptr; + const SQRESULT strRet = sq_getstring(v, 2, &privateToken); - if (!VALID_CHARSTAR(privateToken)) - SCRIPT_CHECK_AND_RETURN(v, SQ_OK); + if (SQ_FAILED(strRet) || VALID_CHARSTAR(privateToken)) + { + v_SQVM_ScriptError("Empty or null private token"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } string hiddenServerRequestMessage; NetGameServer_t netListing; - bool result = g_MasterServer.GetServerByToken(netListing, hiddenServerRequestMessage, privateToken); // Send token connect request. + const bool result = g_MasterServer.GetServerByToken(netListing, hiddenServerRequestMessage, privateToken); // Send token connect request. if (result) { g_ServerListManager.ConnectToServer(netListing.address, netListing.port, netListing.netKey); diff --git a/src/game/server/liveapi/liveapi.cpp b/src/game/server/liveapi/liveapi.cpp index 73c517b6..524df754 100644 --- a/src/game/server/liveapi/liveapi.cpp +++ b/src/game/server/liveapi/liveapi.cpp @@ -2178,10 +2178,15 @@ SQRESULT VScriptCode::Server::LiveAPI_LogRaw(HSQUIRRELVM v) if (sq_istable(object)) { - const SQTable* const table = object._unVal.pTable; - const eLiveAPI_EventTypes eventType = eLiveAPI_EventTypes(sq_getinteger(v, 2)); + const SQTable* const table = _table(object); + SQInteger eventType = 0; - if (!LiveAPI_HandleEventByCategory(v, table, eventType)) + if (SQ_FAILED(sq_getinteger(v, 3, &eventType))) + { + v_SQVM_ScriptError("Second argument must be an integer."); + result = SQ_FAIL; + } + else if (!LiveAPI_HandleEventByCategory(v, table, eLiveAPI_EventTypes(eventType))) result = SQ_ERROR; } else diff --git a/src/game/server/vscript_server.cpp b/src/game/server/vscript_server.cpp index e06d060a..2123d4d7 100644 --- a/src/game/server/vscript_server.cpp +++ b/src/game/server/vscript_server.cpp @@ -48,17 +48,25 @@ namespace VScriptCode //----------------------------------------------------------------------------- SQRESULT CreateServer(HSQUIRRELVM v) { - SQChar* serverName = sq_getstring(v, 1); - SQChar* serverDescription = sq_getstring(v, 2); - SQChar* serverMapName = sq_getstring(v, 3); - SQChar* serverPlaylist = sq_getstring(v, 4); - ServerVisibility_e serverVisibility = static_cast(sq_getinteger(v, 5)); + const SQChar* serverName = nullptr; + const SQChar* serverDescription = nullptr; + const SQChar* serverMapName = nullptr; + const SQChar* serverPlaylist = nullptr; + + sq_getstring(v, 2, &serverName); + sq_getstring(v, 3, &serverDescription); + sq_getstring(v, 4, &serverMapName); + sq_getstring(v, 5, &serverPlaylist); + + SQInteger serverVisibility = 0; + sq_getinteger(v, 6, &serverVisibility); if (!VALID_CHARSTAR(serverName) || !VALID_CHARSTAR(serverMapName) || !VALID_CHARSTAR(serverPlaylist)) { - SCRIPT_CHECK_AND_RETURN(v, SQ_OK); + v_SQVM_ScriptError("Empty or null server criteria"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); } // Adjust browser settings. @@ -70,7 +78,7 @@ namespace VScriptCode details.playlist = serverPlaylist; // Launch server. - g_ServerHostManager.SetVisibility(serverVisibility); + g_ServerHostManager.SetVisibility(ServerVisibility_e(serverVisibility)); g_ServerHostManager.LaunchServer(g_pServer->IsActive()); SCRIPT_CHECK_AND_RETURN(v, SQ_OK); @@ -91,8 +99,17 @@ namespace VScriptCode //----------------------------------------------------------------------------- SQRESULT KickPlayerByName(HSQUIRRELVM v) { - SQChar* playerName = sq_getstring(v, 1); - SQChar* reason = sq_getstring(v, 2); + const SQChar* playerName = nullptr; + const SQChar* reason = nullptr; + + sq_getstring(v, 2, &playerName); + sq_getstring(v, 3, &reason); + + if (!VALID_CHARSTAR(playerName)) + { + v_SQVM_ScriptError("Empty or null player name"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } // Discard empty strings, this will use the default message instead. if (!VALID_CHARSTAR(reason)) @@ -107,8 +124,17 @@ namespace VScriptCode //----------------------------------------------------------------------------- SQRESULT KickPlayerById(HSQUIRRELVM v) { - SQChar* playerHandle = sq_getstring(v, 1); - SQChar* reason = sq_getstring(v, 2); + const SQChar* playerHandle = nullptr; + const SQChar* reason = nullptr; + + sq_getstring(v, 2, &playerHandle); + sq_getstring(v, 3, &reason); + + if (!VALID_CHARSTAR(playerHandle)) + { + v_SQVM_ScriptError("Empty or null player handle"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } // Discard empty strings, this will use the default message instead. if (!VALID_CHARSTAR(reason)) @@ -123,8 +149,17 @@ namespace VScriptCode //----------------------------------------------------------------------------- SQRESULT BanPlayerByName(HSQUIRRELVM v) { - SQChar* playerName = sq_getstring(v, 1); - SQChar* reason = sq_getstring(v, 2); + const SQChar* playerName = nullptr; + const SQChar* reason = nullptr; + + sq_getstring(v, 2, &playerName); + sq_getstring(v, 3, &reason); + + if (!VALID_CHARSTAR(playerName)) + { + v_SQVM_ScriptError("Empty or null player name"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } // Discard empty strings, this will use the default message instead. if (!VALID_CHARSTAR(reason)) @@ -139,8 +174,17 @@ namespace VScriptCode //----------------------------------------------------------------------------- SQRESULT BanPlayerById(HSQUIRRELVM v) { - SQChar* playerHandle = sq_getstring(v, 1); - SQChar* reason = sq_getstring(v, 2); + const SQChar* playerHandle = nullptr; + const SQChar* reason = nullptr; + + sq_getstring(v, 2, &playerHandle); + sq_getstring(v, 3, &reason); + + if (!VALID_CHARSTAR(playerHandle)) + { + v_SQVM_ScriptError("Empty or null player handle"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } // Discard empty strings, this will use the default message instead. if (!VALID_CHARSTAR(reason)) @@ -155,7 +199,15 @@ namespace VScriptCode //----------------------------------------------------------------------------- SQRESULT UnbanPlayer(HSQUIRRELVM v) { - SQChar* szCriteria = sq_getstring(v, 1); + const SQChar* szCriteria = nullptr; + sq_getstring(v, 2, &szCriteria); + + if (!VALID_CHARSTAR(szCriteria)) + { + v_SQVM_ScriptError("Empty or null player criteria"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } + g_BanSystem.UnbanPlayer(szCriteria); SCRIPT_CHECK_AND_RETURN(v, SQ_OK); diff --git a/src/vscript/languages/squirrel_re/include/sqobject.h b/src/vscript/languages/squirrel_re/include/sqobject.h index 4385f0bc..c9c2498a 100644 --- a/src/vscript/languages/squirrel_re/include/sqobject.h +++ b/src/vscript/languages/squirrel_re/include/sqobject.h @@ -93,8 +93,8 @@ struct SQWeakRef : SQRefCounted #define _stringval(obj) (obj)._unVal.pString->_val #define _userdataval(obj) (obj)._unVal.pUserData->_val -#define tofloat(num) ((type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num)) -#define tointeger(num) ((type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num)) +#define tofloat(num) ((sq_type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num)) +#define tointeger(num) ((sq_type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num)) ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// struct SQObjectPtr : public SQObject diff --git a/src/vscript/languages/squirrel_re/include/squirrel.h b/src/vscript/languages/squirrel_re/include/squirrel.h index 7e650d4c..6b5c5b64 100644 --- a/src/vscript/languages/squirrel_re/include/squirrel.h +++ b/src/vscript/languages/squirrel_re/include/squirrel.h @@ -163,8 +163,11 @@ typedef struct tagSQObject /////////////////////////////////////////////////////////////////////////////// SQRESULT sq_pushroottable(HSQUIRRELVM v); -SQChar* sq_getstring(HSQUIRRELVM v, SQInteger i); -SQInteger sq_getinteger(HSQUIRRELVM v, SQInteger i); +SQRESULT sq_getinteger(HSQUIRRELVM v, SQInteger idx, SQInteger* i); +SQRESULT sq_getfloat(HSQUIRRELVM v, SQInteger idx, SQFloat* f); +SQRESULT sq_getbool(HSQUIRRELVM v, SQInteger idx, SQBool* b); +SQRESULT sq_getthread(HSQUIRRELVM v, SQInteger idx, HSQUIRRELVM* thread); +SQRESULT sq_getstring(HSQUIRRELVM v, SQInteger idx, const SQChar** c); SQRESULT sq_get(HSQUIRRELVM v, SQInteger idx); SQInteger sq_gettop(HSQUIRRELVM v); SQRESULT sq_pushroottable(HSQUIRRELVM v); @@ -184,6 +187,7 @@ SQRESULT sq_startconsttable(HSQUIRRELVM v); SQRESULT sq_endconsttable(HSQUIRRELVM v); /*UTILITY MACRO*/ +#define sq_isnumeric(o) ((o)._type&SQOBJECT_NUMERIC) #define sq_istable(o) ((o)._type==OT_TABLE) #define sq_isarray(o) ((o)._type==OT_ARRAY) #define sq_isfunction(o) ((o)._type==OT_FUNCPROTO) diff --git a/src/vscript/languages/squirrel_re/include/sqvm.h b/src/vscript/languages/squirrel_re/include/sqvm.h index 9d38afa9..7f82b708 100644 --- a/src/vscript/languages/squirrel_re/include/sqvm.h +++ b/src/vscript/languages/squirrel_re/include/sqvm.h @@ -18,7 +18,7 @@ enum class SQCONTEXT : SQInteger struct SQVM : public CHAINABLE_OBJ { - void PrintObjVal(const SQObject& oin, SQObject& oout); + void PrintObjVal(const SQObject* oin, SQObject* oout); // push sqobjectptr on to the stack void Push(const SQObjectPtr& o); @@ -69,7 +69,7 @@ inline void(*v_SQVM_CompileError)(HSQUIRRELVM v, const SQChar* pszError, const S inline void(*v_SQVM_LogicError)(SQBool bPrompt); inline SQInteger(*v_SQVM_ScriptError)(const SQChar* pszFormat, ...); inline SQInteger(*v_SQVM_RaiseError)(HSQUIRRELVM v, const SQChar* pszFormat, ...); -inline void(*v_SQVM_PrintObjVal)(HSQUIRRELVM v, const SQObjectPtr& oin, const SQObjectPtr& oout); +inline void(*v_SQVM_PrintObjVal)(HSQUIRRELVM v, const SQObject* oin, SQObject* oout); SQRESULT SQVM_PrintFunc(HSQUIRRELVM v, SQChar* fmt, ...); SQRESULT SQVM_sprintf(HSQUIRRELVM v, SQInteger a2, SQInteger a3, SQInteger* nStringSize, SQChar** ppString); diff --git a/src/vscript/languages/squirrel_re/squirrel/sqapi.cpp b/src/vscript/languages/squirrel_re/squirrel/sqapi.cpp index fafb1b54..707df29f 100644 --- a/src/vscript/languages/squirrel_re/squirrel/sqapi.cpp +++ b/src/vscript/languages/squirrel_re/squirrel/sqapi.cpp @@ -16,7 +16,7 @@ bool sq_aux_gettypedarg(HSQUIRRELVM v, SQInteger idx, SQObjectType type, SQObjec *o = &stack_get(v, idx); if (sq_type(**o) != type) { SQObjectPtr oval; - v->PrintObjVal(**o, oval); + v->PrintObjVal(*o, &oval); v_SQVM_RaiseError(v, _SC("wrong argument type, expected '%s' got '%.50s'"), IdType2Name(type), _stringval(oval)); return false; } @@ -32,9 +32,45 @@ bool sq_aux_gettypedarg(HSQUIRRELVM v, SQInteger idx, SQObjectType type, SQObjec } //--------------------------------------------------------------------------------- -SQChar* sq_getstring(HSQUIRRELVM v, SQInteger i) // TODO: deprecate and remove! +SQRESULT sq_getinteger(HSQUIRRELVM v, SQInteger idx, SQInteger* i) { - return v->_stackbase[i]._unVal.pString->_val; + SQObjectPtr& o = stack_get(v, idx); + if (sq_isnumeric(o)) { + *i = tointeger(o); + return SQ_OK; + } + return SQ_ERROR; +} + +//--------------------------------------------------------------------------------- +SQRESULT sq_getfloat(HSQUIRRELVM v, SQInteger idx, SQFloat* f) +{ + SQObjectPtr& o = stack_get(v, idx); + if (sq_isnumeric(o)) { + *f = tofloat(o); + return SQ_OK; + } + return SQ_ERROR; +} + +//--------------------------------------------------------------------------------- +SQRESULT sq_getbool(HSQUIRRELVM v, SQInteger idx, SQBool* b) +{ + SQObjectPtr& o = stack_get(v, idx); + if (sq_isbool(o)) { + *b = _integer(o); + return SQ_OK; + } + return SQ_ERROR; +} + +//--------------------------------------------------------------------------------- +SQRESULT sq_getthread(HSQUIRRELVM v, SQInteger idx, HSQUIRRELVM* thread) +{ + SQObjectPtr* o = NULL; + _GETSAFE_OBJ(v, idx, OT_THREAD, o); + *thread = _thread(*o); + return SQ_OK; } //--------------------------------------------------------------------------------- @@ -46,12 +82,6 @@ SQRESULT sq_getstring(HSQUIRRELVM v, SQInteger idx, const SQChar** c) return SQ_OK; } -//--------------------------------------------------------------------------------- -SQInteger sq_getinteger(HSQUIRRELVM v, SQInteger i) -{ - return v->_stackbase[i]._unVal.nInteger; -} - //--------------------------------------------------------------------------------- SQRESULT sq_get(HSQUIRRELVM v, SQInteger idx) { diff --git a/src/vscript/languages/squirrel_re/squirrel/sqdebug.cpp b/src/vscript/languages/squirrel_re/squirrel/sqdebug.cpp index de368561..e68caa3b 100644 --- a/src/vscript/languages/squirrel_re/squirrel/sqdebug.cpp +++ b/src/vscript/languages/squirrel_re/squirrel/sqdebug.cpp @@ -4,7 +4,7 @@ #include "sqvm.h" #include "sqstring.h" -void SQVM::PrintObjVal(const SQObject& oin, SQObject& oout) +void SQVM::PrintObjVal(const SQObject* oin, SQObject* oout) { v_SQVM_PrintObjVal(this, oin, oout); }