s_base.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "cpp_api/s_base.h"
  17. #include "cpp_api/s_internal.h"
  18. #include "cpp_api/s_security.h"
  19. #include "lua_api/l_object.h"
  20. #include "common/c_converter.h"
  21. #include "serverobject.h"
  22. #include "filesys.h"
  23. #include "mods.h"
  24. #include "porting.h"
  25. #include "util/string.h"
  26. #include "server.h"
  27. #ifndef SERVER
  28. #include "client.h"
  29. #endif
  30. extern "C" {
  31. #include "lualib.h"
  32. #if USE_LUAJIT
  33. #include "luajit.h"
  34. #endif
  35. }
  36. #include <stdio.h>
  37. #include <cstdarg>
  38. #include "script/common/c_content.h"
  39. #include <sstream>
  40. class ModNameStorer
  41. {
  42. private:
  43. lua_State *L;
  44. public:
  45. ModNameStorer(lua_State *L_, const std::string &mod_name):
  46. L(L_)
  47. {
  48. // Store current mod name in registry
  49. lua_pushstring(L, mod_name.c_str());
  50. lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
  51. }
  52. ~ModNameStorer()
  53. {
  54. // Clear current mod name from registry
  55. lua_pushnil(L);
  56. lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
  57. }
  58. };
  59. /*
  60. ScriptApiBase
  61. */
  62. ScriptApiBase::ScriptApiBase()
  63. {
  64. #ifdef SCRIPTAPI_LOCK_DEBUG
  65. m_lock_recursion_count = 0;
  66. #endif
  67. m_luastack = luaL_newstate();
  68. FATAL_ERROR_IF(!m_luastack, "luaL_newstate() failed");
  69. lua_atpanic(m_luastack, &luaPanic);
  70. luaL_openlibs(m_luastack);
  71. // Make the ScriptApiBase* accessible to ModApiBase
  72. lua_pushlightuserdata(m_luastack, this);
  73. lua_rawseti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI);
  74. // Add and save an error handler
  75. lua_getglobal(m_luastack, "debug");
  76. lua_getfield(m_luastack, -1, "traceback");
  77. lua_rawseti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_BACKTRACE);
  78. lua_pop(m_luastack, 1); // pop debug
  79. // If we are using LuaJIT add a C++ wrapper function to catch
  80. // exceptions thrown in Lua -> C++ calls
  81. #if USE_LUAJIT
  82. lua_pushlightuserdata(m_luastack, (void*) script_exception_wrapper);
  83. luaJIT_setmode(m_luastack, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON);
  84. lua_pop(m_luastack, 1);
  85. #endif
  86. // Add basic globals
  87. lua_newtable(m_luastack);
  88. lua_setglobal(m_luastack, "core");
  89. lua_pushstring(m_luastack, DIR_DELIM);
  90. lua_setglobal(m_luastack, "DIR_DELIM");
  91. lua_pushstring(m_luastack, porting::getPlatformName());
  92. lua_setglobal(m_luastack, "PLATFORM");
  93. }
  94. ScriptApiBase::~ScriptApiBase()
  95. {
  96. lua_close(m_luastack);
  97. }
  98. int ScriptApiBase::luaPanic(lua_State *L)
  99. {
  100. std::ostringstream oss;
  101. oss << "LUA PANIC: unprotected error in call to Lua API ("
  102. << lua_tostring(L, -1) << ")";
  103. FATAL_ERROR(oss.str().c_str());
  104. // NOTREACHED
  105. return 0;
  106. }
  107. void ScriptApiBase::loadMod(const std::string &script_path,
  108. const std::string &mod_name)
  109. {
  110. ModNameStorer mod_name_storer(getStack(), mod_name);
  111. loadScript(script_path);
  112. }
  113. void ScriptApiBase::loadScript(const std::string &script_path)
  114. {
  115. verbosestream << "Loading and running script from " << script_path << std::endl;
  116. lua_State *L = getStack();
  117. int error_handler = PUSH_ERROR_HANDLER(L);
  118. bool ok;
  119. if (m_secure) {
  120. ok = ScriptApiSecurity::safeLoadFile(L, script_path.c_str());
  121. } else {
  122. ok = !luaL_loadfile(L, script_path.c_str());
  123. }
  124. ok = ok && !lua_pcall(L, 0, 0, error_handler);
  125. if (!ok) {
  126. std::string error_msg = lua_tostring(L, -1);
  127. lua_pop(L, 2); // Pop error message and error handler
  128. throw ModError("Failed to load and run script from " +
  129. script_path + ":\n" + error_msg);
  130. }
  131. lua_pop(L, 1); // Pop error handler
  132. }
  133. #ifndef SERVER
  134. void ScriptApiBase::loadModFromMemory(const std::string &mod_name)
  135. {
  136. ModNameStorer mod_name_storer(getStack(), mod_name);
  137. const std::string *init_filename = getClient()->getModFile(mod_name + ":init.lua");
  138. const std::string display_filename = mod_name + ":init.lua";
  139. if(init_filename == NULL)
  140. throw ModError("Mod:\"" + mod_name + "\" lacks init.lua");
  141. verbosestream << "Loading and running script " << display_filename << std::endl;
  142. lua_State *L = getStack();
  143. int error_handler = PUSH_ERROR_HANDLER(L);
  144. bool ok = ScriptApiSecurity::safeLoadFile(L, init_filename->c_str(), display_filename.c_str());
  145. if (ok)
  146. ok = !lua_pcall(L, 0, 0, error_handler);
  147. if (!ok) {
  148. std::string error_msg = luaL_checkstring(L, -1);
  149. lua_pop(L, 2); // Pop error message and error handler
  150. throw ModError("Failed to load and run mod \"" +
  151. mod_name + "\":\n" + error_msg);
  152. }
  153. lua_pop(L, 1); // Pop error handler
  154. }
  155. #endif
  156. // Push the list of callbacks (a lua table).
  157. // Then push nargs arguments.
  158. // Then call this function, which
  159. // - runs the callbacks
  160. // - replaces the table and arguments with the return value,
  161. // computed depending on mode
  162. // This function must only be called with scriptlock held (i.e. inside of a
  163. // code block with SCRIPTAPI_PRECHECKHEADER declared)
  164. void ScriptApiBase::runCallbacksRaw(int nargs,
  165. RunCallbacksMode mode, const char *fxn)
  166. {
  167. #ifdef SCRIPTAPI_LOCK_DEBUG
  168. assert(m_lock_recursion_count > 0);
  169. #endif
  170. lua_State *L = getStack();
  171. FATAL_ERROR_IF(lua_gettop(L) < nargs + 1, "Not enough arguments");
  172. // Insert error handler
  173. PUSH_ERROR_HANDLER(L);
  174. int error_handler = lua_gettop(L) - nargs - 1;
  175. lua_insert(L, error_handler);
  176. // Insert run_callbacks between error handler and table
  177. lua_getglobal(L, "core");
  178. lua_getfield(L, -1, "run_callbacks");
  179. lua_remove(L, -2);
  180. lua_insert(L, error_handler + 1);
  181. // Insert mode after table
  182. lua_pushnumber(L, (int)mode);
  183. lua_insert(L, error_handler + 3);
  184. // Stack now looks like this:
  185. // ... <error handler> <run_callbacks> <table> <mode> <arg#1> <arg#2> ... <arg#n>
  186. int result = lua_pcall(L, nargs + 2, 1, error_handler);
  187. if (result != 0)
  188. scriptError(result, fxn);
  189. lua_remove(L, error_handler);
  190. }
  191. void ScriptApiBase::realityCheck()
  192. {
  193. int top = lua_gettop(m_luastack);
  194. if (top >= 30) {
  195. dstream << "Stack is over 30:" << std::endl;
  196. stackDump(dstream);
  197. std::string traceback = script_get_backtrace(m_luastack);
  198. throw LuaError("Stack is over 30 (reality check)\n" + traceback);
  199. }
  200. }
  201. void ScriptApiBase::scriptError(int result, const char *fxn)
  202. {
  203. script_error(getStack(), result, m_last_run_mod.c_str(), fxn);
  204. }
  205. void ScriptApiBase::stackDump(std::ostream &o)
  206. {
  207. int top = lua_gettop(m_luastack);
  208. for (int i = 1; i <= top; i++) { /* repeat for each level */
  209. int t = lua_type(m_luastack, i);
  210. switch (t) {
  211. case LUA_TSTRING: /* strings */
  212. o << "\"" << lua_tostring(m_luastack, i) << "\"";
  213. break;
  214. case LUA_TBOOLEAN: /* booleans */
  215. o << (lua_toboolean(m_luastack, i) ? "true" : "false");
  216. break;
  217. case LUA_TNUMBER: /* numbers */ {
  218. char buf[10];
  219. snprintf(buf, 10, "%lf", lua_tonumber(m_luastack, i));
  220. o << buf;
  221. break;
  222. }
  223. default: /* other values */
  224. o << lua_typename(m_luastack, t);
  225. break;
  226. }
  227. o << " ";
  228. }
  229. o << std::endl;
  230. }
  231. void ScriptApiBase::setOriginDirect(const char *origin)
  232. {
  233. m_last_run_mod = origin ? origin : "??";
  234. }
  235. void ScriptApiBase::setOriginFromTableRaw(int index, const char *fxn)
  236. {
  237. #ifdef SCRIPTAPI_DEBUG
  238. lua_State *L = getStack();
  239. m_last_run_mod = lua_istable(L, index) ?
  240. getstringfield_default(L, index, "mod_origin", "") : "";
  241. //printf(">>>> running %s for mod: %s\n", fxn, m_last_run_mod.c_str());
  242. #endif
  243. }
  244. void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
  245. {
  246. SCRIPTAPI_PRECHECKHEADER
  247. //infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
  248. // Create object on stack
  249. ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
  250. int object = lua_gettop(L);
  251. // Get core.object_refs table
  252. lua_getglobal(L, "core");
  253. lua_getfield(L, -1, "object_refs");
  254. luaL_checktype(L, -1, LUA_TTABLE);
  255. int objectstable = lua_gettop(L);
  256. // object_refs[id] = object
  257. lua_pushnumber(L, cobj->getId()); // Push id
  258. lua_pushvalue(L, object); // Copy object to top of stack
  259. lua_settable(L, objectstable);
  260. }
  261. void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
  262. {
  263. SCRIPTAPI_PRECHECKHEADER
  264. //infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
  265. // Get core.object_refs table
  266. lua_getglobal(L, "core");
  267. lua_getfield(L, -1, "object_refs");
  268. luaL_checktype(L, -1, LUA_TTABLE);
  269. int objectstable = lua_gettop(L);
  270. // Get object_refs[id]
  271. lua_pushnumber(L, cobj->getId()); // Push id
  272. lua_gettable(L, objectstable);
  273. // Set object reference to NULL
  274. ObjectRef::set_null(L);
  275. lua_pop(L, 1); // pop object
  276. // Set object_refs[id] = nil
  277. lua_pushnumber(L, cobj->getId()); // Push id
  278. lua_pushnil(L);
  279. lua_settable(L, objectstable);
  280. }
  281. // Creates a new anonymous reference if cobj=NULL or id=0
  282. void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
  283. ServerActiveObject *cobj)
  284. {
  285. if (cobj == NULL || cobj->getId() == 0) {
  286. ObjectRef::create(L, cobj);
  287. } else {
  288. push_objectRef(L, cobj->getId());
  289. }
  290. }
  291. Server* ScriptApiBase::getServer()
  292. {
  293. return dynamic_cast<Server *>(m_gamedef);
  294. }
  295. #ifndef SERVER
  296. Client* ScriptApiBase::getClient()
  297. {
  298. return dynamic_cast<Client *>(m_gamedef);
  299. }
  300. #endif