From a59316354482ee89687a95d238ee0078ae006a6d Mon Sep 17 00:00:00 2001 From: darkdreamingdan Date: Fri, 12 Aug 2016 21:56:55 +0100 Subject: [PATCH 01/10] Reimplemented Lua packages in C++ Similar design to before, but in C++: use require, and package.loaded is enabled. Pure Lua modules must be placed correctly in either: /?.lua /?/init.lua Lua C Modules must be placed in: /server/mods/deathmatch/modules/?.dll To easily test or use modules for Windows: Download and install Lua for Windows. Copy contents of C:\Program Files (x86)\Lua\5.1\clibs into /server/mods/deathmatch/modules. Use e.g. require"lfs" To-do: * Port over to clientside (without C module support) * More detailed error messages for Pure lua packages * ACL support for C modules. * Extensive testing --- Server/mods/deathmatch/logic/lua/CLuaMain.cpp | 169 +++++++++++++++++- Server/mods/deathmatch/logic/lua/CLuaMain.h | 8 +- .../deathmatch/logic/luadefs/CLuaUtilDefs.cpp | 38 ++++ .../deathmatch/logic/luadefs/CLuaUtilDefs.h | 3 + vendor/lua/src/lauxlib.h | 5 + vendor/lua/src/loadlib.c | 12 ++ 6 files changed, 231 insertions(+), 4 deletions(-) diff --git a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp index 43c23bf7348..fe083103cd9 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp @@ -126,7 +126,6 @@ void CLuaMain::InitSecurity ( void ) { lua_register ( m_luaVM, "dofile", CLuaUtilDefs::DisabledFunction ); lua_register ( m_luaVM, "loadfile", CLuaUtilDefs::DisabledFunction ); - lua_register ( m_luaVM, "require", CLuaUtilDefs::DisabledFunction ); lua_register ( m_luaVM, "loadlib", CLuaUtilDefs::DisabledFunction ); lua_register ( m_luaVM, "getfenv", CLuaUtilDefs::DisabledFunction ); lua_register ( m_luaVM, "newproxy", CLuaUtilDefs::DisabledFunction ); @@ -192,6 +191,9 @@ void CLuaMain::InitVM ( void ) luaopen_debug ( m_luaVM ); luaopen_utf8 ( m_luaVM ); + // Initialize packages system + InitPackageStorage(m_luaVM); + // Initialize security restrictions. Very important to prevent lua trojans and viruses! InitSecurity (); @@ -250,7 +252,7 @@ void CLuaMain::InstructionCountHook ( lua_State* luaVM, lua_Debug* pDebug ) } -bool CLuaMain::LoadScriptFromBuffer ( const char* cpInBuffer, unsigned int uiInSize, const char* szFileName ) +bool CLuaMain::LoadScriptFromBuffer(const char* cpInBuffer, unsigned int uiInSize, const char* szFileName, bool bClearReturnValues ) { SString strNiceFilename = ConformResourcePath( szFileName ); @@ -320,7 +322,7 @@ bool CLuaMain::LoadScriptFromBuffer ( const char* cpInBuffer, unsigned int uiInS g_pGame->GetScriptDebugging()->LogPCallError( m_luaVM, strRes, true ); } // Cleanup any return values - if ( lua_gettop ( m_luaVM ) > luaSavedTop ) + if ( bClearReturnValues && lua_gettop ( m_luaVM ) > luaSavedTop ) lua_settop( m_luaVM, luaSavedTop ); return true; } @@ -686,3 +688,164 @@ int CLuaMain::OnUndump( const char* p, size_t n ) } return 1; } + + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::InitPackageStorage +// +// Create a table for storage of Lua packages - stored in the Lua VM +// +/////////////////////////////////////////////////////////////// +void CLuaMain::InitPackageStorage(lua_State* L) +{ + lua_newtable(L); // stack: [tbl_new] + lua_pushstring(L, "loaded"); // stack: [tbl_new,"loaded"] + lua_newtable(L); // stack: [tbl_new,"loaded",tbl_new2] + + // We push our default Lua libs are loaded packages + std::vector szDefaultLibs = { "math", "string", "table", "debug", "utf8" }; + for (auto it : szDefaultLibs) + { + lua_pushstring(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math"] + lua_getglobal(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math",_G.math] + lua_settable(L, -3); // stack: [tbl_new,"loaded",tbl_new2] + } + + // Finally, store our original table as package.loaded + lua_settable(L, -3); // stack: [tbl_new] + lua_setglobal(L, "package"); // stack: [] +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::SetPackage +// +// Pop the top most value as a package +// +/////////////////////////////////////////////////////////////// +void CLuaMain::SetPackage(lua_State* L, SString &strName ) +{ + // We set varPkg, which is already on the stack, into package.loaded.moduleName = varPkg. + // stack: [varPkg] + int iPkg = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [] + lua_getglobal(L, "package"); // stack: [tbl_package] + if (lua_type(L, -1) == LUA_TNIL ) + InitPackageStorage(L); + + lua_pushstring(L, "loaded"); // stack: [tbl_package,"loaded"] + lua_rawget(L, -2); // stack: [tbl_package,tbl_loaded] + if (lua_type(L, -1) == LUA_TNIL) + InitPackageStorage(L); + + + lua_pushstring(L, strName.c_str()); // stack: [tbl_package,tbl_loaded,"moduleName"] + lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [tbl_package,tbl_loaded,"moduleName",varPkg] + lua_rawset(L, -3); // stack: [tbl_package,tbl_loaded] + lua_pop(L, 2); // stack: [] + lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] + + // Cleanup our used registry entry, REGISTRY[i] = nil. + lua_pushnil(L); // stack: [varPkg,nil] + lua_rawseti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::GetPackage +// +// Push the value of a package of name to the stack +// +/////////////////////////////////////////////////////////////// +void CLuaMain::GetPackage(lua_State* L, SString &strName) +{ + lua_getglobal(L, "package"); // stack: [tbl_package] + if (lua_type(L, -1) == LUA_TNIL ) + InitPackageStorage(m_luaVM); + + lua_pushstring(L, "loaded"); // stack: [tbl_package,"loaded"] + if (lua_type(L, -1) == LUA_TNIL) + InitPackageStorage(m_luaVM); + + lua_rawget(L, -2); // stack: [tbl_package,tbl_loaded] + lua_pushstring(L, strName.c_str()); // stack: [tbl_package,tbl_loaded,"moduleName"] + lua_rawget(L, -2); // stack: [tbl_package,varPkg] + lua_remove(L, -2); // stack: [varPkg] +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::LoadLuaLib +// +// Load a Lua lib of a given name +// +/////////////////////////////////////////////////////////////// +bool CLuaMain::LoadLuaLib(lua_State *L, SString strName) +{ + SString strPath = strName; + // Name format shouldn't include slashes. Subdirs are dots. + ReplaceOccurrencesInString(strPath, "\\", ""); + ReplaceOccurrencesInString(strPath, "/", ""); + ReplaceOccurrencesInString(strPath, ".", "/"); + + SString strResPath = m_pResource->IsResourceZip() ? m_pResource->GetResourceCacheDirectoryPath() : m_pResource->GetResourceDirectoryPath(); + + std::vector < char > buffer; + // Try /?.lua + SString strFilePath = PathJoin(strResPath, strPath + ".lua"); + if (FileExists(strFilePath)) + FileLoad(strFilePath, buffer); + else + { + // Try /?/init.lua + strFilePath = PathJoin(strResPath, strPath, "init.lua"); + if (FileExists(strFilePath)) + FileLoad(strFilePath, buffer); + } + + if (buffer.size() > 0) + { + int luaSavedTop = lua_gettop(L); + LoadScriptFromBuffer(&buffer.at(0), buffer.size(), strFilePath.c_str(), false); + // Only keep the first return value + if (lua_gettop(L) > luaSavedTop) + lua_settop(L, luaSavedTop+1); + + SetPackage(L, strName); // Store our package into package.loaded + GetPackage(L, strName); // Grab it back as a return value. + return true; + } + + return false; +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::LoadClib +// +// Load a C lib of a given name +// +/////////////////////////////////////////////////////////////// +bool CLuaMain::LoadClib(lua_State* L, SString strName) +{ + SString strPath = strName; + // Name format shouldn't include slashes. Subdirs are dots. + ReplaceOccurrencesInString(strPath, "\\", ""); + ReplaceOccurrencesInString(strPath, "/", ""); + ReplaceOccurrencesInString(strPath, ".", "/"); + + strPath = PathJoin(g_pServerInterface->GetModManager()->GetServerPath(), SERVER_BIN_PATH_MOD, "modules", strPath); + +#ifdef WIN32 + strPath += ".dll"; +#else + strPath += ".so"; +#endif + + luaL_loader_C(L, strName.c_str(), strPath.c_str()); + if (lua_type(L, -1) == LUA_TNIL) + return false; + + SetPackage(L, strName); + return true; +} \ No newline at end of file diff --git a/Server/mods/deathmatch/logic/lua/CLuaMain.h b/Server/mods/deathmatch/logic/lua/CLuaMain.h index 4ed2a2d0771..19c704b3374 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaMain.h +++ b/Server/mods/deathmatch/logic/lua/CLuaMain.h @@ -59,7 +59,7 @@ class CLuaMain //: public CClient ~CLuaMain ( void ); - bool LoadScriptFromBuffer ( const char* cpBuffer, unsigned int uiSize, const char* szFileName ); + bool LoadScriptFromBuffer ( const char* cpBuffer, unsigned int uiSize, const char* szFileName, bool bClearReturnValues = true ); bool LoadScript ( const char* szLUAScript ); void UnloadScript ( void ); @@ -120,6 +120,12 @@ class CLuaMain //: public CClient static int LuaLoadBuffer ( lua_State *L, const char *buff, size_t sz, const char *name ); static int OnUndump ( const char* p, size_t n ); + void InitPackageStorage ( lua_State* L ); // Create a psuedo package.loaded table + void GetPackage ( lua_State *L, SString &strName ); // Push the package value to the top of the stack + void SetPackage ( lua_State *L, SString &strName ); // Set the package to the value at the top of the stack + bool LoadLuaLib ( lua_State *L, SString strName ); // Load a lua library of a given name + bool LoadClib ( lua_State *L, SString strName ); // Load a C Lib of a given name + private: void InitSecurity ( void ); void InitClasses ( lua_State* luaVM ); diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp index 5f289295938..e525d72d44a 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp @@ -38,6 +38,9 @@ void CLuaUtilDefs::LoadFunctions ( void ) CLuaCFunctions::AddFunction ( "pregFind", PregFind ); CLuaCFunctions::AddFunction ( "pregReplace", PregReplace ); CLuaCFunctions::AddFunction ( "pregMatch", PregMatch ); + + // Package functions + CLuaCFunctions::AddFunction ( "require", Require ); } int CLuaUtilDefs::DisabledFunction ( lua_State* luaVM ) @@ -559,3 +562,38 @@ int CLuaUtilDefs::PregMatch ( lua_State* luaVM ) lua_pushboolean ( luaVM, false ); return 1; } + +int CLuaUtilDefs::Require(lua_State* luaVM) +{ +#ifndef MTA_CLIENT + // table require ( string name ) + SString strMod; + + CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM); + CScriptArgReader argStream(luaVM); + argStream.ReadString(strMod); + + if (!argStream.HasErrors()) + { + // Check if package exists already, if so load it + // stack: ["moduleName"] + pLuaMain->GetPackage(luaVM, strMod); // stack: ["moduleName",pkgModule/nil] + if (lua_type(luaVM, -1) != LUA_TNIL) + return 1; + lua_pop(luaVM,1); // stack: ["moduleName"] + + // Check whether the appropriate pure lua module exists + if (pLuaMain->LoadLuaLib(luaVM, strMod)) // stack: ["moduleName",pkgLuaMod/nil] + return 1; + + // Check if a C library exists + if (pLuaMain->LoadClib(luaVM, strMod)) // stack: ["moduleName",fncModule/nil] + return 1; + lua_pop(luaVM,2); // stack: [] + } + else + m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); +#endif + lua_pushboolean(luaVM, false); + return 1; +} \ No newline at end of file diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.h b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.h index b5b32173d30..bc58a049825 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.h +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.h @@ -45,4 +45,7 @@ class CLuaUtilDefs : public CLuaDefs LUA_DECLARE ( PregFind ); LUA_DECLARE ( PregReplace ); LUA_DECLARE ( PregMatch ); + + // Package functions + LUA_DECLARE ( Require ); }; diff --git a/vendor/lua/src/lauxlib.h b/vendor/lua/src/lauxlib.h index 34258235dbe..fad2c246835 100644 --- a/vendor/lua/src/lauxlib.h +++ b/vendor/lua/src/lauxlib.h @@ -172,3 +172,8 @@ LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); #endif +///////////////////////////// +// MTA EXTENSIONS +///////////////////////////// +LUALIB_API int luaL_loader_C(lua_State *L, const char* name, const char* filename); + diff --git a/vendor/lua/src/loadlib.c b/vendor/lua/src/loadlib.c index 6158c5353df..b1dcaeb781c 100644 --- a/vendor/lua/src/loadlib.c +++ b/vendor/lua/src/loadlib.c @@ -664,3 +664,15 @@ LUALIB_API int luaopen_package (lua_State *L) { return 1; /* return 'package' table */ } + +///////////////////////////// +// MTA EXTENSIONS +///////////////////////////// + +// API to direct load a C library. +LUA_API int luaL_loader_C(lua_State *L, const char* name, const char* filename) { + const char* funcname = mkfuncname(L, name); + if (ll_loadfunc(L, filename, funcname) != 0) + loaderror(L, filename); + return 1; /* library loaded successfully */ +} \ No newline at end of file From a1d0cd74fd8dd1a6801b89b72a1c44a025f428c9 Mon Sep 17 00:00:00 2001 From: darkdreamingdan Date: Sat, 13 Aug 2016 00:35:04 +0100 Subject: [PATCH 02/10] Code cleanup Fixed if someone naughty sets package as nil. --- Server/mods/deathmatch/logic/lua/CLuaMain.cpp | 58 +++++++++---------- Server/mods/deathmatch/logic/lua/CLuaMain.h | 1 + 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp index fe083103cd9..fc3a089fbb4 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp @@ -63,6 +63,7 @@ CLuaMain::CLuaMain ( CLuaManager* pLuaManager, m_bEnableOOP = bEnableOOP; + m_iPackageLoadedRef = -1; CPerfStatLuaMemory::GetSingleton ()->OnLuaMainCreate ( this ); CPerfStatLuaTiming::GetSingleton ()->OnLuaMainCreate ( this ); @@ -712,7 +713,11 @@ void CLuaMain::InitPackageStorage(lua_State* L) lua_settable(L, -3); // stack: [tbl_new,"loaded",tbl_new2] } - // Finally, store our original table as package.loaded + // Keep our package.loaded table safely in registry + m_iPackageLoadedRef = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [tbl_new,"loaded"] + lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_new,"loaded",tbl_new2] + + // Finally, store our original table as global package.loaded lua_settable(L, -3); // stack: [tbl_new] lua_setglobal(L, "package"); // stack: [] } @@ -721,33 +726,28 @@ void CLuaMain::InitPackageStorage(lua_State* L) // // CLuaMain::SetPackage // -// Pop the top most value as a package +// Set the top most value as a package (No pop) // /////////////////////////////////////////////////////////////// void CLuaMain::SetPackage(lua_State* L, SString &strName ) { + if (m_iPackageLoadedRef < 0) + return; // We set varPkg, which is already on the stack, into package.loaded.moduleName = varPkg. - // stack: [varPkg] - int iPkg = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [] - lua_getglobal(L, "package"); // stack: [tbl_package] - if (lua_type(L, -1) == LUA_TNIL ) - InitPackageStorage(L); - - lua_pushstring(L, "loaded"); // stack: [tbl_package,"loaded"] - lua_rawget(L, -2); // stack: [tbl_package,tbl_loaded] - if (lua_type(L, -1) == LUA_TNIL) - InitPackageStorage(L); + // stack: [varPkg] + int iPkg = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [] + lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // [tbl_loaded] - lua_pushstring(L, strName.c_str()); // stack: [tbl_package,tbl_loaded,"moduleName"] - lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [tbl_package,tbl_loaded,"moduleName",varPkg] - lua_rawset(L, -3); // stack: [tbl_package,tbl_loaded] - lua_pop(L, 2); // stack: [] - lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] + lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"] + lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [tbl_loaded,"moduleName",varPkg] + lua_rawset(L, -3); // stack: [tbl_loaded] + lua_pop(L, 2); // stack: [] + lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] - // Cleanup our used registry entry, REGISTRY[i] = nil. - lua_pushnil(L); // stack: [varPkg,nil] - lua_rawseti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] + // Cleanup our used registry entry, i.e. REGISTRY[i] = nil. + lua_pushnil(L); // stack: [varPkg,nil] + lua_rawseti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] } /////////////////////////////////////////////////////////////// @@ -759,18 +759,13 @@ void CLuaMain::SetPackage(lua_State* L, SString &strName ) /////////////////////////////////////////////////////////////// void CLuaMain::GetPackage(lua_State* L, SString &strName) { - lua_getglobal(L, "package"); // stack: [tbl_package] - if (lua_type(L, -1) == LUA_TNIL ) - InitPackageStorage(m_luaVM); - - lua_pushstring(L, "loaded"); // stack: [tbl_package,"loaded"] - if (lua_type(L, -1) == LUA_TNIL) - InitPackageStorage(m_luaVM); + if (m_iPackageLoadedRef < 0) + return; - lua_rawget(L, -2); // stack: [tbl_package,tbl_loaded] - lua_pushstring(L, strName.c_str()); // stack: [tbl_package,tbl_loaded,"moduleName"] - lua_rawget(L, -2); // stack: [tbl_package,varPkg] - lua_remove(L, -2); // stack: [varPkg] + lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_loaded] + lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"] + lua_rawget(L, -2); // stack: [tbl_loaded,varPkg] + lua_remove(L, -2); // stack: [varPkg] } /////////////////////////////////////////////////////////////// @@ -812,7 +807,6 @@ bool CLuaMain::LoadLuaLib(lua_State *L, SString strName) lua_settop(L, luaSavedTop+1); SetPackage(L, strName); // Store our package into package.loaded - GetPackage(L, strName); // Grab it back as a return value. return true; } diff --git a/Server/mods/deathmatch/logic/lua/CLuaMain.h b/Server/mods/deathmatch/logic/lua/CLuaMain.h index 19c704b3374..14033c688f2 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaMain.h +++ b/Server/mods/deathmatch/logic/lua/CLuaMain.h @@ -141,6 +141,7 @@ class CLuaMain //: public CClient lua_State* m_luaVM; CLuaTimerManager* m_pLuaTimerManager; + int m_iPackageLoadedRef; class CResource* m_pResource; class CResourceFile* m_pResourceFile; From b8ec9e2c225818f01cfe6b239c9d5f8a1f63e88b Mon Sep 17 00:00:00 2001 From: darkdreamingdan Date: Sat, 13 Aug 2016 11:41:40 +0100 Subject: [PATCH 03/10] Added more useful error messages to require --- Server/mods/deathmatch/logic/lua/CLuaMain.cpp | 41 ++++++++++++++++--- Server/mods/deathmatch/logic/lua/CLuaMain.h | 4 +- .../deathmatch/logic/luadefs/CLuaUtilDefs.cpp | 8 +++- vendor/lua/src/loadlib.c | 2 +- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp index fc3a089fbb4..479f6ce6cfe 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp @@ -757,7 +757,7 @@ void CLuaMain::SetPackage(lua_State* L, SString &strName ) // Push the value of a package of name to the stack // /////////////////////////////////////////////////////////////// -void CLuaMain::GetPackage(lua_State* L, SString &strName) +void CLuaMain::GetPackage(lua_State* L, SString &strName ) { if (m_iPackageLoadedRef < 0) return; @@ -775,7 +775,7 @@ void CLuaMain::GetPackage(lua_State* L, SString &strName) // Load a Lua lib of a given name // /////////////////////////////////////////////////////////////// -bool CLuaMain::LoadLuaLib(lua_State *L, SString strName) +bool CLuaMain::LoadLuaLib(lua_State *L, SString strName, SString &strError) { SString strPath = strName; // Name format shouldn't include slashes. Subdirs are dots. @@ -792,10 +792,21 @@ bool CLuaMain::LoadLuaLib(lua_State *L, SString strName) FileLoad(strFilePath, buffer); else { + // Don't use a format string for safety, so we construct the error by hand + strError += "error loading module " + strName + " from file " + strFilePath + + ":\n\t The specified module could not be found"; + // Try /?/init.lua strFilePath = PathJoin(strResPath, strPath, "init.lua"); if (FileExists(strFilePath)) FileLoad(strFilePath, buffer); + else + { + strError += "\n"; + strError += "error loading module " + strName + " from file " + strFilePath + + ":\n\t The specified module could not be found"; + return false; + } } if (buffer.size() > 0) @@ -806,9 +817,19 @@ bool CLuaMain::LoadLuaLib(lua_State *L, SString strName) if (lua_gettop(L) > luaSavedTop) lua_settop(L, luaSavedTop+1); + if (lua_type(L, -1) == LUA_TNIL) + { + strError += "error loading module " + strName + " from file " + strFilePath + + ":\n\t Module didn't return a value"; + return false; + } + SetPackage(L, strName); // Store our package into package.loaded return true; } + else + strError += "error loading module " + strName + " from file " + strFilePath + + ":\n\t Error loading script file"; return false; } @@ -820,7 +841,7 @@ bool CLuaMain::LoadLuaLib(lua_State *L, SString strName) // Load a C lib of a given name // /////////////////////////////////////////////////////////////// -bool CLuaMain::LoadClib(lua_State* L, SString strName) +bool CLuaMain::LoadClib(lua_State* L, SString strName, SString &strError ) { SString strPath = strName; // Name format shouldn't include slashes. Subdirs are dots. @@ -836,9 +857,19 @@ bool CLuaMain::LoadClib(lua_State* L, SString strName) strPath += ".so"; #endif - luaL_loader_C(L, strName.c_str(), strPath.c_str()); - if (lua_type(L, -1) == LUA_TNIL) + if (!FileExists(strPath)) + { + strError += "error loading module " + strName + " from file " + strPath + + ":\n\t The specified module could not be found"; return false; + } + + if (!luaL_loader_C(L, strName.c_str(), strPath.c_str()) || lua_type(L, -1) == LUA_TNIL) + { + strError += "error loading module " + strName + " from file " + strPath + + ":\n\t Failed to load module"; + return false; + } SetPackage(L, strName); return true; diff --git a/Server/mods/deathmatch/logic/lua/CLuaMain.h b/Server/mods/deathmatch/logic/lua/CLuaMain.h index 14033c688f2..7b8f5e160e0 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaMain.h +++ b/Server/mods/deathmatch/logic/lua/CLuaMain.h @@ -123,8 +123,8 @@ class CLuaMain //: public CClient void InitPackageStorage ( lua_State* L ); // Create a psuedo package.loaded table void GetPackage ( lua_State *L, SString &strName ); // Push the package value to the top of the stack void SetPackage ( lua_State *L, SString &strName ); // Set the package to the value at the top of the stack - bool LoadLuaLib ( lua_State *L, SString strName ); // Load a lua library of a given name - bool LoadClib ( lua_State *L, SString strName ); // Load a C Lib of a given name + bool LoadLuaLib ( lua_State *L, SString strName, SString &strError ); // Load a lua library of a given name + bool LoadClib ( lua_State *L, SString strName, SString &strError ); // Load a C Lib of a given name private: void InitSecurity ( void ); diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp index e525d72d44a..b6c2f11e9d0 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp @@ -575,6 +575,7 @@ int CLuaUtilDefs::Require(lua_State* luaVM) if (!argStream.HasErrors()) { + SString strError = ""; // Check if package exists already, if so load it // stack: ["moduleName"] pLuaMain->GetPackage(luaVM, strMod); // stack: ["moduleName",pkgModule/nil] @@ -583,12 +584,15 @@ int CLuaUtilDefs::Require(lua_State* luaVM) lua_pop(luaVM,1); // stack: ["moduleName"] // Check whether the appropriate pure lua module exists - if (pLuaMain->LoadLuaLib(luaVM, strMod)) // stack: ["moduleName",pkgLuaMod/nil] + if (pLuaMain->LoadLuaLib(luaVM, strMod,strError)) // stack: ["moduleName",pkgLuaMod/nil] return 1; + strError += "\n"; // Check if a C library exists - if (pLuaMain->LoadClib(luaVM, strMod)) // stack: ["moduleName",fncModule/nil] + if (pLuaMain->LoadClib(luaVM, strMod,strError)) // stack: ["moduleName",fncModule/nil] return 1; + m_pScriptDebugging->LogCustom(luaVM, strError); + lua_pop(luaVM,2); // stack: [] } else diff --git a/vendor/lua/src/loadlib.c b/vendor/lua/src/loadlib.c index b1dcaeb781c..2ab4c6f147d 100644 --- a/vendor/lua/src/loadlib.c +++ b/vendor/lua/src/loadlib.c @@ -673,6 +673,6 @@ LUALIB_API int luaopen_package (lua_State *L) { LUA_API int luaL_loader_C(lua_State *L, const char* name, const char* filename) { const char* funcname = mkfuncname(L, name); if (ll_loadfunc(L, filename, funcname) != 0) - loaderror(L, filename); + return 0; return 1; /* library loaded successfully */ } \ No newline at end of file From 90dc2cd80d236fa134532035b92113a84bb3b2a1 Mon Sep 17 00:00:00 2001 From: darkdreamingdan Date: Sat, 13 Aug 2016 17:43:58 +0100 Subject: [PATCH 04/10] Lua C modules now require ACL access For each resource that wants to use a C module, a right needs to be added in the following format: For example, A * wildcard works to grant a resource access to all modules. --- .../logic/CAccessControlListManager.cpp | 9 +++++++++ .../deathmatch/logic/CAccessControlListRight.h | 3 ++- .../logic/lua/CLuaFunctionParseHelpers.cpp | 1 + Server/mods/deathmatch/logic/lua/CLuaMain.cpp | 18 ++++++++++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Server/mods/deathmatch/logic/CAccessControlListManager.cpp b/Server/mods/deathmatch/logic/CAccessControlListManager.cpp index c963c8d5e9e..452a044ca17 100644 --- a/Server/mods/deathmatch/logic/CAccessControlListManager.cpp +++ b/Server/mods/deathmatch/logic/CAccessControlListManager.cpp @@ -144,6 +144,10 @@ bool CAccessControlListManager::Load ( void ) { pRight = pACL->AddRight ( &szRightName[8], CAccessControlListRight::RIGHT_TYPE_GENERAL, bAccess ); } + else if ( StringBeginsWith ( szRightName, "module." ) ) + { + pRight = pACL->AddRight ( &szRightName[7], CAccessControlListRight::RIGHT_TYPE_MODULE, bAccess ); + } else continue; // Set all the extra attributes @@ -552,6 +556,11 @@ const char* CAccessControlListManager::ExtractRightName ( const char* szRightNam eType = CAccessControlListRight::RIGHT_TYPE_GENERAL; return szRightName + 8; } + else if ( StringBeginsWith( szRightName, "module." ) ) + { + eType = CAccessControlListRight::RIGHT_TYPE_MODULE; + return szRightName + 7; + } // Failed return NULL; diff --git a/Server/mods/deathmatch/logic/CAccessControlListRight.h b/Server/mods/deathmatch/logic/CAccessControlListRight.h index ee4c70d5474..4106e038f06 100644 --- a/Server/mods/deathmatch/logic/CAccessControlListRight.h +++ b/Server/mods/deathmatch/logic/CAccessControlListRight.h @@ -25,7 +25,8 @@ class CAccessControlListRight RIGHT_TYPE_COMMAND, RIGHT_TYPE_FUNCTION, RIGHT_TYPE_RESOURCE, - RIGHT_TYPE_GENERAL + RIGHT_TYPE_GENERAL, + RIGHT_TYPE_MODULE }; public: diff --git a/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index 2608a5c5b38..79d1743176b 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -240,6 +240,7 @@ IMPLEMENT_ENUM_BEGIN( CAccessControlListRight::ERightType ) ADD_ENUM ( CAccessControlListRight::RIGHT_TYPE_FUNCTION, "function" ) ADD_ENUM ( CAccessControlListRight::RIGHT_TYPE_RESOURCE, "resource" ) ADD_ENUM ( CAccessControlListRight::RIGHT_TYPE_GENERAL, "general" ) + ADD_ENUM ( CAccessControlListRight::RIGHT_TYPE_MODULE, "module" ) IMPLEMENT_ENUM_END( "right-type" ) IMPLEMENT_ENUM_BEGIN( CElement::EElementType ) diff --git a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp index 479f6ce6cfe..a133480734a 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp @@ -864,6 +864,24 @@ bool CLuaMain::LoadClib(lua_State* L, SString strName, SString &strError ) return false; } + // Check ACL permissions + if ( !g_pGame->GetACLManager()->CanObjectUseRight(m_pResource->GetName().c_str(), + CAccessControlListGroupObject::OBJECT_TYPE_RESOURCE, + "*", + CAccessControlListRight::RIGHT_TYPE_MODULE, + false) && + !g_pGame->GetACLManager()->CanObjectUseRight(m_pResource->GetName().c_str(), + CAccessControlListGroupObject::OBJECT_TYPE_RESOURCE, + strName.c_str(), + CAccessControlListRight::RIGHT_TYPE_MODULE, + false) + ) + { + strError += "error loading module " + strName + " from file " + strPath + + ":\n\t ACL access denied. Grant \"module." + strName + "\" right to resource " + m_pResource->GetName(); + return false; + } + if (!luaL_loader_C(L, strName.c_str(), strPath.c_str()) || lua_type(L, -1) == LUA_TNIL) { strError += "error loading module " + strName + " from file " + strPath + From 09319f3fdac895dd8e367a72c93414b4524a49b3 Mon Sep 17 00:00:00 2001 From: darkdreamingdan Date: Sat, 13 Aug 2016 21:37:48 +0100 Subject: [PATCH 05/10] Added clientside support for require (only for pure lua modules) --- Client/mods/deathmatch/logic/lua/CLuaMain.cpp | 153 +++++++++++++++++- Client/mods/deathmatch/logic/lua/CLuaMain.h | 8 +- .../deathmatch/logic/luadefs/CLuaUtilDefs.cpp | 8 +- 3 files changed, 161 insertions(+), 8 deletions(-) diff --git a/Client/mods/deathmatch/logic/lua/CLuaMain.cpp b/Client/mods/deathmatch/logic/lua/CLuaMain.cpp index ef82cdd5c2e..2356c317ecc 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaMain.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaMain.cpp @@ -42,6 +42,8 @@ CLuaMain::CLuaMain ( CLuaManager* pLuaManager, CResource* pResourceOwner, bool b m_pResource = pResourceOwner; + m_iPackageLoadedRef = -1; + m_bEnableOOP = bEnableOOP; CClientPerfStatLuaMemory::GetSingleton ()->OnLuaMainCreate ( this ); @@ -150,6 +152,9 @@ void CLuaMain::InitVM ( void ) luaopen_debug ( m_luaVM ); luaopen_utf8 ( m_luaVM ); + // Initialize packages system + InitPackageStorage(m_luaVM); + // Initialize security restrictions. Very important to prevent lua trojans and viruses! InitSecurity(); @@ -207,7 +212,7 @@ void CLuaMain::InstructionCountHook ( lua_State* luaVM, lua_Debug* pDebug ) } -bool CLuaMain::LoadScriptFromBuffer ( const char* cpInBuffer, unsigned int uiInSize, const char* szFileName ) +bool CLuaMain::LoadScriptFromBuffer(const char* cpInBuffer, unsigned int uiInSize, const char* szFileName, bool bClearReturnValues) { SString strNiceFilename = ConformResourcePath( szFileName ); @@ -272,7 +277,7 @@ bool CLuaMain::LoadScriptFromBuffer ( const char* cpInBuffer, unsigned int uiInS g_pClientGame->GetScriptDebugging()->LogPCallError( m_luaVM, strRes, true ); } // Cleanup any return values - if ( lua_gettop ( m_luaVM ) > luaSavedTop ) + if ( bClearReturnValues && lua_gettop ( m_luaVM ) > luaSavedTop ) lua_settop( m_luaVM, luaSavedTop ); return true; } @@ -571,3 +576,147 @@ int CLuaMain::OnUndump( const char* p, size_t n ) } return 1; } + + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::InitPackageStorage +// +// Create a table for storage of Lua packages - stored in the Lua VM +// +/////////////////////////////////////////////////////////////// +void CLuaMain::InitPackageStorage(lua_State* L) +{ + lua_newtable(L); // stack: [tbl_new] + lua_pushstring(L, "loaded"); // stack: [tbl_new,"loaded"] + lua_newtable(L); // stack: [tbl_new,"loaded",tbl_new2] + + // We push our default Lua libs are loaded packages + std::vector szDefaultLibs = { "math", "string", "table", "debug", "utf8" }; + for (auto it : szDefaultLibs) + { + lua_pushstring(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math"] + lua_getglobal(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math",_G.math] + lua_settable(L, -3); // stack: [tbl_new,"loaded",tbl_new2] + } + + // Keep our package.loaded table safely in registry + m_iPackageLoadedRef = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [tbl_new,"loaded"] + lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_new,"loaded",tbl_new2] + + // Finally, store our original table as global package.loaded + lua_settable(L, -3); // stack: [tbl_new] + lua_setglobal(L, "package"); // stack: [] +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::SetPackage +// +// Set the top most value as a package (No pop) +// +/////////////////////////////////////////////////////////////// +void CLuaMain::SetPackage(lua_State* L, SString &strName) +{ + if (m_iPackageLoadedRef < 0) + return; + // We set varPkg, which is already on the stack, into package.loaded.moduleName = varPkg. + // stack: [varPkg] + int iPkg = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [] + lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // [tbl_loaded] + + + lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"] + lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [tbl_loaded,"moduleName",varPkg] + lua_rawset(L, -3); // stack: [tbl_loaded] + lua_pop(L, 2); // stack: [] + lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] + + // Cleanup our used registry entry, i.e. REGISTRY[i] = nil. + lua_pushnil(L); // stack: [varPkg,nil] + lua_rawseti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::GetPackage +// +// Push the value of a package of name to the stack +// +/////////////////////////////////////////////////////////////// +void CLuaMain::GetPackage(lua_State* L, SString &strName) +{ + if (m_iPackageLoadedRef < 0) + return; + + lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_loaded] + lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"] + lua_rawget(L, -2); // stack: [tbl_loaded,varPkg] + lua_remove(L, -2); // stack: [varPkg] +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::LoadLuaLib +// +// Load a Lua lib of a given name +// +/////////////////////////////////////////////////////////////// +bool CLuaMain::LoadLuaLib(lua_State *L, SString strName, SString &strError) +{ + SString strPath = strName; + // Name format shouldn't include slashes. Subdirs are dots. + ReplaceOccurrencesInString(strPath, "\\", ""); + ReplaceOccurrencesInString(strPath, "/", ""); + ReplaceOccurrencesInString(strPath, ".", "/"); + + SString strResPath = m_pResource->GetResourceDirectoryPath(ACCESS_PUBLIC, ""); + + std::vector < char > buffer; + // Try /?.lua + SString strFilePath = PathJoin(strResPath, strPath + ".lua"); + if (FileExists(strFilePath)) + FileLoad(strFilePath, buffer); + else + { + // Don't use a format string for safety, so we construct the error by hand + strError += "error loading module " + strName + " from file " + strFilePath + + ":\n\t The specified module could not be found"; + + // Try /?/init.lua + strFilePath = PathJoin(strResPath, strPath, "init.lua"); + if (FileExists(strFilePath)) + FileLoad(strFilePath, buffer); + else + { + strError += "\n"; + strError += "error loading module " + strName + " from file " + strFilePath + + ":\n\t The specified module could not be found"; + return false; + } + } + + if (buffer.size() > 0) + { + int luaSavedTop = lua_gettop(L); + LoadScriptFromBuffer(&buffer.at(0), buffer.size(), strFilePath.c_str(), false); + // Only keep the first return value + if (lua_gettop(L) > luaSavedTop) + lua_settop(L, luaSavedTop + 1); + + if (lua_type(L, -1) == LUA_TNIL) + { + strError += "error loading module " + strName + " from file " + strFilePath + + ":\n\t Module didn't return a value"; + return false; + } + + SetPackage(L, strName); // Store our package into package.loaded + return true; + } + else + strError += "error loading module " + strName + " from file " + strFilePath + + ":\n\t Error loading script file"; + + return false; +} \ No newline at end of file diff --git a/Client/mods/deathmatch/logic/lua/CLuaMain.h b/Client/mods/deathmatch/logic/lua/CLuaMain.h index a98153b9f4d..b0b3b80afbd 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaMain.h +++ b/Client/mods/deathmatch/logic/lua/CLuaMain.h @@ -44,7 +44,7 @@ class CLuaMain //: public CClient CLuaMain ( class CLuaManager* pLuaManager, CResource* pResourceOwner, bool bEnableOOP ); ~CLuaMain ( void ); - bool LoadScriptFromBuffer ( const char* cpBuffer, unsigned int uiSize, const char* szFileName ); + bool LoadScriptFromBuffer ( const char* cpBuffer, unsigned int uiSize, const char* szFileName, bool bClearReturnValues = true ); bool LoadScript ( const char* szLUAScript ); void UnloadScript ( void ); @@ -80,6 +80,11 @@ class CLuaMain //: public CClient static int LuaLoadBuffer ( lua_State *L, const char *buff, size_t sz, const char *name ); static int OnUndump ( const char* p, size_t n ); + void InitPackageStorage(lua_State* L); // Create a psuedo package.loaded table + void GetPackage(lua_State *L, SString &strName); // Push the package value to the top of the stack + void SetPackage(lua_State *L, SString &strName); // Set the package to the value at the top of the stack + bool LoadLuaLib(lua_State *L, SString strName, SString &strError); // Load a lua library of a given name + bool IsOOPEnabled ( void ) { return m_bEnableOOP; } private: void InitSecurity ( void ); @@ -90,6 +95,7 @@ class CLuaMain //: public CClient lua_State* m_luaVM; CLuaTimerManager* m_pLuaTimerManager; + int m_iPackageLoadedRef; bool m_bBeingDeleted; // prevent it being deleted twice diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp index b6c2f11e9d0..dee3e795726 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp @@ -565,7 +565,6 @@ int CLuaUtilDefs::PregMatch ( lua_State* luaVM ) int CLuaUtilDefs::Require(lua_State* luaVM) { -#ifndef MTA_CLIENT // table require ( string name ) SString strMod; @@ -587,17 +586,16 @@ int CLuaUtilDefs::Require(lua_State* luaVM) if (pLuaMain->LoadLuaLib(luaVM, strMod,strError)) // stack: ["moduleName",pkgLuaMod/nil] return 1; strError += "\n"; - +#ifndef MTA_CLIENT // Check if a C library exists if (pLuaMain->LoadClib(luaVM, strMod,strError)) // stack: ["moduleName",fncModule/nil] return 1; +#endif m_pScriptDebugging->LogCustom(luaVM, strError); - - lua_pop(luaVM,2); // stack: [] } else m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); -#endif + lua_pushboolean(luaVM, false); return 1; } \ No newline at end of file From c5babeb47ab08a3cf25c4dd9fb1cd1791c21fab8 Mon Sep 17 00:00:00 2001 From: darkdreamingdan Date: Sat, 13 Aug 2016 21:39:17 +0100 Subject: [PATCH 06/10] Adjusted mtaserver.conf comments to annoy developers and users --- Server/mods/deathmatch/mtaserver.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Server/mods/deathmatch/mtaserver.conf b/Server/mods/deathmatch/mtaserver.conf index 90aac341233..1ed92cdb62a 100644 --- a/Server/mods/deathmatch/mtaserver.conf +++ b/Server/mods/deathmatch/mtaserver.conf @@ -229,8 +229,8 @@ Values: 0 - Off, 1 - On. Default - 1 --> 1 - + From eb03d0ca3beb468f1ab493a297707c9420504963 Mon Sep 17 00:00:00 2001 From: darkdreamingdan Date: Mon, 26 Sep 2016 15:09:52 +0100 Subject: [PATCH 07/10] Small lua packages fix --- Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp index dee3e795726..677254507bd 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp @@ -585,8 +585,8 @@ int CLuaUtilDefs::Require(lua_State* luaVM) // Check whether the appropriate pure lua module exists if (pLuaMain->LoadLuaLib(luaVM, strMod,strError)) // stack: ["moduleName",pkgLuaMod/nil] return 1; - strError += "\n"; #ifndef MTA_CLIENT + strError += "\n"; // Check if a C library exists if (pLuaMain->LoadClib(luaVM, strMod,strError)) // stack: ["moduleName",fncModule/nil] return 1; From aae6ebf52b3c52295e44d0934da966f10f776d3d Mon Sep 17 00:00:00 2001 From: Qais Patankar Date: Wed, 31 Oct 2018 22:23:58 +0000 Subject: [PATCH 08/10] Move duplicate package methods to CLuaMain.Shared --- Client/mods/deathmatch/logic/lua/CLuaMain.cpp | 138 ---------------- Server/mods/deathmatch/logic/lua/CLuaMain.cpp | 138 ---------------- .../deathmatch/logic/lua/CLuaMain.Shared.cpp | 151 ++++++++++++++++++ 3 files changed, 151 insertions(+), 276 deletions(-) create mode 100644 Shared/mods/deathmatch/logic/lua/CLuaMain.Shared.cpp diff --git a/Client/mods/deathmatch/logic/lua/CLuaMain.cpp b/Client/mods/deathmatch/logic/lua/CLuaMain.cpp index 188f1a4f1d3..bd4e2b577ac 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaMain.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaMain.cpp @@ -560,141 +560,3 @@ int CLuaMain::OnUndump(const char* p, size_t n) } return 1; } - -/////////////////////////////////////////////////////////////// -// -// CLuaMain::InitPackageStorage -// -// Create a table for storage of Lua packages - stored in the Lua VM -// -/////////////////////////////////////////////////////////////// -void CLuaMain::InitPackageStorage(lua_State* L) -{ - lua_newtable(L); // stack: [tbl_new] - lua_pushstring(L, "loaded"); // stack: [tbl_new,"loaded"] - lua_newtable(L); // stack: [tbl_new,"loaded",tbl_new2] - - // We push our default Lua libs are loaded packages - std::vector szDefaultLibs = {"math", "string", "table", "debug", "utf8"}; - for (auto it : szDefaultLibs) - { - lua_pushstring(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math"] - lua_getglobal(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math",_G.math] - lua_settable(L, -3); // stack: [tbl_new,"loaded",tbl_new2] - } - - // Keep our package.loaded table safely in registry - m_iPackageLoadedRef = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [tbl_new,"loaded"] - lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_new,"loaded",tbl_new2] - - // Finally, store our original table as global package.loaded - lua_settable(L, -3); // stack: [tbl_new] - lua_setglobal(L, "package"); // stack: [] -} - -/////////////////////////////////////////////////////////////// -// -// CLuaMain::SetPackage -// -// Set the top most value as a package (No pop) -// -/////////////////////////////////////////////////////////////// -void CLuaMain::SetPackage(lua_State* L, SString& strName) -{ - if (m_iPackageLoadedRef < 0) - return; - // We set varPkg, which is already on the stack, into package.loaded.moduleName = varPkg. - // stack: [varPkg] - int iPkg = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [] - lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // [tbl_loaded] - - lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"] - lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [tbl_loaded,"moduleName",varPkg] - lua_rawset(L, -3); // stack: [tbl_loaded] - lua_pop(L, 2); // stack: [] - lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] - - // Cleanup our used registry entry, i.e. REGISTRY[i] = nil. - lua_pushnil(L); // stack: [varPkg,nil] - lua_rawseti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] -} - -/////////////////////////////////////////////////////////////// -// -// CLuaMain::GetPackage -// -// Push the value of a package of name to the stack -// -/////////////////////////////////////////////////////////////// -void CLuaMain::GetPackage(lua_State* L, SString& strName) -{ - if (m_iPackageLoadedRef < 0) - return; - - lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_loaded] - lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"] - lua_rawget(L, -2); // stack: [tbl_loaded,varPkg] - lua_remove(L, -2); // stack: [varPkg] -} - -/////////////////////////////////////////////////////////////// -// -// CLuaMain::LoadLuaLib -// -// Load a Lua lib of a given name -// -/////////////////////////////////////////////////////////////// -bool CLuaMain::LoadLuaLib(lua_State* L, SString strName, SString& strError) -{ - SString strPath = strName; - // Name format shouldn't include slashes. Subdirs are dots. - ReplaceOccurrencesInString(strPath, "\\", ""); - ReplaceOccurrencesInString(strPath, "/", ""); - ReplaceOccurrencesInString(strPath, ".", "/"); - - SString strResPath = m_pResource->GetResourceDirectoryPath(ACCESS_PUBLIC, ""); - - std::vector buffer; - // Try /?.lua - SString strFilePath = PathJoin(strResPath, strPath + ".lua"); - if (FileExists(strFilePath)) - FileLoad(strFilePath, buffer); - else - { - // Don't use a format string for safety, so we construct the error by hand - strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t The specified module could not be found"; - - // Try /?/init.lua - strFilePath = PathJoin(strResPath, strPath, "init.lua"); - if (FileExists(strFilePath)) - FileLoad(strFilePath, buffer); - else - { - strError += "\n"; - strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t The specified module could not be found"; - return false; - } - } - - if (buffer.size() > 0) - { - int luaSavedTop = lua_gettop(L); - LoadScriptFromBuffer(&buffer.at(0), buffer.size(), strFilePath.c_str(), false); - // Only keep the first return value - if (lua_gettop(L) > luaSavedTop) - lua_settop(L, luaSavedTop + 1); - - if (lua_type(L, -1) == LUA_TNIL) - { - strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t Module didn't return a value"; - return false; - } - - SetPackage(L, strName); // Store our package into package.loaded - return true; - } - else - strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t Error loading script file"; - - return false; -} diff --git a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp index 2c355d0400a..3da150210e6 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp @@ -661,144 +661,6 @@ int CLuaMain::OnUndump(const char* p, size_t n) return 1; } -/////////////////////////////////////////////////////////////// -// -// CLuaMain::InitPackageStorage -// -// Create a table for storage of Lua packages - stored in the Lua VM -// -/////////////////////////////////////////////////////////////// -void CLuaMain::InitPackageStorage(lua_State* L) -{ - lua_newtable(L); // stack: [tbl_new] - lua_pushstring(L, "loaded"); // stack: [tbl_new,"loaded"] - lua_newtable(L); // stack: [tbl_new,"loaded",tbl_new2] - - // We push our default Lua libs are loaded packages - std::vector szDefaultLibs = {"math", "string", "table", "debug", "utf8"}; - for (auto it : szDefaultLibs) - { - lua_pushstring(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math"] - lua_getglobal(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math",_G.math] - lua_settable(L, -3); // stack: [tbl_new,"loaded",tbl_new2] - } - - // Keep our package.loaded table safely in registry - m_iPackageLoadedRef = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [tbl_new,"loaded"] - lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_new,"loaded",tbl_new2] - - // Finally, store our original table as global package.loaded - lua_settable(L, -3); // stack: [tbl_new] - lua_setglobal(L, "package"); // stack: [] -} - -/////////////////////////////////////////////////////////////// -// -// CLuaMain::SetPackage -// -// Set the top most value as a package (No pop) -// -/////////////////////////////////////////////////////////////// -void CLuaMain::SetPackage(lua_State* L, SString& strName) -{ - if (m_iPackageLoadedRef < 0) - return; - // We set varPkg, which is already on the stack, into package.loaded.moduleName = varPkg. - // stack: [varPkg] - int iPkg = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [] - lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // [tbl_loaded] - - lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"] - lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [tbl_loaded,"moduleName",varPkg] - lua_rawset(L, -3); // stack: [tbl_loaded] - lua_pop(L, 2); // stack: [] - lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] - - // Cleanup our used registry entry, i.e. REGISTRY[i] = nil. - lua_pushnil(L); // stack: [varPkg,nil] - lua_rawseti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] -} - -/////////////////////////////////////////////////////////////// -// -// CLuaMain::GetPackage -// -// Push the value of a package of name to the stack -// -/////////////////////////////////////////////////////////////// -void CLuaMain::GetPackage(lua_State* L, SString& strName) -{ - if (m_iPackageLoadedRef < 0) - return; - - lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_loaded] - lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"] - lua_rawget(L, -2); // stack: [tbl_loaded,varPkg] - lua_remove(L, -2); // stack: [varPkg] -} - -/////////////////////////////////////////////////////////////// -// -// CLuaMain::LoadLuaLib -// -// Load a Lua lib of a given name -// -/////////////////////////////////////////////////////////////// -bool CLuaMain::LoadLuaLib(lua_State* L, SString strName, SString& strError) -{ - SString strPath = strName; - // Name format shouldn't include slashes. Subdirs are dots. - ReplaceOccurrencesInString(strPath, "\\", ""); - ReplaceOccurrencesInString(strPath, "/", ""); - ReplaceOccurrencesInString(strPath, ".", "/"); - - SString strResPath = m_pResource->IsResourceZip() ? m_pResource->GetResourceCacheDirectoryPath() : m_pResource->GetResourceDirectoryPath(); - - std::vector buffer; - // Try /?.lua - SString strFilePath = PathJoin(strResPath, strPath + ".lua"); - if (FileExists(strFilePath)) - FileLoad(strFilePath, buffer); - else - { - // Don't use a format string for safety, so we construct the error by hand - strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t The specified module could not be found"; - - // Try /?/init.lua - strFilePath = PathJoin(strResPath, strPath, "init.lua"); - if (FileExists(strFilePath)) - FileLoad(strFilePath, buffer); - else - { - strError += "\n"; - strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t The specified module could not be found"; - return false; - } - } - - if (buffer.size() > 0) - { - int luaSavedTop = lua_gettop(L); - LoadScriptFromBuffer(&buffer.at(0), buffer.size(), strFilePath.c_str(), false); - // Only keep the first return value - if (lua_gettop(L) > luaSavedTop) - lua_settop(L, luaSavedTop + 1); - - if (lua_type(L, -1) == LUA_TNIL) - { - strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t Module didn't return a value"; - return false; - } - - SetPackage(L, strName); // Store our package into package.loaded - return true; - } - else - strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t Error loading script file"; - - return false; -} - /////////////////////////////////////////////////////////////// // // CLuaMain::LoadClib diff --git a/Shared/mods/deathmatch/logic/lua/CLuaMain.Shared.cpp b/Shared/mods/deathmatch/logic/lua/CLuaMain.Shared.cpp new file mode 100644 index 00000000000..1b292c051f5 --- /dev/null +++ b/Shared/mods/deathmatch/logic/lua/CLuaMain.Shared.cpp @@ -0,0 +1,151 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: Shared/mods/logic/lua/CLuaMain.Shared.cpp + * + *****************************************************************************/ + +#include "StdInc.h" + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::InitPackageStorage +// +// Create a table for storage of Lua packages - stored in the Lua VM +// +/////////////////////////////////////////////////////////////// +void CLuaMain::InitPackageStorage(lua_State* L) +{ + lua_newtable(L); // stack: [tbl_new] + lua_pushstring(L, "loaded"); // stack: [tbl_new,"loaded"] + lua_newtable(L); // stack: [tbl_new,"loaded",tbl_new2] + + // We push our default Lua libs are loaded packages + std::vector szDefaultLibs = {"math", "string", "table", "debug", "utf8"}; + for (auto it : szDefaultLibs) + { + lua_pushstring(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math"] + lua_getglobal(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math",_G.math] + lua_settable(L, -3); // stack: [tbl_new,"loaded",tbl_new2] + } + + // Keep our package.loaded table safely in registry + m_iPackageLoadedRef = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [tbl_new,"loaded"] + lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_new,"loaded",tbl_new2] + + // Finally, store our original table as global package.loaded + lua_settable(L, -3); // stack: [tbl_new] + lua_setglobal(L, "package"); // stack: [] +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::SetPackage +// +// Set the top most value as a package (No pop) +// +/////////////////////////////////////////////////////////////// +void CLuaMain::SetPackage(lua_State* L, SString& strName) +{ + if (m_iPackageLoadedRef < 0) + return; + // We set varPkg, which is already on the stack, into package.loaded.moduleName = varPkg. + // stack: [varPkg] + int iPkg = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [] + lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // [tbl_loaded] + + lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"] + lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [tbl_loaded,"moduleName",varPkg] + lua_rawset(L, -3); // stack: [tbl_loaded] + lua_pop(L, 2); // stack: [] + lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] + + // Cleanup our used registry entry, i.e. REGISTRY[i] = nil. + lua_pushnil(L); // stack: [varPkg,nil] + lua_rawseti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::GetPackage +// +// Push the value of a package of name to the stack +// +/////////////////////////////////////////////////////////////// +void CLuaMain::GetPackage(lua_State* L, SString& strName) +{ + if (m_iPackageLoadedRef < 0) + return; + + lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_loaded] + lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"] + lua_rawget(L, -2); // stack: [tbl_loaded,varPkg] + lua_remove(L, -2); // stack: [varPkg] +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::LoadLuaLib +// +// Load a Lua lib of a given name +// +/////////////////////////////////////////////////////////////// +bool CLuaMain::LoadLuaLib(lua_State* L, SString strName, SString& strError) +{ + SString strPath = strName; + // Name format shouldn't include slashes. Subdirs are dots. + ReplaceOccurrencesInString(strPath, "\\", ""); + ReplaceOccurrencesInString(strPath, "/", ""); + ReplaceOccurrencesInString(strPath, ".", "/"); + +#ifdef MTA_CLIENT + SString strResPath = m_pResource->GetResourceDirectoryPath(ACCESS_PUBLIC, ""); +#else + SString strResPath = m_pResource->IsResourceZip() ? m_pResource->GetResourceCacheDirectoryPath() : m_pResource->GetResourceDirectoryPath(); +#endif + + std::vector buffer; + // Try /?.lua + SString strFilePath = PathJoin(strResPath, strPath + ".lua"); + if (FileExists(strFilePath)) + FileLoad(strFilePath, buffer); + else + { + // Don't use a format string for safety, so we construct the error by hand + strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t The specified module could not be found"; + + // Try /?/init.lua + strFilePath = PathJoin(strResPath, strPath, "init.lua"); + if (FileExists(strFilePath)) + FileLoad(strFilePath, buffer); + else + { + strError += "\n"; + strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t The specified module could not be found"; + return false; + } + } + + if (buffer.size() > 0) + { + int luaSavedTop = lua_gettop(L); + LoadScriptFromBuffer(&buffer.at(0), buffer.size(), strFilePath.c_str(), false); + // Only keep the first return value + if (lua_gettop(L) > luaSavedTop) + lua_settop(L, luaSavedTop + 1); + + if (lua_type(L, -1) == LUA_TNIL) + { + strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t Module didn't return a value"; + return false; + } + + SetPackage(L, strName); // Store our package into package.loaded + return true; + } + else + strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t Error loading script file"; + + return false; +} From 4f299a131cfea0b9bc1deea7ef66513b94db2ffd Mon Sep 17 00:00:00 2001 From: CrosRoad95 Date: Wed, 20 Feb 2019 19:33:14 +0100 Subject: [PATCH 09/10] Improved warnings for lua-package (#683) * Improved warnings Previous looks like shit * fix conflicts * fix conflicts * Fix indentation * Tweak location text * fix path * fixed `nil` return in require * Fix code formatting --- Client/mods/deathmatch/logic/lua/CLuaMain.h | 8 ++-- Server/mods/deathmatch/logic/lua/CLuaMain.cpp | 8 ++-- Server/mods/deathmatch/logic/lua/CLuaMain.h | 10 ++--- .../deathmatch/logic/lua/CLuaMain.Shared.cpp | 16 +++++--- .../deathmatch/logic/luadefs/CLuaUtilDefs.cpp | 11 +++++- Shared/sdk/SharedUtil.Misc.h | 2 + Shared/sdk/SharedUtil.Misc.hpp | 37 +++++++++++++++++++ 7 files changed, 71 insertions(+), 21 deletions(-) diff --git a/Client/mods/deathmatch/logic/lua/CLuaMain.h b/Client/mods/deathmatch/logic/lua/CLuaMain.h index 976d8791d47..5729f6d2972 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaMain.h +++ b/Client/mods/deathmatch/logic/lua/CLuaMain.h @@ -78,10 +78,10 @@ class CLuaMain //: public CClient bool IsOOPEnabled() { return m_bEnableOOP; } - void InitPackageStorage(lua_State* L); // Create a psuedo package.loaded table - void GetPackage(lua_State* L, SString& strName); // Push the package value to the top of the stack - void SetPackage(lua_State* L, SString& strName); // Set the package to the value at the top of the stack - bool LoadLuaLib(lua_State* L, SString strName, SString& strError); // Load a lua library of a given name + void InitPackageStorage(lua_State* L); // Create a psuedo package.loaded table + void GetPackage(lua_State* L, SString& strName); // Push the package value to the top of the stack + void SetPackage(lua_State* L, SString& strName); // Set the package to the value at the top of the stack + bool LoadLuaLib(lua_State* L, SString strName, SString& strError, bool& bEmpty); // Load a lua library of a given name private: void InitSecurity(); diff --git a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp index 30128498330..74539286e2a 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp @@ -686,7 +686,7 @@ bool CLuaMain::LoadClib(lua_State* L, SString strName, SString& strError) if (!FileExists(strPath)) { - strError += "error loading module " + strName + " from file " + strPath + ":\n\t The specified module could not be found"; + strError += "#3: " + ConformPath(strPath, "modules/"); return false; } @@ -696,14 +696,14 @@ bool CLuaMain::LoadClib(lua_State* L, SString strName, SString& strError) !g_pGame->GetACLManager()->CanObjectUseRight(m_pResource->GetName().c_str(), CAccessControlListGroupObject::OBJECT_TYPE_RESOURCE, strName.c_str(), CAccessControlListRight::RIGHT_TYPE_MODULE, false)) { - strError += "error loading module " + strName + " from file " + strPath + ":\n\t ACL access denied. Grant \"module." + strName + - "\" right to resource " + m_pResource->GetName(); + strError = "could not load module '" + strName + "' from file " + ConformPath(strPath, "modules/") + ":\n\t ACL access denied. Grant \"module." + + strName + "\" right to resource " + m_pResource->GetName(); return false; } if (!luaL_loader_C(L, strName.c_str(), strPath.c_str()) || lua_type(L, -1) == LUA_TNIL) { - strError += "error loading module " + strName + " from file " + strPath + ":\n\t Failed to load module"; + strError = "failed to load module '" + strName + "' from file " + ConformPath(strPath, "modules/"); return false; } diff --git a/Server/mods/deathmatch/logic/lua/CLuaMain.h b/Server/mods/deathmatch/logic/lua/CLuaMain.h index 419a1cd2523..35c99d5e315 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaMain.h +++ b/Server/mods/deathmatch/logic/lua/CLuaMain.h @@ -108,11 +108,11 @@ class CLuaMain //: public CClient static int LuaLoadBuffer(lua_State* L, const char* buff, size_t sz, const char* name); static int OnUndump(const char* p, size_t n); - void InitPackageStorage(lua_State* L); // Create a psuedo package.loaded table - void GetPackage(lua_State* L, SString& strName); // Push the package value to the top of the stack - void SetPackage(lua_State* L, SString& strName); // Set the package to the value at the top of the stack - bool LoadLuaLib(lua_State* L, SString strName, SString& strError); // Load a lua library of a given name - bool LoadClib(lua_State* L, SString strName, SString& strError); // Load a C Lib of a given name + void InitPackageStorage(lua_State* L); // Create a psuedo package.loaded table + void GetPackage(lua_State* L, SString& strName); // Push the package value to the top of the stack + void SetPackage(lua_State* L, SString& strName); // Set the package to the value at the top of the stack + bool LoadLuaLib(lua_State* L, SString strName, SString& strError, bool& bEmpty); // Load a lua library of a given name + bool LoadClib(lua_State* L, SString strName, SString& strError); // Load a C Lib of a given name private: void InitSecurity(); diff --git a/Shared/mods/deathmatch/logic/lua/CLuaMain.Shared.cpp b/Shared/mods/deathmatch/logic/lua/CLuaMain.Shared.cpp index 1b292c051f5..455d2a624ec 100644 --- a/Shared/mods/deathmatch/logic/lua/CLuaMain.Shared.cpp +++ b/Shared/mods/deathmatch/logic/lua/CLuaMain.Shared.cpp @@ -91,7 +91,7 @@ void CLuaMain::GetPackage(lua_State* L, SString& strName) // Load a Lua lib of a given name // /////////////////////////////////////////////////////////////// -bool CLuaMain::LoadLuaLib(lua_State* L, SString strName, SString& strError) +bool CLuaMain::LoadLuaLib(lua_State* L, SString strName, SString& strError, bool& bEmpty) { SString strPath = strName; // Name format shouldn't include slashes. Subdirs are dots. @@ -106,6 +106,7 @@ bool CLuaMain::LoadLuaLib(lua_State* L, SString strName, SString& strError) #endif std::vector buffer; + strError = "error loading module '" + strName + "' from locations:\n\t"; // Try /?.lua SString strFilePath = PathJoin(strResPath, strPath + ".lua"); if (FileExists(strFilePath)) @@ -113,7 +114,7 @@ bool CLuaMain::LoadLuaLib(lua_State* L, SString strName, SString& strError) else { // Don't use a format string for safety, so we construct the error by hand - strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t The specified module could not be found"; + strError += "#1: " + ConformPath(strFilePath, "resources/") + "\n\t"; // Try /?/init.lua strFilePath = PathJoin(strResPath, strPath, "init.lua"); @@ -121,8 +122,7 @@ bool CLuaMain::LoadLuaLib(lua_State* L, SString strName, SString& strError) FileLoad(strFilePath, buffer); else { - strError += "\n"; - strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t The specified module could not be found"; + strError += "#2: " + ConformPath(strFilePath, "resources/") + "\n\t"; return false; } } @@ -137,7 +137,8 @@ bool CLuaMain::LoadLuaLib(lua_State* L, SString strName, SString& strError) if (lua_type(L, -1) == LUA_TNIL) { - strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t Module didn't return a value"; + strError = "module '" + strName + "' in location " + ConformPath(strFilePath, "resources/") + " didn't return a value."; + bEmpty = true; return false; } @@ -145,7 +146,10 @@ bool CLuaMain::LoadLuaLib(lua_State* L, SString strName, SString& strError) return true; } else - strError += "error loading module " + strName + " from file " + strFilePath + ":\n\t Error loading script file"; + { + strError = "could not load module '" + strName + "' from file " + ConformPath(strFilePath, "resources/") + ": File is empty."; + bEmpty = true; + } return false; } diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp index c4b14e5e3d1..c2d537eaacc 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp @@ -732,6 +732,7 @@ int CLuaUtilDefs::Require(lua_State* luaVM) if (!argStream.HasErrors()) { SString strError = ""; + bool bEmpty = false; // Check if package exists already, if so load it // stack: ["moduleName"] pLuaMain->GetPackage(luaVM, strMod); // stack: ["moduleName",pkgModule/nil] @@ -740,10 +741,16 @@ int CLuaUtilDefs::Require(lua_State* luaVM) lua_pop(luaVM, 1); // stack: ["moduleName"] // Check whether the appropriate pure lua module exists - if (pLuaMain->LoadLuaLib(luaVM, strMod, strError)) // stack: ["moduleName",pkgLuaMod/nil] + if (pLuaMain->LoadLuaLib(luaVM, strMod, strError, bEmpty)) // stack: ["moduleName",pkgLuaMod/nil] return 1; + + if (bEmpty) + { + m_pScriptDebugging->LogCustom(luaVM, strError); + lua_pushboolean(luaVM, false); + return 1; + } #ifndef MTA_CLIENT - strError += "\n"; // Check if a C library exists if (pLuaMain->LoadClib(luaVM, strMod, strError)) // stack: ["moduleName",fncModule/nil] return 1; diff --git a/Shared/sdk/SharedUtil.Misc.h b/Shared/sdk/SharedUtil.Misc.h index b6edd31699f..2b4807ac7e7 100644 --- a/Shared/sdk/SharedUtil.Misc.h +++ b/Shared/sdk/SharedUtil.Misc.h @@ -209,6 +209,8 @@ namespace SharedUtil // SString ConformResourcePath(const char* szRes, bool bConvertToUnixPathSep = false); + SString ConformPath(const char* szRes, SString szPath, bool bConvertToUnixPathSep = false); + // // string stuff // diff --git a/Shared/sdk/SharedUtil.Misc.hpp b/Shared/sdk/SharedUtil.Misc.hpp index 45311dc544c..5b707775553 100644 --- a/Shared/sdk/SharedUtil.Misc.hpp +++ b/Shared/sdk/SharedUtil.Misc.hpp @@ -1448,6 +1448,43 @@ SString SharedUtil::ConformResourcePath(const char* szRes, bool bConvertToUnixPa return strText; } +SString SharedUtil::ConformPath(const char* szRes, SString szPath, bool bConvertToUnixPathSep) +{ + SString strText = szRes ? szRes : ""; + char cPathSep; + + // Handle which path sep char +#ifdef WIN32 + if (!bConvertToUnixPathSep) + { + cPathSep = '\\'; + szPath = szPath.Replace("/", "\\"); + strText = strText.Replace("/", "\\"); + } + else +#endif + { + cPathSep = '/'; + szPath = szPath.Replace("\\", "/"); + strText = strText.Replace("\\", "/"); + } + + // Remove up to first occurrence + int iPos = strText.find(szPath); + if (iPos >= 0) + return SString("%s%s", szPath.c_str(), strText.substr(iPos + szPath.length()).c_str()); + + if (strText.substr(0, 3) == "...") + { + // Remove up to first '/' + int iPos = strText.find(cPathSep); + if (iPos >= 0) + return SString("%s%s", szPath.c_str(), strText.substr(iPos + 1).c_str()); + } + + return strText; +} + namespace SharedUtil { CArgMap::CArgMap(const SString& strArgSep, const SString& strPartsSep, const SString& strExtraDisallowedChars) From 7333c22186b4ca039e72118fc513c9c72fdb43fd Mon Sep 17 00:00:00 2001 From: Patrik Juvonen Date: Wed, 1 May 2019 12:49:45 +0300 Subject: [PATCH 10/10] fix google-breakpad refresh_binaries.bat line endings --- .../src/tools/windows/refresh_binaries.bat | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/vendor/google-breakpad/src/tools/windows/refresh_binaries.bat b/vendor/google-breakpad/src/tools/windows/refresh_binaries.bat index d881ae64b53..52828c86ca4 100644 --- a/vendor/google-breakpad/src/tools/windows/refresh_binaries.bat +++ b/vendor/google-breakpad/src/tools/windows/refresh_binaries.bat @@ -1,27 +1,27 @@ -REM This batch file is meant to facilitate regenerating prebuilt binaries for -REM the Windows tools. -REM You MUST run it from a Visual Studio xxxx Command Prompt. To do this, -REM navigate to: -REM -REM Start->Programs->Microsoft Visual Studio XXXX->Tools-> -REM Visual Studio Command Prompt -REM -REM Then run this batch file. It performs an SVN update, edits the -REM README.binaries file to contain -REM the revision number, and builds the tools. You must run 'svn commit' to -REM commit the pending edits to the repository. - -pushd %~dp0\..\..\ -call svn update --accept postpone -cd tools\windows -devenv symupload\symupload.vcproj /rebuild Release -copy symupload\Release\symupload.exe binaries\ -REM switch back to top level so that 'svn info' displays useful information. -cd ..\..\ -echo This checkin of the binaries was created by refresh_binaries.bat. > %TEMP%\checkin.txt -echo Date: %DATE% %TIME% >> %TEMP%\checkin.txt -echo Repository information (output of 'svn info') follows: >> %TEMP%\checkin.txt -call svn info >> %TEMP%\checkin.txt -echo Done! -echo type 'svn commit -F %%TEMP%%\checkin.txt' to commit. -popd +REM This batch file is meant to facilitate regenerating prebuilt binaries for +REM the Windows tools. +REM You MUST run it from a Visual Studio xxxx Command Prompt. To do this, +REM navigate to: +REM +REM Start->Programs->Microsoft Visual Studio XXXX->Tools-> +REM Visual Studio Command Prompt +REM +REM Then run this batch file. It performs an SVN update, edits the +REM README.binaries file to contain +REM the revision number, and builds the tools. You must run 'svn commit' to +REM commit the pending edits to the repository. + +pushd %~dp0\..\..\ +call svn update --accept postpone +cd tools\windows +devenv symupload\symupload.vcproj /rebuild Release +copy symupload\Release\symupload.exe binaries\ +REM switch back to top level so that 'svn info' displays useful information. +cd ..\..\ +echo This checkin of the binaries was created by refresh_binaries.bat. > %TEMP%\checkin.txt +echo Date: %DATE% %TIME% >> %TEMP%\checkin.txt +echo Repository information (output of 'svn info') follows: >> %TEMP%\checkin.txt +call svn info >> %TEMP%\checkin.txt +echo Done! +echo type 'svn commit -F %%TEMP%%\checkin.txt' to commit. +popd