issue #163 Base must be protected as luaF_close can now reallocate stack due to invocation of deferred functions

defer
Dibyendu Majumdar 5 years ago
parent 9a0ced9620
commit edce55b997

@ -19,6 +19,7 @@
#include "lua.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
@ -87,25 +88,59 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
return uv;
}
static void callclose (lua_State *L, void *ud) {
luaD_callnoyield(L, cast(StkId, ud), 0);
static void calldeferred(lua_State *L, void *ud) {
UNUSED(ud);
luaD_callnoyield(L, L->top - 2, 0);
}
static int calldeferredfunction (lua_State *L, UpVal *uv, StkId level, int status) {
StkId func = level + 1; /* save slot for old error message */
setobj2s(L, func, uv->v); /* will call it */
if (status != LUA_OK) /* was there an error? */
luaD_seterrorobj(L, status, level); /* save error message */
else
setnilvalue(level);
setobjs2s(L, func + 1, level); /* error msg. as argument */
L->top = func + 2; /* add function and argument */
if (status == LUA_OK) /* not in "error mode"? */
callclose(L, func); /* call closing method */
else { /* already inside error handler; cannot raise another error */
int newstatus = luaD_pcall(L, callclose, func, savestack(L, level), 0);
if (newstatus != LUA_OK) /* error when closing? */
status = newstatus; /* this will be the new error */
/*
** Prepare deferred function plus its arguments for object 'obj' with
** error message 'err'. (This function assumes EXTRA_STACK.)
*/
static int preparetocall(lua_State *L, TValue *func, TValue *err) {
StkId top = L->top;
setobj2s(L, top, func); /* will call deferred function */
if (err) {
setobj2s(L, top + 1, err); /* and error msg. as 1st argument */
}
else {
setnilvalue(top + 1);
}
L->top = top + 2; /* add function and arguments */
return 1;
}
/*
** Prepare and call a deferred function. If status is OK, code is still
** inside the original protected call, and so any error will be handled
** there. Otherwise, a previous error already activated the original
** protected call, and so the call to the deferred method must be
** protected here. (A status == -1 behaves like a previous
** error, to also run the closing method in protected mode).
** If status is OK, the call to the deferred method will be pushed
** at the top of the stack. Otherwise, values are pushed after
** the 'level' of the upvalue containing deferred function, as everything after
** that won't be used again.
*/
static int calldeferredfunction(lua_State *L, StkId level, int status) {
TValue *uv = level; /* value being closed */
if (status == LUA_OK) {
preparetocall(L, uv, NULL); /* something to call? */
calldeferred(L, NULL); /* call closing method */
}
else { /* must close the object in protected mode */
ptrdiff_t oldtop;
level++; /* space for error message */
oldtop = savestack(L, level + 1); /* top will be after that */
luaD_seterrorobj(L, status, level); /* set error message */
preparetocall(L, uv, level);
int newstatus = luaD_pcall(L, calldeferred, NULL, oldtop, 0);
if (newstatus != LUA_OK && status == -1) /* first error? */
status = newstatus; /* this will be the new error */
else {
/* leave original error (or nil) on top */
L->top = restorestack(L, oldtop);
}
}
return status;
}
@ -118,10 +153,10 @@ int luaF_close (lua_State *L, StkId level, int status) {
if (uv->refcount == 0) { /* no references? */
if (uv->flags && ttisfunction(uv->v)) {
ptrdiff_t levelrel = savestack(L, level);
status = calldeferredfunction(L, uv, uv->v, status);
status = calldeferredfunction(L, uv->v, status);
level = restorestack(L, levelrel);
}
luaM_free(L, uv); /* free upvalue */
luaM_free(L, uv); /* free upvalue */ /* FIXME leak if error occurs above */
}
else {
setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */

@ -16,6 +16,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <lparser.h>
#include "lua.h"
@ -919,10 +920,17 @@ static Proto *addprototype (LexState *ls) {
** so that, if it invokes the GC, the GC knows which registers
** are in use at that time.
*/
static void codeclosure (LexState *ls, expdesc *v) {
static void codeclosure (LexState *ls, expdesc *v, int deferred) {
FuncState *fs = ls->fs->prev;
int pc = -1;
if (deferred) {
pc = luaK_codeABC(fs, OP_RAVI_DEFER, 0, 0, 0);
}
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1), RAVI_TFUNCTION, NULL);
luaK_exp2nextreg(fs, v); /* fix it at the last register */
if (deferred) {
SETARG_A(fs->f->code[pc], v->u.info);
}
DEBUG_VARS(raviY_printf(ls->fs, "codeclosure -> closure created %e\n", v));
}
@ -1283,7 +1291,7 @@ static void parlist (LexState *ls) {
}
static void body (LexState *ls, expdesc *e, int ismethod, int line) {
static void body (LexState *ls, expdesc *e, int ismethod, int line, int deferred) {
/* body -> '(' parlist ')' block END */
FuncState new_fs;
BlockCnt bl;
@ -1300,7 +1308,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) {
statlist(ls);
new_fs.f->lastlinedefined = ls->linenumber;
check_match(ls, TK_END, TK_FUNCTION, line);
codeclosure(ls, e);
codeclosure(ls, e, deferred);
close_func(ls);
}
@ -1592,7 +1600,7 @@ static void simpleexp (LexState *ls, expdesc *v) {
}
case TK_FUNCTION: {
luaX_next(ls);
body(ls, v, 0, ls->linenumber);
body(ls, v, 0, ls->linenumber, 0);
return;
}
default: {
@ -2183,14 +2191,13 @@ static void localfunc (LexState *ls, int defer) {
if (defer) {
static const char funcname[] = "(deferred function)";
new_localvar(ls, luaX_newstring(ls, funcname, sizeof funcname-1), RAVI_TFUNCTION, NULL); /* new local variable */
luaK_codeABC(fs, OP_RAVI_DEFER, fs->nactvar, 0, 0);
markupval(fs, fs->nactvar);
} else {
/* RAVI change - add type */
new_localvar(ls, str_checkname(ls), RAVI_TFUNCTION, NULL); /* new local variable */
}
adjustlocalvars(ls, 1); /* enter its scope */
body(ls, &b, 0, ls->linenumber); /* function created in next register */
body(ls, &b, 0, ls->linenumber, defer); /* function created in next register */
/* debug information will only see the variable after this point! */
getlocvar(fs, b.u.info)->startpc = fs->pc;
}
@ -2253,7 +2260,7 @@ static void funcstat (LexState *ls, int line) {
luaX_next(ls); /* skip FUNCTION */
ismethod = funcname(ls, &v);
DEBUG_VARS(raviY_printf(ls->fs, "funcstat -> declaring function %e\n", &v));
body(ls, &b, ismethod, line);
body(ls, &b, ismethod, line, 0);
luaK_storevar(ls->fs, &v, &b);
luaK_fixline(ls->fs, line); /* definition "happens" in the first line */
}

@ -1027,7 +1027,7 @@ void luaV_finishOp (lua_State *L) {
*/
#define dojump(ci,i,e) \
{ int a = GETARG_A(i); \
if (a != 0) luaF_close(L, ci->u.l.base + a - 1, LUA_OK); \
if (a != 0) Protect_base(luaF_close(L, ci->u.l.base + a - 1, LUA_OK)); \
pc += GETARG_sBx(i) + e; updatemask(L); }
/* for test instructions, execute the jump instruction that follows it */
@ -1721,7 +1721,7 @@ int luaV_execute (lua_State *L) {
StkId lim = nci->u.l.base + getproto(nfunc)->numparams;
int aux;
/* close all upvalues from previous call */
if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base, LUA_OK);
if (cl->p->sizep > 0) Protect_base(luaF_close(L, oci->u.l.base, LUA_OK));
/* move new frame into old one */
for (aux = 0; nfunc + aux < lim; aux++)
setobjs2s(L, ofunc + aux, nfunc + aux);
@ -1738,7 +1738,7 @@ int luaV_execute (lua_State *L) {
}
vmcase(OP_RETURN) {
int b = GETARG_B(i);
if (cl->p->sizep > 0) luaF_close(L, base, LUA_OK);
if (cl->p->sizep > 0) Protect_base(luaF_close(L, base, LUA_OK));
savepc(L);
int nres = (b != 0 ? b - 1 : cast_int(L->top - ra));
b = luaD_poscall(L, ci, ra, nres);

@ -1013,6 +1013,7 @@ static void emit_comparison(struct function *fn, int A, int B, int C, int j, int
if (jA > 0) {
membuff_add_fstring(&fn->body, " ra = R(%d);\n", jA - 1);
membuff_add_string(&fn->body, " luaF_close(L, ra, LUA_OK);\n");
membuff_add_string(&fn->body, " base = ci->u.l.base;\n");
}
membuff_add_fstring(&fn->body, " goto Lbc_%d;\n", j);
membuff_add_string(&fn->body, "}\n");
@ -1045,7 +1046,9 @@ static void emit_op_loadk(struct function *fn, int A, int Bx, int pc) {
static void emit_op_return(struct function *fn, int A, int B, int pc) {
(void)pc;
emit_reg(fn, "ra", A);
membuff_add_string(&fn->body, "if (cl->p->sizep > 0) luaF_close(L, base, LUA_OK);\n");
membuff_add_string(&fn->body, "if (cl->p->sizep > 0) {\n luaF_close(L, base, LUA_OK);\n");
membuff_add_string(&fn->body, " base = ci->u.l.base;\n");
membuff_add_string(&fn->body, "}\n");
membuff_add_fstring(&fn->body, "result = (%d != 0 ? %d - 1 : cast_int(L->top - ra));\n", B, B);
membuff_add_string(&fn->body, "return luaD_poscall(L, ci, ra, result);\n");
}
@ -1069,6 +1072,7 @@ static void emit_op_jmp(struct function *fn, int A, int sBx, int pc) {
if (A > 0) {
membuff_add_fstring(&fn->body, "ra = R(%d);\n", A - 1);
membuff_add_string(&fn->body, "luaF_close(L, ra, LUA_OK);\n");
membuff_add_string(&fn->body, "base = ci->u.l.base;\n");
}
membuff_add_fstring(&fn->body, "goto Lbc_%d;\n", sBx);
}
@ -1093,6 +1097,7 @@ static void emit_op_test(struct function *fn, int A, int B, int C, int j, int jA
if (jA > 0) {
membuff_add_fstring(&fn->body, " ra = R(%d);\n", jA - 1);
membuff_add_string(&fn->body, " luaF_close(L, ra, LUA_OK);\n");
membuff_add_string(&fn->body, " base = ci->u.l.base;\n");
}
membuff_add_fstring(&fn->body, " goto Lbc_%d;\n", j);
membuff_add_string(&fn->body, " }\n");
@ -1111,6 +1116,7 @@ static void emit_op_testset(struct function *fn, int A, int B, int C, int j, int
if (jA > 0) {
membuff_add_fstring(&fn->body, " ra = R(%d);\n", jA - 1);
membuff_add_string(&fn->body, " luaF_close(L, ra, LUA_OK);\n");
membuff_add_string(&fn->body, " base = ci->u.l.base;\n");
}
membuff_add_fstring(&fn->body, " goto Lbc_%d;\n", j);
membuff_add_string(&fn->body, " }\n");

@ -134,6 +134,7 @@ void RaviCodeGenerator::emit_EQ(RaviFunctionDef *def, int A, int B, int C,
// Call luaF_close
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
emit_load_base(def);
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);
@ -240,6 +241,7 @@ void RaviCodeGenerator::emit_TEST(RaviFunctionDef *def, int A, int B, int C,
// Call luaF_close
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
emit_load_base(def);
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);
@ -312,6 +314,7 @@ void RaviCodeGenerator::emit_TESTSET(RaviFunctionDef *def, int A, int B, int C,
// Call luaF_close
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
emit_load_base(def);
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);

@ -78,6 +78,7 @@ void RaviCodeGenerator::emit_RETURN(RaviFunctionDef *def, int A, int B,
// Call luaF_close
CreateCall3(def->builder, def->luaF_closeF, def->L, def->base_ptr, def->types->kInt[LUA_OK]);
emit_load_base(def);
def->builder->CreateBr(else_block);
def->f->getBasicBlockList().push_back(else_block);

Loading…
Cancel
Save