diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-07-11 12:53:23 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-07-11 12:53:23 -0300 |
| commit | 4d5de1c1fb2decb39d74dfb092ca5643ce47176f (patch) | |
| tree | 6d211899db43994b5d421a8a7e59dcb2ecccc0db | |
| parent | 9a825f6bb9a141023ac519a73f6a9958c113659e (diff) | |
| download | lua-4d5de1c1fb2decb39d74dfb092ca5643ce47176f.tar.gz lua-4d5de1c1fb2decb39d74dfb092ca5643ce47176f.tar.bz2 lua-4d5de1c1fb2decb39d74dfb092ca5643ce47176f.zip | |
Fixed bug in line info. when using 'not' operator
When creating code for a jump on a 'not' condition, the code generator
was removing an instruction (the OP_NOT) without adjusting its
corresponding line information.
This fix also added tests for this case and extra functionality in
the test library to debug line info. structures.
| -rw-r--r-- | lcode.c | 76 | ||||
| -rw-r--r-- | ltests.c | 22 | ||||
| -rw-r--r-- | testes/errors.lua | 21 |
3 files changed, 93 insertions, 26 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lcode.c,v 2.160 2018/03/16 14:22:09 roberto Exp roberto $ | 2 | ** $Id: lcode.c $ |
| 3 | ** Code generator for Lua | 3 | ** Code generator for Lua |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -309,10 +309,19 @@ void luaK_patchclose (FuncState *fs, int list) { | |||
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | 311 | ||
| 312 | /* | ||
| 313 | ** MAXimum number of successive Instructions WiTHout ABSolute line | ||
| 314 | ** information. | ||
| 315 | */ | ||
| 312 | #if !defined(MAXIWTHABS) | 316 | #if !defined(MAXIWTHABS) |
| 313 | #define MAXIWTHABS 120 | 317 | #define MAXIWTHABS 120 |
| 314 | #endif | 318 | #endif |
| 315 | 319 | ||
| 320 | |||
| 321 | /* limit for difference between lines in relative line info. */ | ||
| 322 | #define LIMLINEDIFF 0x80 | ||
| 323 | |||
| 324 | |||
| 316 | /* | 325 | /* |
| 317 | ** Save line info for a new instruction. If difference from last line | 326 | ** Save line info for a new instruction. If difference from last line |
| 318 | ** does not fit in a byte, of after that many instructions, save a new | 327 | ** does not fit in a byte, of after that many instructions, save a new |
| @@ -320,14 +329,15 @@ void luaK_patchclose (FuncState *fs, int list) { | |||
| 320 | ** in 'lineinfo' signals the existence of this absolute information.) | 329 | ** in 'lineinfo' signals the existence of this absolute information.) |
| 321 | ** Otherwise, store the difference from last line in 'lineinfo'. | 330 | ** Otherwise, store the difference from last line in 'lineinfo'. |
| 322 | */ | 331 | */ |
| 323 | static void savelineinfo (FuncState *fs, Proto *f, int pc, int line) { | 332 | static void savelineinfo (FuncState *fs, Proto *f, int line) { |
| 324 | int linedif = line - fs->previousline; | 333 | int linedif = line - fs->previousline; |
| 325 | if (abs(linedif) >= 0x80 || fs->iwthabs++ > MAXIWTHABS) { | 334 | int pc = fs->pc - 1; /* last instruction coded */ |
| 335 | if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ > MAXIWTHABS) { | ||
| 326 | luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo, | 336 | luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo, |
| 327 | f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines"); | 337 | f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines"); |
| 328 | f->abslineinfo[fs->nabslineinfo].pc = pc; | 338 | f->abslineinfo[fs->nabslineinfo].pc = pc; |
| 329 | f->abslineinfo[fs->nabslineinfo++].line = line; | 339 | f->abslineinfo[fs->nabslineinfo++].line = line; |
| 330 | linedif = ABSLINEINFO; /* signal there is absolute information */ | 340 | linedif = ABSLINEINFO; /* signal that there is absolute information */ |
| 331 | fs->iwthabs = 0; /* restart counter */ | 341 | fs->iwthabs = 0; /* restart counter */ |
| 332 | } | 342 | } |
| 333 | luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte, | 343 | luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte, |
| @@ -338,6 +348,37 @@ static void savelineinfo (FuncState *fs, Proto *f, int pc, int line) { | |||
| 338 | 348 | ||
| 339 | 349 | ||
| 340 | /* | 350 | /* |
| 351 | ** Remove line information from the last instruction. | ||
| 352 | ** If line information for that instruction is absolute, set 'iwthabs' | ||
| 353 | ** above its max to force the new (replacing) instruction to have | ||
| 354 | ** absolute line info, too. | ||
| 355 | */ | ||
| 356 | static void removelastlineinfo (FuncState *fs) { | ||
| 357 | Proto *f = fs->f; | ||
| 358 | int pc = fs->pc - 1; /* last instruction coded */ | ||
| 359 | if (f->lineinfo[pc] != ABSLINEINFO) { /* relative line info? */ | ||
| 360 | fs->previousline -= f->lineinfo[pc]; /* last line saved */ | ||
| 361 | fs->iwthabs--; | ||
| 362 | } | ||
| 363 | else { /* absolute line information */ | ||
| 364 | fs->nabslineinfo--; /* remove it */ | ||
| 365 | lua_assert(f->abslineinfo[fs->nabslineinfo].pc = pc); | ||
| 366 | fs->iwthabs = MAXIWTHABS + 1; /* force next line info to be absolute */ | ||
| 367 | } | ||
| 368 | } | ||
| 369 | |||
| 370 | |||
| 371 | /* | ||
| 372 | ** Remove the last instruction created, correcting line information | ||
| 373 | ** accordingly. | ||
| 374 | */ | ||
| 375 | static void removelastinstruction (FuncState *fs) { | ||
| 376 | removelastlineinfo(fs); | ||
| 377 | fs->pc--; | ||
| 378 | } | ||
| 379 | |||
| 380 | |||
| 381 | /* | ||
| 341 | ** Emit instruction 'i', checking for array sizes and saving also its | 382 | ** Emit instruction 'i', checking for array sizes and saving also its |
| 342 | ** line information. Return 'i' position. | 383 | ** line information. Return 'i' position. |
| 343 | */ | 384 | */ |
| @@ -346,9 +387,9 @@ static int luaK_code (FuncState *fs, Instruction i) { | |||
| 346 | /* put new instruction in code array */ | 387 | /* put new instruction in code array */ |
| 347 | luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, | 388 | luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, |
| 348 | MAX_INT, "opcodes"); | 389 | MAX_INT, "opcodes"); |
| 349 | f->code[fs->pc] = i; | 390 | f->code[fs->pc++] = i; |
| 350 | savelineinfo(fs, f, fs->pc, fs->ls->lastline); | 391 | savelineinfo(fs, f, fs->ls->lastline); |
| 351 | return fs->pc++; | 392 | return fs->pc - 1; /* index of new instruction */ |
| 352 | } | 393 | } |
| 353 | 394 | ||
| 354 | 395 | ||
| @@ -986,7 +1027,7 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) { | |||
| 986 | if (e->k == VRELOC) { | 1027 | if (e->k == VRELOC) { |
| 987 | Instruction ie = getinstruction(fs, e); | 1028 | Instruction ie = getinstruction(fs, e); |
| 988 | if (GET_OPCODE(ie) == OP_NOT) { | 1029 | if (GET_OPCODE(ie) == OP_NOT) { |
| 989 | fs->pc--; /* remove previous OP_NOT */ | 1030 | removelastinstruction(fs); /* remove previous OP_NOT */ |
| 990 | return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); | 1031 | return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); |
| 991 | } | 1032 | } |
| 992 | /* else go through */ | 1033 | /* else go through */ |
| @@ -1572,23 +1613,12 @@ void luaK_posfix (FuncState *fs, BinOpr opr, | |||
| 1572 | 1613 | ||
| 1573 | 1614 | ||
| 1574 | /* | 1615 | /* |
| 1575 | ** Change line information associated with current position. If that | 1616 | ** Change line information associated with current position, by removing |
| 1576 | ** information is absolute, just change it and correct 'previousline'. | 1617 | ** previous info and adding it again with new line. |
| 1577 | ** Otherwise, restore 'previousline' to its value before saving the | ||
| 1578 | ** current position and than saves the line information again, with the | ||
| 1579 | ** new line. | ||
| 1580 | */ | 1618 | */ |
| 1581 | void luaK_fixline (FuncState *fs, int line) { | 1619 | void luaK_fixline (FuncState *fs, int line) { |
| 1582 | Proto *f = fs->f; | 1620 | removelastlineinfo(fs); |
| 1583 | if (f->lineinfo[fs->pc - 1] == ABSLINEINFO) { | 1621 | savelineinfo(fs, fs->f, line); |
| 1584 | lua_assert(f->abslineinfo[fs->nabslineinfo - 1].pc == fs->pc - 1); | ||
| 1585 | f->abslineinfo[fs->nabslineinfo - 1].line = line; | ||
| 1586 | fs->previousline = line; | ||
| 1587 | } | ||
| 1588 | else { | ||
| 1589 | fs->previousline -= f->lineinfo[fs->pc - 1]; /* undo previous info. */ | ||
| 1590 | savelineinfo(fs, f, fs->pc - 1, line); /* redo it */ | ||
| 1591 | } | ||
| 1592 | } | 1622 | } |
| 1593 | 1623 | ||
| 1594 | 1624 | ||
| @@ -526,7 +526,8 @@ static char *buildop (Proto *p, int pc, char *buff) { | |||
| 526 | OpCode o = GET_OPCODE(i); | 526 | OpCode o = GET_OPCODE(i); |
| 527 | const char *name = opnames[o]; | 527 | const char *name = opnames[o]; |
| 528 | int line = luaG_getfuncline(p, pc); | 528 | int line = luaG_getfuncline(p, pc); |
| 529 | sprintf(buff, "(%4d) %4d - ", line, pc); | 529 | int lineinfo = (p->lineinfo != NULL) ? p->lineinfo[pc] : 0; |
| 530 | sprintf(buff, "(%2d - %4d) %4d - ", lineinfo, line, pc); | ||
| 530 | switch (getOpMode(o)) { | 531 | switch (getOpMode(o)) { |
| 531 | case iABC: | 532 | case iABC: |
| 532 | sprintf(buff+strlen(buff), "%-12s%4d %4d %4d%s", name, | 533 | sprintf(buff+strlen(buff), "%-12s%4d %4d %4d%s", name, |
| @@ -621,6 +622,24 @@ static int listk (lua_State *L) { | |||
| 621 | } | 622 | } |
| 622 | 623 | ||
| 623 | 624 | ||
| 625 | static int listabslineinfo (lua_State *L) { | ||
| 626 | Proto *p; | ||
| 627 | int i; | ||
| 628 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | ||
| 629 | 1, "Lua function expected"); | ||
| 630 | p = getproto(obj_at(L, 1)); | ||
| 631 | luaL_argcheck(L, p->abslineinfo != NULL, 1, "function has no debug info"); | ||
| 632 | lua_createtable(L, 2 * p->sizeabslineinfo, 0); | ||
| 633 | for (i=0; i < p->sizeabslineinfo; i++) { | ||
| 634 | lua_pushinteger(L, p->abslineinfo[i].pc); | ||
| 635 | lua_rawseti(L, -2, 2 * i + 1); | ||
| 636 | lua_pushinteger(L, p->abslineinfo[i].line); | ||
| 637 | lua_rawseti(L, -2, 2 * i + 2); | ||
| 638 | } | ||
| 639 | return 1; | ||
| 640 | } | ||
| 641 | |||
| 642 | |||
| 624 | static int listlocals (lua_State *L) { | 643 | static int listlocals (lua_State *L) { |
| 625 | Proto *p; | 644 | Proto *p; |
| 626 | int pc = cast_int(luaL_checkinteger(L, 2)) - 1; | 645 | int pc = cast_int(luaL_checkinteger(L, 2)) - 1; |
| @@ -1682,6 +1701,7 @@ static const struct luaL_Reg tests_funcs[] = { | |||
| 1682 | {"listcode", listcode}, | 1701 | {"listcode", listcode}, |
| 1683 | {"printcode", printcode}, | 1702 | {"printcode", printcode}, |
| 1684 | {"listk", listk}, | 1703 | {"listk", listk}, |
| 1704 | {"listabslineinfo", listabslineinfo}, | ||
| 1685 | {"listlocals", listlocals}, | 1705 | {"listlocals", listlocals}, |
| 1686 | {"loadlib", loadlib}, | 1706 | {"loadlib", loadlib}, |
| 1687 | {"checkpanic", checkpanic}, | 1707 | {"checkpanic", checkpanic}, |
diff --git a/testes/errors.lua b/testes/errors.lua index 63a7b740..19a7b6fa 100644 --- a/testes/errors.lua +++ b/testes/errors.lua | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | -- $Id: errors.lua,v 1.97 2017/11/28 15:31:56 roberto Exp $ | 1 | -- $Id: errors.lua $ |
| 2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file all.lua |
| 3 | 3 | ||
| 4 | print("testing errors") | 4 | print("testing errors") |
| @@ -299,7 +299,7 @@ end | |||
| 299 | local function lineerror (s, l) | 299 | local function lineerror (s, l) |
| 300 | local err,msg = pcall(load(s)) | 300 | local err,msg = pcall(load(s)) |
| 301 | local line = string.match(msg, ":(%d+):") | 301 | local line = string.match(msg, ":(%d+):") |
| 302 | assert((line and line+0) == l) | 302 | assert(tonumber(line) == l) |
| 303 | end | 303 | end |
| 304 | 304 | ||
| 305 | lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2) | 305 | lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2) |
| @@ -350,6 +350,23 @@ X=1;lineerror((p), 2) | |||
| 350 | X=2;lineerror((p), 1) | 350 | X=2;lineerror((p), 1) |
| 351 | 351 | ||
| 352 | 352 | ||
| 353 | lineerror([[ | ||
| 354 | local b = false | ||
| 355 | if not b then | ||
| 356 | error 'test' | ||
| 357 | end]], 3) | ||
| 358 | |||
| 359 | lineerror([[ | ||
| 360 | local b = false | ||
| 361 | if not b then | ||
| 362 | if not b then | ||
| 363 | if not b then | ||
| 364 | error 'test' | ||
| 365 | end | ||
| 366 | end | ||
| 367 | end]], 5) | ||
| 368 | |||
| 369 | |||
| 353 | if not _soft then | 370 | if not _soft then |
| 354 | -- several tests that exaust the Lua stack | 371 | -- several tests that exaust the Lua stack |
| 355 | collectgarbage() | 372 | collectgarbage() |
