mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-07 15:14:08 +00:00
Rework stack overflow handling.
Reported by pwnhacker0x18. Fixed by Peter Cawley. #1152
This commit is contained in:
parent
9cdd5a9479
commit
defe61a567
@ -63,6 +63,7 @@ static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe)
|
||||
if (cf == NULL || (char *)cframe_pc(cf) == (char *)cframe_L(cf))
|
||||
return NO_BCPOS;
|
||||
ins = cframe_pc(cf); /* Only happens during error/hook handling. */
|
||||
if (!ins) return NO_BCPOS;
|
||||
} else {
|
||||
if (frame_islua(nextframe)) {
|
||||
ins = frame_pc(nextframe);
|
||||
|
22
src/lj_err.c
22
src/lj_err.c
@ -488,7 +488,14 @@ LJ_NOINLINE void lj_err_mem(lua_State *L)
|
||||
{
|
||||
if (L->status == LUA_ERRERR+1) /* Don't touch the stack during lua_open. */
|
||||
lj_vm_unwind_c(L->cframe, LUA_ERRMEM);
|
||||
if (curr_funcisL(L)) L->top = curr_topL(L);
|
||||
if (curr_funcisL(L)) {
|
||||
L->top = curr_topL(L);
|
||||
if (LJ_UNLIKELY(L->top > tvref(L->maxstack))) {
|
||||
/* The current Lua frame violates the stack. Replace it with a dummy. */
|
||||
L->top = L->base;
|
||||
setframe_gc(L->base - 1, obj2gco(L));
|
||||
}
|
||||
}
|
||||
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRMEM));
|
||||
lj_err_throw(L, LUA_ERRMEM);
|
||||
}
|
||||
@ -551,9 +558,11 @@ LJ_NOINLINE void LJ_FASTCALL lj_err_run(lua_State *L)
|
||||
{
|
||||
ptrdiff_t ef = finderrfunc(L);
|
||||
if (ef) {
|
||||
TValue *errfunc = restorestack(L, ef);
|
||||
TValue *top = L->top;
|
||||
TValue *errfunc, *top;
|
||||
lj_state_checkstack(L, LUA_MINSTACK * 2); /* Might raise new error. */
|
||||
lj_trace_abort(G(L));
|
||||
errfunc = restorestack(L, ef);
|
||||
top = L->top;
|
||||
if (!tvisfunc(errfunc) || L->status == LUA_ERRERR) {
|
||||
setstrV(L, top-1, lj_err_str(L, LJ_ERR_ERRERR));
|
||||
lj_err_throw(L, LUA_ERRERR);
|
||||
@ -567,6 +576,13 @@ LJ_NOINLINE void LJ_FASTCALL lj_err_run(lua_State *L)
|
||||
lj_err_throw(L, LUA_ERRRUN);
|
||||
}
|
||||
|
||||
/* Stack overflow error. */
|
||||
void LJ_FASTCALL lj_err_stkov(lua_State *L)
|
||||
{
|
||||
lj_debug_addloc(L, err2msg(LJ_ERR_STKOV), L->base-1, NULL);
|
||||
lj_err_run(L);
|
||||
}
|
||||
|
||||
/* Formatted runtime error message. */
|
||||
LJ_NORET LJ_NOINLINE static void err_msgv(lua_State *L, ErrMsg em, ...)
|
||||
{
|
||||
|
@ -23,6 +23,7 @@ LJ_DATA const char *lj_err_allmsg;
|
||||
LJ_FUNC GCstr *lj_err_str(lua_State *L, ErrMsg em);
|
||||
LJ_FUNCA_NORET void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode);
|
||||
LJ_FUNC_NORET void lj_err_mem(lua_State *L);
|
||||
LJ_FUNC_NORET void LJ_FASTCALL lj_err_stkov(lua_State *L);
|
||||
LJ_FUNCA_NORET void LJ_FASTCALL lj_err_run(lua_State *L);
|
||||
LJ_FUNC_NORET void lj_err_msg(lua_State *L, ErrMsg em);
|
||||
LJ_FUNC_NORET void lj_err_lex(lua_State *L, GCstr *src, const char *tok,
|
||||
|
@ -96,27 +96,45 @@ void lj_state_shrinkstack(lua_State *L, MSize used)
|
||||
/* Try to grow stack. */
|
||||
void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need)
|
||||
{
|
||||
MSize n;
|
||||
if (L->stacksize >= LJ_STACK_MAXEX) {
|
||||
/* 4. Throw 'error in error handling' when we are _over_ the limit. */
|
||||
if (L->stacksize > LJ_STACK_MAXEX)
|
||||
lj_err_throw(L, LUA_ERRERR); /* Does not invoke an error handler. */
|
||||
/* 1. We are _at_ the limit after the last growth. */
|
||||
if (L->status < LUA_ERRRUN) { /* 2. Throw 'stack overflow'. */
|
||||
L->status = LUA_ERRRUN; /* Prevent ending here again for pushed msg. */
|
||||
lj_err_msg(L, LJ_ERR_STKOV); /* May invoke an error handler. */
|
||||
}
|
||||
/* 3. Add space (over the limit) for pushed message and error handler. */
|
||||
}
|
||||
n = L->stacksize + need;
|
||||
if (n > LJ_STACK_MAX) {
|
||||
n += 2*LUA_MINSTACK;
|
||||
} else if (n < 2*L->stacksize) {
|
||||
MSize n = L->stacksize + need;
|
||||
if (LJ_LIKELY(n < LJ_STACK_MAX)) { /* The stack can grow as requested. */
|
||||
if (n < 2 * L->stacksize) { /* Try to double the size. */
|
||||
n = 2 * L->stacksize;
|
||||
if (n >= LJ_STACK_MAX)
|
||||
if (n > LJ_STACK_MAX)
|
||||
n = LJ_STACK_MAX;
|
||||
}
|
||||
resizestack(L, n);
|
||||
} else { /* Request would overflow. Raise a stack overflow error. */
|
||||
if (curr_funcisL(L)) {
|
||||
L->top = curr_topL(L);
|
||||
if (L->top > tvref(L->maxstack)) {
|
||||
/* The current Lua frame violates the stack, so replace it with a
|
||||
** dummy. This can happen when BC_IFUNCF is trying to grow the stack.
|
||||
*/
|
||||
L->top = L->base;
|
||||
setframe_gc(L->base - 1, obj2gco(L));
|
||||
}
|
||||
}
|
||||
if (L->stacksize <= LJ_STACK_MAXEX) {
|
||||
/* An error handler might want to inspect the stack overflow error, but
|
||||
** will need some stack space to run in. We give it a stack size beyond
|
||||
** the normal limit in order to do so, then rely on lj_state_relimitstack
|
||||
** calls during unwinding to bring us back to a convential stack size.
|
||||
** The + 1 is space for the error message, and 2 * LUA_MINSTACK is for
|
||||
** the lj_state_checkstack() call in lj_err_run().
|
||||
*/
|
||||
resizestack(L, LJ_STACK_MAX + 1 + 2 * LUA_MINSTACK);
|
||||
lj_err_stkov(L); /* May invoke an error handler. */
|
||||
} else {
|
||||
/* If we're here, then the stack overflow error handler is requesting
|
||||
** to grow the stack even further. We have no choice but to abort the
|
||||
** error handler.
|
||||
*/
|
||||
GCstr *em = lj_err_str(L, LJ_ERR_STKOV); /* Might OOM. */
|
||||
setstrV(L, L->top++, em); /* There is always space to push an error. */
|
||||
lj_err_throw(L, LUA_ERRERR); /* Does not invoke an error handler. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LJ_FASTCALL lj_state_growstack1(lua_State *L)
|
||||
|
Loading…
Reference in New Issue
Block a user