checking consistency of jumps (and some other details)
This commit is contained in:
101
ldebug.c
101
ldebug.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: ldebug.c,v 1.61 2001/02/09 18:37:33 roberto Exp roberto $
|
** $Id: ldebug.c,v 1.62 2001/02/09 20:22:29 roberto Exp roberto $
|
||||||
** Debug Interface
|
** Debug Interface
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -316,49 +316,82 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** {======================================================
|
** {======================================================
|
||||||
** Symbolic Execution
|
** Symbolic Execution and code checker
|
||||||
** =======================================================
|
** =======================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define check(x) if (!(x)) return 0;
|
/*#define check(x) if (!(x)) return 0;*/
|
||||||
|
#define check(x) assert(x)
|
||||||
#define checkjump(pt, pc) check(0 <= (pc) && (pc) < (pt)->sizecode)
|
#define checkjump(pt, pc) check(0 <= (pc) && (pc) < (pt)->sizecode)
|
||||||
|
|
||||||
static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) {
|
|
||||||
|
static int checklineinfo (const Proto *pt) {
|
||||||
|
int *lineinfo = pt->lineinfo;
|
||||||
|
if (lineinfo == NULL) return 1;
|
||||||
|
check(pt->sizelineinfo >= 2 && lineinfo[pt->sizelineinfo-1] == MAX_INT);
|
||||||
|
if (*lineinfo < 0) lineinfo++;
|
||||||
|
check(*lineinfo == 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int precheck (const Proto *pt) {
|
||||||
|
check(checklineinfo(pt));
|
||||||
|
check(pt->maxstacksize <= MAXSTACK);
|
||||||
|
check(pt->numparams+pt->is_vararg <= pt->maxstacksize);
|
||||||
|
check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* value for non-initialized entries in array stacklevel */
|
||||||
|
#define SL_EMPTY 255
|
||||||
|
|
||||||
|
#define checkstacklevel(sl,top,pc) \
|
||||||
|
if (sl) { if (sl[pc] == SL_EMPTY) sl[pc] = top; else check(sl[pc] == top); }
|
||||||
|
|
||||||
|
|
||||||
|
static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos,
|
||||||
|
unsigned char *sl) {
|
||||||
int stack[MAXSTACK]; /* stores last instruction that changed a stack entry */
|
int stack[MAXSTACK]; /* stores last instruction that changed a stack entry */
|
||||||
const Instruction *code = pt->code;
|
const Instruction *code = pt->code;
|
||||||
int top = pt->numparams;
|
int top = pt->numparams;
|
||||||
int pc = 0;
|
int pc = 0;
|
||||||
if (pt->is_vararg) /* varargs? */
|
if (pt->is_vararg) /* varargs? */
|
||||||
top++; /* `arg' */
|
top++; /* `arg' */
|
||||||
check (top <= pt->maxstacksize && pt->maxstacksize <= MAXSTACK);
|
checkstacklevel(sl, top, pc);
|
||||||
while (pc < lastpc) {
|
while (pc < lastpc) {
|
||||||
const Instruction i = code[pc++];
|
const Instruction i = code[pc++];
|
||||||
OpCode op = GET_OPCODE(i);
|
OpCode op = GET_OPCODE(i);
|
||||||
int push = (int)luaK_opproperties[op].push;
|
|
||||||
int pop = (int)luaK_opproperties[op].pop;
|
|
||||||
int arg1 = 0;
|
int arg1 = 0;
|
||||||
int arg2 = 0;
|
int arg2 = 0;
|
||||||
|
int push, pop;
|
||||||
|
check(op < NUM_OPCODES);
|
||||||
|
push = (int)luaK_opproperties[op].push;
|
||||||
|
pop = (int)luaK_opproperties[op].pop;
|
||||||
switch ((enum Mode)luaK_opproperties[op].mode) {
|
switch ((enum Mode)luaK_opproperties[op].mode) {
|
||||||
case iO: break;
|
case iO: break;
|
||||||
case iU: arg1 = GETARG_U(i); break;
|
case iU: arg1 = GETARG_U(i); check(arg1 >= 0); break;
|
||||||
case iS: arg1 = GETARG_S(i); break;
|
case iS: arg1 = GETARG_S(i); break;
|
||||||
case iAB: arg1 = GETARG_A(i); arg2 = GETARG_B(i); break;
|
case iAB:
|
||||||
|
arg1 = GETARG_A(i); arg2 = GETARG_B(i); check(arg1 >= 0); break;
|
||||||
}
|
}
|
||||||
check(0 <= top && top <= pt->maxstacksize);
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case OP_RETURN: {
|
case OP_RETURN: {
|
||||||
|
check(arg1 <= top);
|
||||||
pop = top-arg1;
|
pop = top-arg1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_CALL: {
|
case OP_CALL: {
|
||||||
if (arg2 == MULT_RET) arg2 = 1;
|
if (arg2 == MULT_RET) arg2 = 1;
|
||||||
|
check(arg1 < top);
|
||||||
pop = top-arg1;
|
pop = top-arg1;
|
||||||
push = arg2;
|
push = arg2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_TAILCALL: {
|
case OP_TAILCALL: {
|
||||||
check(arg1 <= top);
|
check(arg1 < top && arg2 <= top);
|
||||||
pop = top-arg2;
|
pop = top-arg2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -395,7 +428,7 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_SETTABLE: {
|
case OP_SETTABLE: {
|
||||||
check(2 <= arg1 && arg1 <= top);
|
check(3 <= arg1 && arg1 <= top);
|
||||||
pop = arg2;
|
pop = arg2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -425,21 +458,24 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) {
|
|||||||
case OP_JMPGT:
|
case OP_JMPGT:
|
||||||
case OP_JMPGE:
|
case OP_JMPGE:
|
||||||
case OP_JMPT:
|
case OP_JMPT:
|
||||||
case OP_JMPF:
|
case OP_JMPF: {
|
||||||
|
checkjump(pt, pc+arg1);
|
||||||
|
check(pop <= top);
|
||||||
|
checkstacklevel(sl, top-pop, pc+arg1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case OP_JMP:
|
case OP_JMP:
|
||||||
case OP_FORLOOP:
|
case OP_FORLOOP:
|
||||||
case OP_LFORLOOP: {
|
case OP_LFORLOOP: {
|
||||||
checkjump(pt, pc+arg1);
|
checkjump(pt, pc+arg1);
|
||||||
break;
|
checkstacklevel(sl, top, pc+arg1);
|
||||||
}
|
|
||||||
case OP_PUSHNILJMP: {
|
|
||||||
checkjump(pt, pc+1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_JMPONT:
|
case OP_JMPONT:
|
||||||
case OP_JMPONF: {
|
case OP_JMPONF: {
|
||||||
int newpc = pc + arg1;
|
int newpc = pc+arg1;
|
||||||
checkjump(pt, newpc);
|
checkjump(pt, newpc);
|
||||||
|
checkstacklevel(sl, top, newpc);
|
||||||
/* jump is forward and do not skip `lastpc' and not full check? */
|
/* jump is forward and do not skip `lastpc' and not full check? */
|
||||||
if (pc < newpc && newpc <= lastpc && stackpos >= 0) {
|
if (pc < newpc && newpc <= lastpc && stackpos >= 0) {
|
||||||
stack[top-1] = pc-1; /* value comes from `and'/`or' */
|
stack[top-1] = pc-1; /* value comes from `and'/`or' */
|
||||||
@@ -448,14 +484,24 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OP_PUSHNILJMP: {
|
||||||
|
check(GET_OPCODE(code[pc]) == OP_PUSHINT); /* only valid sequence */
|
||||||
|
break;
|
||||||
|
}
|
||||||
case OP_FORPREP: {
|
case OP_FORPREP: {
|
||||||
|
int newpc = pc-arg1; /* jump is `negative' here */
|
||||||
check(top >= 3);
|
check(top >= 3);
|
||||||
checkjump(pt, pc-arg1); /* jump is `negative' here */
|
checkjump(pt, newpc);
|
||||||
|
check(GET_OPCODE(code[newpc-1]) == OP_FORLOOP);
|
||||||
|
check(GETARG_S(code[newpc-1]) == arg1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_LFORPREP: {
|
case OP_LFORPREP: {
|
||||||
|
int newpc = pc-arg1; /* jump is `negative' here */
|
||||||
check(top >= 1);
|
check(top >= 1);
|
||||||
checkjump(pt, pc-arg1); /* jump is `negative' here */
|
checkjump(pt, newpc);
|
||||||
|
check(GET_OPCODE(code[newpc-1]) == OP_LFORLOOP);
|
||||||
|
check(GETARG_S(code[newpc-1]) == arg1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_PUSHINT:
|
case OP_PUSHINT:
|
||||||
@@ -472,18 +518,21 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check(0 <= pop && 0 <= push);
|
|
||||||
check(0 <= top-pop && top+(push-pop) <= pt->maxstacksize);
|
|
||||||
top -= pop;
|
top -= pop;
|
||||||
|
check(0 <= top && top+push <= pt->maxstacksize);
|
||||||
while (push--) stack[top++] = pc-1;
|
while (push--) stack[top++] = pc-1;
|
||||||
|
checkstacklevel(sl, top, pc);
|
||||||
}
|
}
|
||||||
check(GET_OPCODE(code[pt->sizecode-1]) == OP_RETURN);
|
|
||||||
return (stackpos >= 0) ? code[stack[stackpos]] : 1;
|
return (stackpos >= 0) ? code[stack[stackpos]] : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaG_checkcode (const Proto *pt) {
|
int luaG_checkcode (lua_State *L, const Proto *pt) {
|
||||||
return luaG_symbexec(pt, pt->sizecode-1, -1);
|
unsigned char *sl = (unsigned char *)luaO_openspace(L, pt->sizecode);
|
||||||
|
int i;
|
||||||
|
for (i=0; i<pt->sizecode; i++)
|
||||||
|
sl[i] = SL_EMPTY;
|
||||||
|
return precheck(pt) && luaG_symbexec(pt, pt->sizecode-1, -1, sl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -495,7 +544,7 @@ static const char *getobjname (lua_State *L, StkId obj, const char **name) {
|
|||||||
Proto *p = infovalue(func)->func->f.l;
|
Proto *p = infovalue(func)->func->f.l;
|
||||||
int pc = currentpc(func);
|
int pc = currentpc(func);
|
||||||
int stackpos = obj - (func+1); /* func+1 == function base */
|
int stackpos = obj - (func+1); /* func+1 == function base */
|
||||||
Instruction i = luaG_symbexec(p, pc, stackpos);
|
Instruction i = luaG_symbexec(p, pc, stackpos, NULL);
|
||||||
lua_assert(pc != -1);
|
lua_assert(pc != -1);
|
||||||
switch (GET_OPCODE(i)) {
|
switch (GET_OPCODE(i)) {
|
||||||
case OP_GETGLOBAL: {
|
case OP_GETGLOBAL: {
|
||||||
|
|||||||
Reference in New Issue
Block a user