From 6e7c6ae56792add3f8d701eca7d144d96ed19458 Mon Sep 17 00:00:00 2001 From: dshaligram Date: Thu, 21 Jun 2007 11:19:35 +0000 Subject: Added support for limiting memory used by the Lua interpreter. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1613 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/AppHdr.h | 18 ++++++------ crawl-ref/source/acr.cc | 3 +- crawl-ref/source/clua.cc | 71 +++++++++++++++++++++++++++++++++++++---------- crawl-ref/source/clua.h | 7 +++++ crawl-ref/source/delay.cc | 2 +- crawl-ref/source/ouch.cc | 2 +- 6 files changed, 78 insertions(+), 25 deletions(-) (limited to 'crawl-ref') diff --git a/crawl-ref/source/AppHdr.h b/crawl-ref/source/AppHdr.h index a42d8141a9..a96eb04111 100644 --- a/crawl-ref/source/AppHdr.h +++ b/crawl-ref/source/AppHdr.h @@ -43,17 +43,19 @@ #ifndef APPHDR_H #define APPHDR_H -#if defined(GCC) -# define HASH_CONTAINER_NS __gnu_cxx -# define HASH_CONTAINERS -#endif - -// Uncomment to enable the Crawl Lua bindings. You can also set this in your -// makefile by adding -DCLUA_BINDINGS to the CFLAGS line (this is preferred to -// editing AppHdr.h directly). +// Uncomment to enable the Crawl Lua bindings. You can also set this +// in your makefile by adding -DCLUA_BINDINGS to the CFLAGS line (this +// is preferred to editing AppHdr.h directly). // // #define CLUA_BINDINGS +// The maximum memory that the user-script Lua interpreter can +// allocate, in kilobytes. This limit is enforced to prevent +// badly-written or malicious user scripts from consuming too much +// memory. +// +#define CLUA_MAX_MEMORY_USE (2 * 1024) + // Enable support for Unicode character glyphs. Note that this needs // to be accompanied by changes to linker and compiler options and may // not be available on all platforms. In most cases you want to set diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 43d2a7933d..9f01b74414 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -297,7 +297,8 @@ int main( int argc, char *argv[] ) simple_god_message( " says: Go forth and aid the weak!" ); break; case GOD_BEOGH: - simple_god_message( " says: Let disbelievers drown in blood!" ); + simple_god_message( + " says: Drown the unbelievers in a sea of blood!"); break; default: break; diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc index fb36672fe9..d6ddf14a0b 100644 --- a/crawl-ref/source/clua.cc +++ b/crawl-ref/source/clua.cc @@ -11,6 +11,7 @@ #include "chardump.h" #include "cio.h" #include "delay.h" +#include "files.h" #include "food.h" #include "invent.h" #include "initfile.h" @@ -31,15 +32,7 @@ #include "stuff.h" #include - -#ifdef HASH_CONTAINERS -# include -# define CHMAP HASH_CONTAINER_NS::hash_map -#else -# include -# define CHMAP std::map -#endif - +#include #include #define BUGGY_PCALL_ERROR "667: Malformed response to guarded pcall." @@ -57,23 +50,28 @@ else static void clua_throttle_hook(lua_State *, lua_Debug *); +static void *clua_allocator(void *ud, void *ptr, size_t osize, size_t nsize); static int clua_guarded_pcall(lua_State *); +static int clua_panic(lua_State *); CLua clua(true); const int CLua::MAX_THROTTLE_SLEEPS; CLua::CLua(bool managed) - : error(), managed_vm(managed), throttle_unit_lines(10000), + : error(), managed_vm(managed), shutting_down(false), + throttle_unit_lines(10000), throttle_sleep_ms(0), throttle_sleep_start(2), throttle_sleep_end(800), n_throttle_sleeps(0), mixed_call_depth(0), lua_call_depth(0), max_mixed_call_depth(8), - max_lua_call_depth(100), _state(NULL), sourced_files(), uniqindex(0L) + max_lua_call_depth(100), memory_used(0), + _state(NULL), sourced_files(), uniqindex(0L) { } CLua::~CLua() { + shutting_down = true; if (_state) lua_close(_state); } @@ -546,9 +544,12 @@ void CLua::init_lua() if (_state) return; - _state = lua_open(); + _state = managed_vm? lua_newstate(clua_allocator, this) : luaL_newstate(); if (!_state) return; + + lua_atpanic(_state, clua_panic); + luaopen_base(_state); luaopen_string(_state); luaopen_table(_state); @@ -2168,7 +2169,7 @@ void lua_open_monsters(lua_State *ls) #define PATTERN_FLUSH_CEILING 100 -typedef CHMAP pattern_map; +typedef std::map pattern_map; static pattern_map pattern_cache; static text_pattern &get_text_pattern(const std::string &s, bool checkcase) @@ -2181,7 +2182,7 @@ static text_pattern &get_text_pattern(const std::string &s, bool checkcase) pattern_cache.clear(); pattern_cache[s] = text_pattern(s, !checkcase); - return pattern_cache[s]; + return (pattern_cache[s]); } static int lua_pmatch(lua_State *ls) @@ -2380,6 +2381,48 @@ bool lua_text_pattern::translate() const lua_call_throttle::lua_clua_map lua_call_throttle::lua_map; +// A panic function for the Lua interpreter, usually called when it +// runs out of memory when trying to load a file or a chunk of Lua from +// an unprotected Lua op. The only cases of unprotected Lua loads are +// loads of Lua code from .crawlrc, which is read at start of game. +// +// If there's an inordinately large .crawlrc (we're talking seriously +// massive here) that wants more memory than we're willing to give +// Lua, then the game will save and exit until the .crawlrc is fixed. +// +// Lua can also run out of memory during protected script execution, +// such as when running a macro or some other game hook, but in such +// cases the Lua interpreter will throw an exception instead of +// panicking. +// +static int clua_panic(lua_State *ls) +{ + if (crawl_state.need_save && !crawl_state.saving_game + && !crawl_state.updating_scores) + { + save_game(true); + } + return (0); +} + +static void *clua_allocator(void *ud, void *ptr, size_t osize, size_t nsize) +{ + CLua *cl = static_cast( ud ); + cl->memory_used += nsize - osize; + + if (nsize > osize && cl->memory_used >= CLUA_MAX_MEMORY_USE * 1024 + && cl->mixed_call_depth) + return (NULL); + + if (!nsize) + { + free(ptr); + return (NULL); + } + else + return (realloc(ptr, nsize)); +} + static void clua_throttle_hook(lua_State *ls, lua_Debug *dbg) { CLua *lua = lua_call_throttle::find_clua(ls); diff --git a/crawl-ref/source/clua.h b/crawl-ref/source/clua.h index af6196f826..a060923da7 100644 --- a/crawl-ref/source/clua.h +++ b/crawl-ref/source/clua.h @@ -18,6 +18,10 @@ extern "C" { #include "libutil.h" #include "externs.h" +#ifndef CLUA_MAX_MEMORY_USE +#define CLUA_MAX_MEMORY_USE (6 * 1024) +#endif + class CLua; class lua_call_throttle { @@ -76,6 +80,7 @@ public: // If managed_vm is set, we have to take steps to control badly-behaved // scripts. bool managed_vm; + bool shutting_down; int throttle_unit_lines; int throttle_sleep_ms; int throttle_sleep_start, throttle_sleep_end; @@ -85,6 +90,8 @@ public: int max_mixed_call_depth; int max_lua_call_depth; + long memory_used; + static const int MAX_THROTTLE_SLEEPS = 100; private: diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc index a993b30b71..f8f5806705 100644 --- a/crawl-ref/source/delay.cc +++ b/crawl-ref/source/delay.cc @@ -873,7 +873,7 @@ void run_macro(const char *macroname) if (!clua.callbooleanfn(false, "c_macro", "s", macroname)) { if (clua.error.length()) - mpr(clua.error.c_str()); + mprf(MSGCH_WARN, "Lua error: %s", clua.error.c_str()); stop_delay(); } diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc index 77b3ee92d3..06c3b9fefb 100644 --- a/crawl-ref/source/ouch.cc +++ b/crawl-ref/source/ouch.cc @@ -736,7 +736,7 @@ void ouch( int dam, int death_source, kill_method_type death_type, interrupt_activity( AI_HP_LOSS, &hpl ); if (you.deaths_door && death_type != KILLED_BY_LAVA - && death_type != KILLED_BY_WATER) + && death_type != KILLED_BY_WATER) { return; } -- cgit v1.2.3-54-g00ecf