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() |