diff options
-rw-r--r-- | src/lapi.js | 14 | ||||
-rw-r--r-- | src/ldo.js | 27 | ||||
-rw-r--r-- | src/lstate.js | 3 |
3 files changed, 43 insertions, 1 deletions
diff --git a/src/lapi.js b/src/lapi.js index cea0568..79c666c 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -91,8 +91,20 @@ const index2addr_ = function(L, idx) { }; const lua_checkstack = function(L, n) { + let res; let ci = L.ci; - let res = L.stack.length < luaconf.LUAI_MAXSTACK; + assert(n >= 0, "negative 'n'"); + if (L.stack.length - L.top > n) /* stack large enough? */ + res = true; + else { /* no; need to grow stack */ + let inuse = L.top + lstate.EXTRA_STACK; + if (inuse > luaconf.LUAI_MAXSTACK - n) /* can grow without overflow? */ + res = false; /* no */ + else { /* try to grow stack */ + ldo.luaD_growstack(L, n); + res = true; + } + } if (res && ci.top < L.top + n) ci.top = L.top + n; /* adjust frame top */ @@ -13,6 +13,7 @@ const lparser = require('./lparser.js'); const lstate = require('./lstate.js'); const lstring = require('./lstring.js'); const ltm = require('./ltm.js'); +const luaconf = require('./luaconf.js'); const lundump = require('./lundump.js'); const lvm = require('./lvm.js'); const lzio = require('./lzio.js'); @@ -38,6 +39,30 @@ const seterrorobj = function(L, errcode, oldtop) { L.top = oldtop + 1; }; +const ERRORSTACKSIZE = luaconf.LUAI_MAXSTACK + 200; + +const luaD_reallocstack = function(L, newsize) { + L.stack.length = newsize; +}; + +const luaD_growstack = function(L, n) { + let size = L.stack.length; + if (size > luaconf.LUAI_MAXSTACK) + luaD_throw(L, TS.LUA_ERRERR); + else { + let needed = L.top + n + lstate.EXTRA_STACK; + let newsize = 2 * size; + if (newsize > luaconf.LUAI_MAXSTACK) newsize = luaconf.LUAI_MAXSTACK; + if (newsize < needed) newsize = needed; + if (newsize > luaconf.LUAI_MAXSTACK) { /* stack overflow? */ + luaD_reallocstack(L, ERRORSTACKSIZE); + ldebug.luaG_runerror(L, "stack overflow"); + } + else + luaD_reallocstack(L, newsize); + } +}; + /* ** Prepares a function call: checks the stack, creates a new CallInfo ** entry, fills in the relevant information, calls hook if needed. @@ -594,12 +619,14 @@ module.exports.SParser = SParser; module.exports.adjust_varargs = adjust_varargs; module.exports.luaD_call = luaD_call; module.exports.luaD_callnoyield = luaD_callnoyield; +module.exports.luaD_growstack = luaD_growstack; module.exports.luaD_hook = luaD_hook; module.exports.luaD_pcall = luaD_pcall; module.exports.luaD_poscall = luaD_poscall; module.exports.luaD_precall = luaD_precall; module.exports.luaD_protectedparser = luaD_protectedparser; module.exports.luaD_rawrunprotected = luaD_rawrunprotected; +module.exports.luaD_reallocstack = luaD_reallocstack; module.exports.luaD_throw = luaD_throw; module.exports.lua_isyieldable = lua_isyieldable; module.exports.lua_resume = lua_resume; diff --git a/src/lstate.js b/src/lstate.js index 5a65c12..d1789e8 100644 --- a/src/lstate.js +++ b/src/lstate.js @@ -14,6 +14,8 @@ const CT = defs.constant_types; const TS = defs.thread_status; const LUA_NUMTAGS = defs.LUA_NUMTAGS; +const EXTRA_STACK = 5; + const BASIC_STACK_SIZE = 2 * defs.LUA_MINSTACK; class CallInfo { @@ -200,6 +202,7 @@ module.exports.CIST_TAIL = (1<<5); /* call was tail called */ module.exports.CIST_HOOKYIELD = (1<<6); /* last hook called yielded */ module.exports.CIST_LEQ = (1<<7); /* using __lt for __le */ module.exports.CIST_FIN = (1<<8); /* call is running a finalizer */ +module.exports.EXTRA_STACK = EXTRA_STACK; module.exports.lua_close = lua_close; module.exports.lua_newstate = lua_newstate; module.exports.lua_newthread = lua_newthread; |