diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2001-02-12 17:54:28 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2001-02-12 17:54:28 -0200 |
commit | 3c649ce1230eaf1df0d64afb2cb2c2a98cd4faa4 (patch) | |
tree | a18ad8614489166aac54d2ac56aa917fd97bf4a8 | |
parent | 95da574dbc97bfab54c2fdb170e1caf2f5571f1f (diff) | |
download | lua-3c649ce1230eaf1df0d64afb2cb2c2a98cd4faa4.tar.gz lua-3c649ce1230eaf1df0d64afb2cb2c2a98cd4faa4.tar.bz2 lua-3c649ce1230eaf1df0d64afb2cb2c2a98cd4faa4.zip |
checking consistency of jumps (and some other details)
-rw-r--r-- | ldebug.c | 101 |
1 files changed, 75 insertions, 26 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldebug.c,v 1.61 2001/02/09 18:37:33 roberto Exp roberto $ | 2 | ** $Id: ldebug.c,v 1.62 2001/02/09 20:22:29 roberto Exp roberto $ |
3 | ** Debug Interface | 3 | ** Debug Interface |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -316,49 +316,82 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { | |||
316 | 316 | ||
317 | /* | 317 | /* |
318 | ** {====================================================== | 318 | ** {====================================================== |
319 | ** Symbolic Execution | 319 | ** Symbolic Execution and code checker |
320 | ** ======================================================= | 320 | ** ======================================================= |
321 | */ | 321 | */ |
322 | 322 | ||
323 | 323 | ||
324 | #define check(x) if (!(x)) return 0; | 324 | /*#define check(x) if (!(x)) return 0;*/ |
325 | #define check(x) assert(x) | ||
325 | #define checkjump(pt, pc) check(0 <= (pc) && (pc) < (pt)->sizecode) | 326 | #define checkjump(pt, pc) check(0 <= (pc) && (pc) < (pt)->sizecode) |
326 | 327 | ||
327 | static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) { | 328 | |
329 | static int checklineinfo (const Proto *pt) { | ||
330 | int *lineinfo = pt->lineinfo; | ||
331 | if (lineinfo == NULL) return 1; | ||
332 | check(pt->sizelineinfo >= 2 && lineinfo[pt->sizelineinfo-1] == MAX_INT); | ||
333 | if (*lineinfo < 0) lineinfo++; | ||
334 | check(*lineinfo == 0); | ||
335 | return 1; | ||
336 | } | ||
337 | |||
338 | |||
339 | static int precheck (const Proto *pt) { | ||
340 | check(checklineinfo(pt)); | ||
341 | check(pt->maxstacksize <= MAXSTACK); | ||
342 | check(pt->numparams+pt->is_vararg <= pt->maxstacksize); | ||
343 | check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); | ||
344 | return 1; | ||
345 | } | ||
346 | |||
347 | |||
348 | /* value for non-initialized entries in array stacklevel */ | ||
349 | #define SL_EMPTY 255 | ||
350 | |||
351 | #define checkstacklevel(sl,top,pc) \ | ||
352 | if (sl) { if (sl[pc] == SL_EMPTY) sl[pc] = top; else check(sl[pc] == top); } | ||
353 | |||
354 | |||
355 | static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos, | ||
356 | unsigned char *sl) { | ||
328 | int stack[MAXSTACK]; /* stores last instruction that changed a stack entry */ | 357 | int stack[MAXSTACK]; /* stores last instruction that changed a stack entry */ |
329 | const Instruction *code = pt->code; | 358 | const Instruction *code = pt->code; |
330 | int top = pt->numparams; | 359 | int top = pt->numparams; |
331 | int pc = 0; | 360 | int pc = 0; |
332 | if (pt->is_vararg) /* varargs? */ | 361 | if (pt->is_vararg) /* varargs? */ |
333 | top++; /* `arg' */ | 362 | top++; /* `arg' */ |
334 | check (top <= pt->maxstacksize && pt->maxstacksize <= MAXSTACK); | 363 | checkstacklevel(sl, top, pc); |
335 | while (pc < lastpc) { | 364 | while (pc < lastpc) { |
336 | const Instruction i = code[pc++]; | 365 | const Instruction i = code[pc++]; |
337 | OpCode op = GET_OPCODE(i); | 366 | OpCode op = GET_OPCODE(i); |
338 | int push = (int)luaK_opproperties[op].push; | ||
339 | int pop = (int)luaK_opproperties[op].pop; | ||
340 | int arg1 = 0; | 367 | int arg1 = 0; |
341 | int arg2 = 0; | 368 | int arg2 = 0; |
369 | int push, pop; | ||
370 | check(op < NUM_OPCODES); | ||
371 | push = (int)luaK_opproperties[op].push; | ||
372 | pop = (int)luaK_opproperties[op].pop; | ||
342 | switch ((enum Mode)luaK_opproperties[op].mode) { | 373 | switch ((enum Mode)luaK_opproperties[op].mode) { |
343 | case iO: break; | 374 | case iO: break; |
344 | case iU: arg1 = GETARG_U(i); break; | 375 | case iU: arg1 = GETARG_U(i); check(arg1 >= 0); break; |
345 | case iS: arg1 = GETARG_S(i); break; | 376 | case iS: arg1 = GETARG_S(i); break; |
346 | case iAB: arg1 = GETARG_A(i); arg2 = GETARG_B(i); break; | 377 | case iAB: |
378 | arg1 = GETARG_A(i); arg2 = GETARG_B(i); check(arg1 >= 0); break; | ||
347 | } | 379 | } |
348 | check(0 <= top && top <= pt->maxstacksize); | ||
349 | switch (op) { | 380 | switch (op) { |
350 | case OP_RETURN: { | 381 | case OP_RETURN: { |
382 | check(arg1 <= top); | ||
351 | pop = top-arg1; | 383 | pop = top-arg1; |
352 | break; | 384 | break; |
353 | } | 385 | } |
354 | case OP_CALL: { | 386 | case OP_CALL: { |
355 | if (arg2 == MULT_RET) arg2 = 1; | 387 | if (arg2 == MULT_RET) arg2 = 1; |
388 | check(arg1 < top); | ||
356 | pop = top-arg1; | 389 | pop = top-arg1; |
357 | push = arg2; | 390 | push = arg2; |
358 | break; | 391 | break; |
359 | } | 392 | } |
360 | case OP_TAILCALL: { | 393 | case OP_TAILCALL: { |
361 | check(arg1 <= top); | 394 | check(arg1 < top && arg2 <= top); |
362 | pop = top-arg2; | 395 | pop = top-arg2; |
363 | break; | 396 | break; |
364 | } | 397 | } |
@@ -395,7 +428,7 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) { | |||
395 | break; | 428 | break; |
396 | } | 429 | } |
397 | case OP_SETTABLE: { | 430 | case OP_SETTABLE: { |
398 | check(2 <= arg1 && arg1 <= top); | 431 | check(3 <= arg1 && arg1 <= top); |
399 | pop = arg2; | 432 | pop = arg2; |
400 | break; | 433 | break; |
401 | } | 434 | } |
@@ -425,21 +458,24 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) { | |||
425 | case OP_JMPGT: | 458 | case OP_JMPGT: |
426 | case OP_JMPGE: | 459 | case OP_JMPGE: |
427 | case OP_JMPT: | 460 | case OP_JMPT: |
428 | case OP_JMPF: | 461 | case OP_JMPF: { |
462 | checkjump(pt, pc+arg1); | ||
463 | check(pop <= top); | ||
464 | checkstacklevel(sl, top-pop, pc+arg1); | ||
465 | break; | ||
466 | } | ||
429 | case OP_JMP: | 467 | case OP_JMP: |
430 | case OP_FORLOOP: | 468 | case OP_FORLOOP: |
431 | case OP_LFORLOOP: { | 469 | case OP_LFORLOOP: { |
432 | checkjump(pt, pc+arg1); | 470 | checkjump(pt, pc+arg1); |
433 | break; | 471 | checkstacklevel(sl, top, pc+arg1); |
434 | } | ||
435 | case OP_PUSHNILJMP: { | ||
436 | checkjump(pt, pc+1); | ||
437 | break; | 472 | break; |
438 | } | 473 | } |
439 | case OP_JMPONT: | 474 | case OP_JMPONT: |
440 | case OP_JMPONF: { | 475 | case OP_JMPONF: { |
441 | int newpc = pc + arg1; | 476 | int newpc = pc+arg1; |
442 | checkjump(pt, newpc); | 477 | checkjump(pt, newpc); |
478 | checkstacklevel(sl, top, newpc); | ||
443 | /* jump is forward and do not skip `lastpc' and not full check? */ | 479 | /* jump is forward and do not skip `lastpc' and not full check? */ |
444 | if (pc < newpc && newpc <= lastpc && stackpos >= 0) { | 480 | if (pc < newpc && newpc <= lastpc && stackpos >= 0) { |
445 | stack[top-1] = pc-1; /* value comes from `and'/`or' */ | 481 | 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) { | |||
448 | } | 484 | } |
449 | break; | 485 | break; |
450 | } | 486 | } |
487 | case OP_PUSHNILJMP: { | ||
488 | check(GET_OPCODE(code[pc]) == OP_PUSHINT); /* only valid sequence */ | ||
489 | break; | ||
490 | } | ||
451 | case OP_FORPREP: { | 491 | case OP_FORPREP: { |
492 | int newpc = pc-arg1; /* jump is `negative' here */ | ||
452 | check(top >= 3); | 493 | check(top >= 3); |
453 | checkjump(pt, pc-arg1); /* jump is `negative' here */ | 494 | checkjump(pt, newpc); |
495 | check(GET_OPCODE(code[newpc-1]) == OP_FORLOOP); | ||
496 | check(GETARG_S(code[newpc-1]) == arg1); | ||
454 | break; | 497 | break; |
455 | } | 498 | } |
456 | case OP_LFORPREP: { | 499 | case OP_LFORPREP: { |
500 | int newpc = pc-arg1; /* jump is `negative' here */ | ||
457 | check(top >= 1); | 501 | check(top >= 1); |
458 | checkjump(pt, pc-arg1); /* jump is `negative' here */ | 502 | checkjump(pt, newpc); |
503 | check(GET_OPCODE(code[newpc-1]) == OP_LFORLOOP); | ||
504 | check(GETARG_S(code[newpc-1]) == arg1); | ||
459 | break; | 505 | break; |
460 | } | 506 | } |
461 | case OP_PUSHINT: | 507 | case OP_PUSHINT: |
@@ -472,18 +518,21 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) { | |||
472 | break; | 518 | break; |
473 | } | 519 | } |
474 | } | 520 | } |
475 | check(0 <= pop && 0 <= push); | ||
476 | check(0 <= top-pop && top+(push-pop) <= pt->maxstacksize); | ||
477 | top -= pop; | 521 | top -= pop; |
522 | check(0 <= top && top+push <= pt->maxstacksize); | ||
478 | while (push--) stack[top++] = pc-1; | 523 | while (push--) stack[top++] = pc-1; |
524 | checkstacklevel(sl, top, pc); | ||
479 | } | 525 | } |
480 | check(GET_OPCODE(code[pt->sizecode-1]) == OP_RETURN); | ||
481 | return (stackpos >= 0) ? code[stack[stackpos]] : 1; | 526 | return (stackpos >= 0) ? code[stack[stackpos]] : 1; |
482 | } | 527 | } |
483 | 528 | ||
484 | 529 | ||
485 | int luaG_checkcode (const Proto *pt) { | 530 | int luaG_checkcode (lua_State *L, const Proto *pt) { |
486 | return luaG_symbexec(pt, pt->sizecode-1, -1); | 531 | unsigned char *sl = (unsigned char *)luaO_openspace(L, pt->sizecode); |
532 | int i; | ||
533 | for (i=0; i<pt->sizecode; i++) | ||
534 | sl[i] = SL_EMPTY; | ||
535 | return precheck(pt) && luaG_symbexec(pt, pt->sizecode-1, -1, sl); | ||
487 | } | 536 | } |
488 | 537 | ||
489 | 538 | ||
@@ -495,7 +544,7 @@ static const char *getobjname (lua_State *L, StkId obj, const char **name) { | |||
495 | Proto *p = infovalue(func)->func->f.l; | 544 | Proto *p = infovalue(func)->func->f.l; |
496 | int pc = currentpc(func); | 545 | int pc = currentpc(func); |
497 | int stackpos = obj - (func+1); /* func+1 == function base */ | 546 | int stackpos = obj - (func+1); /* func+1 == function base */ |
498 | Instruction i = luaG_symbexec(p, pc, stackpos); | 547 | Instruction i = luaG_symbexec(p, pc, stackpos, NULL); |
499 | lua_assert(pc != -1); | 548 | lua_assert(pc != -1); |
500 | switch (GET_OPCODE(i)) { | 549 | switch (GET_OPCODE(i)) { |
501 | case OP_GETGLOBAL: { | 550 | case OP_GETGLOBAL: { |