summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lapi.js14
-rw-r--r--src/ldo.js27
-rw-r--r--src/lstate.js3
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 */
diff --git a/src/ldo.js b/src/ldo.js
index eb8df06..1036ce5 100644
--- a/src/ldo.js
+++ b/src/ldo.js
@@ -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;