diff --git a/bugs b/bugs deleted file mode 100644 index a965025b..00000000 --- a/bugs +++ /dev/null @@ -1,4052 +0,0 @@ ---[=[ -** lua.stx / llex.c -Tue Dec 2 10:45:48 EDT 1997 ->> BUG: "lastline" was not reset on function entry, so debug information ->> started only in the 2nd line of a function. - - - -================================================================= ---- Version 3.1 alpha - -** lua.c -Thu Jan 15 14:34:58 EDT 1998 ->> must include "stdlib.h" (for "exit()"). - -** lbuiltin.c / lobject.h -Thu Jan 15 14:34:58 EDT 1998 ->> MAX_WORD may be bigger than MAX_INT -(by lhf) - -** llex.c -Mon Jan 19 18:17:18 EDT 1998 ->> wrong line number (+1) in error report when file starts with "#..." - -** lstrlib.c -Tue Jan 27 15:27:49 EDT 1998 ->> formats like "%020d" were considered too big (3 digits); moreover, ->> some sistems limit printf to at most 500 chars, so we can limit sizes ->> to 2 digits (99). - -** lapi.c -Tue Jan 27 17:12:36 EDT 1998 ->> "lua_getstring" may create a new string, so should check GC - -** lstring.c / ltable.c -Wed Jan 28 14:48:12 EDT 1998 ->> tables can become full of "empty" slots, and keep growing without limits. - -** lstrlib.c -Mon Mar 9 15:26:09 EST 1998 ->> gsub('a', '(b?)%1*' ...) loops (because the capture is empty). - -** lstrlib.c -Mon May 18 19:20:00 EST 1998 ->> arguments for "format" 'x', 'X', 'o' and 'u' must be unsigned int. - - - -================================================================= ---- Version 3.1 - -** liolib.c / lauxlib.c -Mon Sep 7 15:57:02 EST 1998 ->> function "luaL_argerror" prints wrong argument number (from a user's point -of view) when functions have upvalues. - -** lstrlib.c -Tue Nov 10 17:29:36 EDT 1998 ->> gsub/strfind do not check whether captures are properly finished. -(by roberto/tomas) - -** lbuiltin.c -Fri Dec 18 11:22:55 EDT 1998 ->> "tonumber" goes crazy with negative numbers in other bases (not 10), -because "strtol" returns long, not unsigned long. -(by Visual C++) - -** lstrlib.c -Mon Jan 4 10:41:40 EDT 1999 ->> "format" does not check size of format item (such as "%00000...00000d"). - -** lapi.c -Wed Feb 3 14:40:21 EDT 1999 ->> getlocal cannot return the local itself, since lua_isstring and -lua_isnumber can modify it. - -** lstrlib.c -Thu Feb 4 17:08:50 EDT 1999 ->> format "%s" may break limit of "sprintf" on some machines. -(by Marcelo Sales) - -** lzio.c -Thu Mar 4 11:49:37 EST 1999 ->> file stream cannot call fread after EOF. -(by lhf) - - - -================================================================= ---- Version 3.2 (beta) - -** lstrlib.c -Fri Apr 30 11:10:20 EST 1999 ->> '$' at end of pattern was matching regular '$', too. -(by anna; since 2.5) - -** lbuiltin.c -Fri May 21 17:15:11 EST 1999 ->> foreach, foreachi, foreachvar points to function in stack when stack -can be reallocated. -(by tomas; since 3.2 beta) - -** lparser.c -Wed Jun 16 10:32:46 EST 1999 ->> cannot assign to unlimited variables, because it causes overflow in -the number of returns of a function. -(since 3.1) - - - -================================================================= ---- Version 3.2 - -** lmathlib.c -Wed Aug 18 11:28:38 EST 1999 ->> random(0) and random(x,0) are wrong (0 is read as no argument!). -(by Dave Bollinger; since 3.1) - -** lparser.c -Thu Sep 2 10:07:20 EST 1999 ->> in the (old) expression << ls->fs->f->consts[checkname(ls)] >>, checkname -could realloc f->consts. -(by Supratik Champati; since 3.2 beta) - -** lobject.c / lbuiltin.c -Wed Sep 8 17:41:54 EST 1999 ->> tonumber'e1' and tonumber(' ', x), for x!=10, gave 0 instead of nil. -(since 3.1) - -** lstrlib.c -Thu Nov 11 14:36:30 EDT 1999 ->> `strfind' does not handle \0 in plain search. -(by Jon Kleiser; since 3.1) - -** lparser.c -Wed Dec 29 16:05:43 EDT 1999 ->> return gives wrong line in debug information -(by lhf; since 3.2 [at least]) - -** ldo.c -Thu Dec 30 16:39:33 EDT 1999 ->> cannot reopen stdin (for binary mode) -(by lhf & roberto; since 3.1) - -** lapi.c -Thu Mar 2 09:41:53 EST 2000 ->> lua_settable should check stack space (it could call a T.M.) -(by lhf & celes; since 3.2; it was already fixed by fixed stack) - -** lparser.c -Mon Apr 3 09:59:06 EST 2000 ->> '%' should be in expfollow -(by Edgar Toernig; since 3.1; it was already fixed) - -** lbuiltin.c -Mon Apr 3 10:05:05 EST 2000 ->> tostring() without arguments gives seg. fault. -(by Edgar Toernig; since 3.0) - - - -================================================================= ---- Version 4.0 alpha - -Tested with full test suites (as locked in Mon Apr 24 14:23:11 EST 2000) -in the following platforms: -* Linux - gcc, g++ -* AIX - gcc -* Solaris - gcc, cc -* IRIX - cc, cc-purify -* Windows - Visual C++ (.c e .cpp, warning level=4) - - -** lstrlib.c -Tue May 2 15:27:58 EST 2000 ->> `strfind' gets wrong subject length when there is an offset -(by Jon Kleiser; since 4.0a) - -** lparser.c -Fri May 12 15:11:12 EST 2000 ->> first element in a list constructor is not adjusted to one value ->> (e.g. «a = {gsub('a','a','')}») -(by Tomas; since 4.0a) - -** lparser.c -Wed May 24 14:50:16 EST 2000 ->> record-constructor starting with an upvalue name gets an error ->> (e.g. «local a; function f() x = {a=1} end») -(by Edgar Toernig; since 3.1) - -** lparser.c -Tue Aug 29 15:56:05 EST 2000 ->> error message for `for' uses `while' -(since 4.0a; already corrected) - -** lgc.c -Tue Aug 29 15:57:41 EST 2000 ->> gc tag method for nil could call line hook -(by ry; since ?) - - - -================================================================= ---- Version 4.0 Beta - -** liolib.c -Fri Sep 22 15:12:37 EST 2000 ->> `read("*w")' should return nil at EOF -(by roberto; since 4.0b) - -** lvm.c -Mon Sep 25 11:47:48 EST 2000 ->> lua_gettable does not get key from stack top -(by Philip Yi; since 4.0b) - -** lgc.c -Mon Sep 25 11:50:48 EST 2000 ->> GC may crash when checking locked C closures -(by Philip Yi; since 4.0b) - -** lapi.c -Wed Sep 27 09:50:19 EST 2000 ->> lua_tag should return LUA_NOTAG for non-valid indices -(by Paul Hankin; since 4.0b) - -** llex.h / llex.c / lparser.c -Wed Sep 27 13:39:45 EST 2000 ->> parser overwrites semantic information when looking ahead ->> (e.g. «a = {print'foo'}») -(by Edgar Toernig; since 4.0b, deriving from previous bug) - -** liolib.c -Thu Oct 26 10:50:46 EDT 2000 ->> in function `read_file', realloc() doesn't free the buffer if it can't ->> allocate new memory -(by Mauro Vezzosi; since 4.0b) - - - -================================================================= ---- Version 4.0 - -** lparser.c -Wed Nov 29 09:51:44 EDT 2000 ->> parser does not accept a `;' after a `return' -(by lhf; since 4.0b) - -** liolib.c -Fri Dec 22 15:30:42 EDT 2000 ->> when `read' fails it must return nil (and not no value) -(by cassino; since at least 3.1) - -** lstring.c/lapi.c -Thu Feb 1 11:55:45 EDT 2001 ->> lua_pushuserdata(L, NULL) is buggy -(by Edgar Toernig; since 4.0) - -** ldo.c -Fri Feb 2 14:06:40 EDT 2001 ->> «while 1 dostring[[print('hello\n')]] end» never reclaims memory -(by Andrew Paton; since 4.0b) - -** lbaselib.c -Tue Feb 6 11:57:13 EDT 2001 ->> ESC (which starts precompiled code) in C is \33, not \27 -(by Edgar Toernig and lhf; since 4.0b) - -** lparser.c -Tue Jul 10 16:59:18 EST 2001 ->> error message for `%a' gave wrong line number -(by Leonardo Constantino; since 4.0) - -** lbaselib.c -Fri Dec 21 15:21:05 EDT 2001 ->> seg. fault when rawget/rawset get extra arguments -(by Eric Mauger; since 4.0b) - -** lvm.c -Wed Jun 19 13:28:20 EST 2002 ->> line hook gets wrong `ar' -(by Daniel C. Sinclair; since 4.0.b) - -** ldo.c -Wed Jun 19 13:31:49 EST 2002 ->> `protectedparser' may run GC, and then collect `filename' ->> (in function `parse_file') -(by Alex Bilyk; since 4.0) - - - - -================================================================= ---- Version 5.0 alpha - -** lgc.c -Fri Aug 30 13:49:14 EST 2002 ->> GC metamethod stored in a weak metatable being collected together with ->> userdata may not be cleared properly -(by Roberto; since 5.0a) - -** lapi.c -Thu Nov 21 11:00:00 EST 2002 ->> ULONG_MAX>>10 may not fit into an int -(by Jeff Petkau; since 4.0) - -** lparser.c -Fri Dec 6 17:06:40 UTC 2002 ->> scope of generic for variables is not sound -(by Gavin Wraith; since 5.0a) - - - - -================================================================= ---- Version 5.0 beta -** lbaselib.c -Fri Dec 20 09:53:19 UTC 2002 ->> `resume' was checking the wrong value for stack overflow -(by Maik Zimmermann; since 5.0b) - -** ldo.c -Thu Jan 23 11:29:06 UTC 2003 ->> error during garbage collection in luaD_protectedparser is not being ->> protected -(by Benoit Germain; since 5.0a) - -** ldo.c (and others) -Fri Feb 28 14:20:33 EST 2003 ->> GC metamethod calls could mess C/Lua stack syncronization -(by Roberto; since 5.0b) - -** lzio.h/zlio.c -Thu Mar 20 11:40:12 EST 2003 ->> zio mixes a 255 as first char in a buffer with EOZ -(by lhf; since 5.0a) - - - ---]=] ------------------------------------------------------------------ --- Lua 5.0 (final) - -Bug{ -what = [[lua_closethread exists only in the manual]], -report = [[by Nguyen Binh, 28/04/2003]], -patch = [[no patch; the manual is wrong]], -} - - -Bug{ -what = [[attempt to resume a running coroutine crashes Lua]], -example = [[ -function co_func (current_co) - coroutine.resume(co) -end -co = coroutine.create(co_func) -coroutine.resume(co) -coroutine.resume(co) --> seg. fault -]], -report = [[by Alex Bilyk, 09/05/2003]], -patch = [[ -* ldo.c: -325,326c325 -< if (nargs >= L->top - L->base) -< luaG_runerror(L, "cannot resume dead coroutine"); ---- -> lua_assert(nargs < L->top - L->base); -329c328,329 -< else if (ci->state & CI_YIELD) { /* inside a yield? */ ---- -> else { /* inside a yield */ -> lua_assert(ci->state & CI_YIELD); -344,345d343 -< else -< luaG_runerror(L, "cannot resume non-suspended coroutine"); -351a350,358 -> static int resume_error (lua_State *L, const char *msg) { -> L->top = L->ci->base; -> setsvalue2s(L->top, luaS_new(L, msg)); -> incr_top(L); -> lua_unlock(L); -> return LUA_ERRRUN; -> } -> -> -355a363,368 -> if (L->ci == L->base_ci) { -> if (nargs >= L->top - L->base) -> return resume_error(L, "cannot resume dead coroutine"); -> } -> else if (!(L->ci->state & CI_YIELD)) /* not inside a yield? */ -> return resume_error(L, "cannot resume non-suspended coroutine"); -]], -} - - -Bug{ -what = [[file:close cannot be called without a file. (results in seg fault)]], -example = [[ -> io.stdin.close() -- correct call shold be io.stdin:close() -]], -report = [[by Tuomo Valkonen, 27/05/2003]], -patch = [[ -* liolib.c: -161c161 -< if (lua_isnone(L, 1)) { ---- -> if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) { -]], --}} -} - - -Bug{ -what = [[C functions also may have stacks larger than current top]], -example = [[ -Must recompile lua with a change in lua.c and with lua_assert defined: -* lua.c: -381a382 -> lua_checkstack(l, 1000); -]], -report = [[Alex Bilyk, 09/06/2003]], -patch = [[ -* lgc.c: -247c247 -< if (!(ci->state & CI_C) && lim < ci->top) ---- -> if (lim < ci->top) -]], -} - - -Bug{ -what = [[`pc' address is invalidated when a coroutine is suspended]], -example = [[ -function g(x) - coroutine.yield(x) -end - -function f (i) - debug.sethook(print, "l") - for j=1,1000 do - g(i+j) - end -end - -co = coroutine.wrap(f) -co(10) -pcall(co) -pcall(co) -]], -report = [[Nick Trout, 07/07/2003]], -patch = [[ -* lvm.c: -402,403c402,403 -< L->ci->u.l.pc = &pc; -< if (L->hookmask & LUA_MASKCALL) ---- -> if (L->hookmask & LUA_MASKCALL) { -> L->ci->u.l.pc = &pc; -404a405 -> } -405a407 -> L->ci->u.l.pc = &pc; -676,678c678 -< lua_assert(ci->u.l.pc == &pc && -< ttisfunction(ci->base - 1) && -< (ci->state & CI_SAVEDPC)); ---- -> lua_assert(ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); -]] -} - - -Bug{ -what = [[userdata to be collected still counts into new GC threshold, -increasing memory consumption]], -report = [[Roberto, 25/07/2003]], -example = [[ -a = newproxy(true) -getmetatable(a).__gc = function () end -for i=1,10000000 do - newproxy(a) - if math.mod(i, 10000) == 0 then print(gcinfo()) end -end -]], -patch = [[ -* lgc.h: -18c18 -< void luaC_separateudata (lua_State *L); ---- -> size_t luaC_separateudata (lua_State *L); - -* lgc.c: -113c113,114 -< void luaC_separateudata (lua_State *L) { ---- -> size_t luaC_separateudata (lua_State *L) { -> size_t deadmem = 0; -127a129 -> deadmem += sizeudata(gcotou(curr)->uv.len); -136a139 -> return deadmem; -390c393 -< static void checkSizes (lua_State *L) { ---- -> static void checkSizes (lua_State *L, size_t deadmem) { -400c403 -< G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ ---- -> G(L)->GCthreshold = 2*G(L)->nblocks - deadmem; /* new threshold */ -454c457,458 -< static void mark (lua_State *L) { ---- -> static size_t mark (lua_State *L) { -> size_t deadmem; -467c471 -< luaC_separateudata(L); /* separate userdata to be preserved */ ---- -> deadmem = luaC_separateudata(L); /* separate userdata to be preserved */ -475a480 -> return deadmem; -480c485 -< mark(L); ---- -> size_t deadmem = mark(L); -482c487 -< checkSizes(L); ---- -> checkSizes(L, deadmem); -]] -} - -Bug{ -what=[[IBM AS400 (OS400) has sizeof(void *)==16, and a `%p' may generate -up to 60 characters in a `printf'. That causes a buffer overflow in -`tostring'.]], - -report = [[David Burgess, 25/08/2003]], - -example = [[print{}; (in an AS400 machine)]], - -patch = [[ -* liolib.c: -178c178 -< char buff[32]; ---- -> char buff[128]; - -* lbaselib.c: -327c327 -< char buff[64]; ---- -> char buff[128]; -]] -} - - -Bug{ -what = [[syntax `local function' does not increment stack size]], - -report = [[Rici Lake, 26/09/2003]], - -example = [[ --- must run this with precompiled code -local a,b,c -local function d () end -]], - -patch = [[ -* lparser.c: -1143a1144 -> FuncState *fs = ls->fs; -1145c1146,1147 -< init_exp(&v, VLOCAL, ls->fs->freereg++); ---- -> init_exp(&v, VLOCAL, fs->freereg); -> luaK_reserveregs(fs, 1); -1148c1150,1152 -< luaK_storevar(ls->fs, &v, &b); ---- -> luaK_storevar(fs, &v, &b); -> /* debug information will only see the variable after this point! */ -> getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; -]], - -} - - -Bug{ - -what = [[count hook may be called without being set]], - -report = [[Andreas Stenius, 06/10/2003]], - -example = [[ -set your hooks with - - lua_sethook(L, my_hook, LUA_MASKLINE | LUA_MASKRET, 1); - -(It is weird to use a count > 0 without setting the count hook, -but it is not wrong.) -]], - -patch = [[ -* lvm.c: -69c69 -< if (mask > LUA_MASKLINE) { /* instruction-hook set? */ ---- -> if (mask & LUA_MASKCOUNT) { /* instruction-hook set? */ -]], - -} - - -Bug{ - -what = [[`dofile' eats one return value when called without arguments]], - -report = [[Frederico Abraham, 15/01/2004]], - -example = [[ -a,b = dofile() --< here you enter `return 1,2,3 ' -print(a,b) --> 2 3 (should be 1 and 2) -]], - -patch = [[ -* lbaselib.c: -313a314 -> int n = lua_gettop(L); -317c318 -< return lua_gettop(L) - 1; ---- -> return lua_gettop(L) - n; -]], - -} - - - ------------------------------------------------------------------ --- Lua 5.0.2 - -Bug{ -what = [[string concatenation may cause arithmetic overflow, leading -to a buffer overflow]], - -report = [[Rici Lake, 20/05/2004]], - -example = [[ -longs = string.rep("\0", 2^25) -function catter(i) - return assert(loadstring( - string.format("return function(a) return a%s end", - string.rep("..a", i-1))))() -end -rep129 = catter(129) -rep129(longs) -]], - -patch = [[ -* lvm.c: -@@ -321,15 +321,15 @@ - luaG_concaterror(L, top-2, top-1); - } else if (tsvalue(top-1)->tsv.len > 0) { /* if len=0, do nothing */ - /* at least two string values; get as many as possible */ -- lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) + -- cast(lu_mem, tsvalue(top-2)->tsv.len); -+ size_t tl = tsvalue(top-1)->tsv.len; - char *buffer; - int i; -- while (n < total && tostring(L, top-n-1)) { /* collect total length */ -- tl += tsvalue(top-n-1)->tsv.len; -- n++; -+ /* collect total length */ -+ for (n = 1; n < total && tostring(L, top-n-1); n++) { -+ size_t l = tsvalue(top-n-1)->tsv.len; -+ if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); -+ tl += l; - } -- if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow"); - buffer = luaZ_openspace(L, &G(L)->buff, tl); - tl = 0; - for (i=n; i>0; i--) { /* concat all strings */ -]] -} - - -Bug{ -what = [[lua_getupvalue and setupvalue do not check for index too small]], - -report = [[Mike Pall, ?/2004]], - -example = [[debug.getupvalue(function() end, 0)]], - -patch = [[ -* lapi.c -941c941 -< if (n > f->c.nupvalues) return NULL; ---- -> if (!(1 <= n && n <= f->c.nupvalues)) return NULL; -947c947 -< if (n > p->sizeupvalues) return NULL; ---- -> if (!(1 <= n && n <= p->sizeupvalues)) return NULL; -]] -} - - -Bug{ -what = [[values holded in open upvalues of suspended threads may be -incorrectly collected]], - -report = [[Spencer Schumann, 31/12/2004]], - -example = [[ -local thread_id = 0 -local threads = {} - -function fn(thread) - thread_id = thread_id + 1 - threads[thread_id] = function() - thread = nil - end - coroutine.yield() -end - -while true do - local thread = coroutine.create(fn) - coroutine.resume(thread, thread) -end -]], - -patch = [[ -* lgc.c: -221,224c221,222 -< if (!u->marked) { -< markobject(st, &u->value); -< u->marked = 1; -< } ---- -> markobject(st, u->v); -> u->marked = 1; -]], -} - - -Bug{ -what = [[rawset/rawget do not ignore extra arguments]], - -report = [[Romulo Bahiense, 11/03/2005]], - -example = [[ -a = {} -rawset(a, 1, 2, 3) -print(a[1], a[2]) -- should be 2 and nil -]], - -patch = [[ -* lbaselib.c: -175a176 -> lua_settop(L, 2); -183a185 -> lua_settop(L, 3); -]], -} - - -Bug{ -what = [[weak tables that survive one collection are never collected]], - -report = [[Chromix, 02/01/2006]], - -example = [[ -a = {} -print(gcinfo()) -for i = 1, 10000 do - a[i] = setmetatable({}, {__mode = "v"}) -end -collectgarbage() -a = nil -collectgarbage() -print(gcinfo()) -]], - -patch = [[ -* lgc.c -@@ -366,7 +366,7 @@ - GCObject *curr; - int count = 0; /* number of collected items */ - while ((curr = *p) != NULL) { -- if (curr->gch.marked > limit) { -+ if ((curr->gch.marked & ~(KEYWEAK | VALUEWEAK)) > limit) { - unmark(curr); - p = &curr->gch.next; - } -]], - -} - - -Bug{ -what = [[Some "not not exp" may not result in boolean values]], -report = [[]], -since = [[4.0]], -example = [[ --- should print false, but prints nil -print(not not (nil and 4)) -]], -patch = [[]], -} - - -Bug{ -what = [[On some machines, closing a "piped file" (created with io.popen) -may crash Lua]], -report = [[]], -since = [[5.0]], -example = [[ --- only on some machines - f = io.popen("ls") - f:close() -]], -patch = [[]], -} - - - ------------------------------------------------------------------ --- Lua 5.1 - -Bug{ -what = [[In 16-bit machines, expressions and/or with numeric constants as the -right operand may result in weird values]], - -report = [[Andreas Stenius/Kein-Hong Man, 15/03/2006]], - -example = [[ -print(false or 0) -- on 16-bit machines -]], - -patch = [[ -* lcode.c: -@@ -731,17 +731,15 @@ - case OPR_AND: { - lua_assert(e1->t == NO_JUMP); /* list must be closed */ - luaK_dischargevars(fs, e2); -- luaK_concat(fs, &e1->f, e2->f); -- e1->k = e2->k; e1->u.s.info = e2->u.s.info; -- e1->u.s.aux = e2->u.s.aux; e1->t = e2->t; -+ luaK_concat(fs, &e2->f, e1->f); -+ *e1 = *e2; - break; - } - case OPR_OR: { - lua_assert(e1->f == NO_JUMP); /* list must be closed */ - luaK_dischargevars(fs, e2); -- luaK_concat(fs, &e1->t, e2->t); -- e1->k = e2->k; e1->u.s.info = e2->u.s.info; -- e1->u.s.aux = e2->u.s.aux; e1->f = e2->f; -+ luaK_concat(fs, &e2->t, e1->t); -+ *e1 = *e2; - break; - } -]], - -} - - -Bug{ -what = [[luaL_checkudata may produce wrong error message]], - -report = [[Greg Falcon, 21/03/2006]], - -example = [[ -getmetatable(io.stdin).__gc() - --> bad argument #1 to '__gc' (FILE* expected, got table) -]], - -patch = [[ -* lauxlib.c: -@@ -123,11 +123,17 @@ - - LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { - void *p = lua_touserdata(L, ud); -- lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ -- if (p == NULL || !lua_getmetatable(L, ud) || !lua_rawequal(L, -1, -2)) -- luaL_typerror(L, ud, tname); -- lua_pop(L, 2); /* remove both metatables */ -- return p; -+ if (p != NULL) { /* value is a userdata? */ -+ if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ -+ lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ -+ if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ -+ lua_pop(L, 2); /* remove both metatables */ -+ return p; -+ } -+ } -+ } -+ luaL_typerror(L, ud, tname); /* else error */ -+ return NULL; /* to avoid warnings */ - } -]] - -} - - -Bug{ -what = [[ -In Windows, -when Lua is used in an application that also uses DirectX, -it may present an erractic behavior. -THIS IS NOT A LUA BUG! -The problem is that DirectX violates an ABI that Lua depends on.]], - -patch = [[ -The simplest solution is to use DirectX with -the D3DCREATE_FPU_PRESERVE flag. - -Otherwise, you can change the definition of lua_number2int, -in luaconf.h, to this one: -#define lua_number2int(i,d) __asm fld d __asm fistp i -]], - -} - - -Bug{ -what = [[option '%q' in string.format does not handle '\r' correctly.]], - -example = [[ -local s = "a string with \r and \n and \r\n and \n\r" -local c = string.format("return %q", s) -assert(assert(loadstring(c))() == s) -]], - -patch = [[ -* lstrlib.c: -@@ -703,6 +703,10 @@ - luaL_addchar(b, *s); - break; - } -+ case '\r': { -+ luaL_addlstring(b, "\\r", 2); -+ break; -+ } - case '\0': { - luaL_addlstring(b, "\\000", 4); - break; -]], - -} - - -Bug{ -what = [[lua_dostring/lua_dofile should return any values returned -by the chunk]], - -patch = [[ -* lauxlib.h: -@@ -108,9 +108,11 @@ - - #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) - --#define luaL_dofile(L, fn) (luaL_loadfile(L, fn) || lua_pcall(L, 0, 0, 0)) -+#define luaL_dofile(L, fn) \ -+ (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) - --#define luaL_dostring(L, s) (luaL_loadstring(L, s) || lua_pcall(L, 0, 0, 0))+#define luaL_dostring(L, s) \ -+ (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) - - #define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) -]], - -} - - -Bug{ - -what = [[garbage collector does not compensate enough for finalizers]], - -patch = [[ -lgc.c: -@@ -322,4 +322,6 @@ - --static void propagateall (global_State *g) { -- while (g->gray) propagatemark(g); -+static size_t propagateall (global_State *g) { -+ size_t m = 0; -+ while (g->gray) m += propagatemark(g); -+ return m; - } -@@ -542,3 +544,3 @@ - marktmu(g); /* mark `preserved' userdata */ -- propagateall(g); /* remark, to propagate `preserveness' */ -+ udsize += propagateall(g); /* remark, to propagate `preserveness' */ - cleartable(g->weak); /* remove collected objects from weak tables */ -@@ -592,2 +594,4 @@ - GCTM(L); -+ if (g->estimate > GCFINALIZECOST) -+ g->estimate -= GCFINALIZECOST; -]] -} - - -Bug{ - -what = [[debug hooks may get wrong when mixed with coroutines]], - -report = [[by Ivko Stanilov, 03/06/2006]], - -example = [[ -co = coroutine.create(function (a,b) - coroutine.yield(a, b) - return b, "end" -end) - -debug.sethook(co, function() end, "lcr") -coroutine.resume(co, 100, 2000) -coroutine.resume(co, 100, 2000) -]], - -patch = [[ -* ldo.c: -@@ -389,6 +389,7 @@ - return; - } - else { /* resuming from previous yield */ -+ L->status = 0; - if (!f_isLua(ci)) { /* `common' yield? */ - /* finish interrupted execution of `OP_CALL' */ - lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || -@@ -399,7 +400,6 @@ - else /* yielded inside a hook: just continue its execution */ - L->base = L->ci->base; - } -- L->status = 0; - luaV_execute(L, cast_int(L->ci - L->base_ci)); - } -]], - -} - - - ------------------------------------------------------------------ --- Lua 5.1.1 - -Bug{ -what = [[list constructors have wrong limit]], - -report = [[by Norman Ramsey, June 2006]], - -since = "5.1", - -example = [[ -a = {} -a[1] = "x={1" -for i = 2, 2^20 do - a[i] = 1 -end -a[#a + 1] = "}" -s = table.concat(a, ",") -assert(loadstring(s))() -print(#x) -]], - -patch = [[ -* lparser.c: -@@ -489,7 +489,7 @@ - - static void listfield (LexState *ls, struct ConsControl *cc) { - expr(ls, &cc->v); -- luaY_checklimit(ls->fs, cc->na, MAXARG_Bx, "items in a constructor"); -+ luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); - cc->na++; - cc->tostore++; - } -]], - -} - - -Bug{ -what = [[wrong message error in some cases involving closures]], - -report = [[Shmuel Zeigerman, on 07/2006]], - -since = "5.1", - -example = [[ -local Var -local function main() - NoSuchName (function() Var=0 end) -end -main() ---> lua5.1: temp:3: attempt to call upvalue 'Var' (a nil value) -]], - -patch = [[ -*ldebug.c: -@@ -435,14 +435,16 @@ - break; - } - case OP_CLOSURE: { -- int nup; -+ int nup, j; - check(b < pt->sizep); - nup = pt->p[b]->nups; - check(pc + nup < pt->sizecode); -- for (; nup>0; nup--) { -- OpCode op1 = GET_OPCODE(pt->code[pc+nup]); -+ for (j = 1; j <= nup; j++) { -+ OpCode op1 = GET_OPCODE(pt->code[pc + j]); - check(op1 == OP_GETUPVAL || op1 == OP_MOVE); - } -+ if (reg != NO_REG) /* tracing? */ -+ pc += nup; /* do not 'execute' these pseudo-instructions */ - break; - } - case OP_VARARG: { -]], - -} - - -Bug{ -what = [[string.format("%") may read past the string]], -report = [[Roberto, on 09/2006]], -since = [[5.0]], -example = [[print(string.format("%"))]], -patch = [[ -*lstrlib.c: -@@ -723,7 +723,7 @@ - - static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; -- while (strchr(FLAGS, *p)) p++; /* skip flags */ -+ while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ - if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) - luaL_error(L, "invalid format (repeated flags)"); - if (isdigit(uchar(*p))) p++; /* skip width */ -]], -} - - -Bug{ -what = [[os.date throws an error when result is the empty string]], -report = [[]], -since = [[4.0]], -example = [[print(os.date(""))]], -patch = [[ -*loslib.c: -@@ -148,7 +148,18 @@ - else { -- char b[256]; -- if (strftime(b, sizeof(b), s, stm)) -- lua_pushstring(L, b); -- else -- return luaL_error(L, LUA_QL("date") " format too long"); -+ char cc[3]; -+ luaL_Buffer b; -+ cc[0] = '%'; cc[2] = '\0'; -+ luaL_buffinit(L, &b); -+ for (; *s; s++) { -+ if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ -+ luaL_addchar(&b, *s); -+ else { -+ size_t reslen; -+ char buff[200]; /* should be big enough for any conversion result */ -+ cc[1] = *(++s); -+ reslen = strftime(buff, sizeof(buff), cc, stm); -+ luaL_addlstring(&b, buff, reslen); -+ } -+ } -+ luaL_pushresult(&b); - } -]], -} - - -Bug{ -what = [[setfenv accepts invalid 1st argument]], -report = [[Doug Rogers, on 02/2007]], -since = [[5.0]], -example = [[setfenv(nil, {}) -- should throw an error]], -patch = [[ -*lbaselib.c: -@@ -116,3 +116,3 @@ - --static void getfunc (lua_State *L) { -+static void getfunc (lua_State *L, int opt) { - if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); -@@ -120,3 +120,3 @@ - lua_Debug ar; -- int level = luaL_optint(L, 1, 1); -+ int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); - luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); -@@ -133,3 +133,3 @@ - static int luaB_getfenv (lua_State *L) { -- getfunc(L); -+ getfunc(L, 1); - if (lua_iscfunction(L, -1)) /* is a C function? */ -@@ -144,3 +144,3 @@ - luaL_checktype(L, 2, LUA_TTABLE); -- getfunc(L); -+ getfunc(L, 0); - lua_pushvalue(L, 2); -]], -} - - -Bug{ -what = [[wrong code for arithmetic expressions in some specific scenarios]], -report = [[Thierry Grellier, on 01/2007]], -since = [[5.1]], -example = [[ --- use a large number of names (almost 256) -v1=1; v2=1; v3=1; v4=1; v5=1; v6=1; v7=1; v8=1; v9=1; -v10=1; v11=1; v12=1; v13=1; v14=1; v15=1; v16=1; v17=1; -v18=1; v19=1; v20=1; v21=1; v22=1; v23=1; v24=1; v25=1; -v26=1; v27=1; v28=1; v29=1; v30=1; v31=1; v32=1; v33=1; -v34=1; v35=1; v36=1; v37=1; v38=1; v39=1; v40=1; v41=1; -v42=1; v43=1; v44=1; v45=1; v46=1; v47=1; v48=1; v49=1; -v50=1; v51=1; v52=1; v53=1; v54=1; v55=1; v56=1; v57=1; -v58=1; v59=1; v60=1; v61=1; v62=1; v63=1; v64=1; v65=1; -v66=1; v67=1; v68=1; v69=1; v70=1; v71=1; v72=1; v73=1; -v74=1; v75=1; v76=1; v77=1; v78=1; v79=1; v80=1; v81=1; -v82=1; v83=1; v84=1; v85=1; v86=1; v87=1; v88=1; v89=1; -v90=1; v91=1; v92=1; v93=1; v94=1; v95=1; v96=1; v97=1; -v98=1; v99=1; v100=1; v101=1; v102=1; v103=1; v104=1; v105=1; -v106=1; v107=1; v108=1; v109=1; v110=1; v111=1; v112=1; v113=1; -v114=1; v115=1; v116=1; v117=1; v118=1; v119=1; v120=1; v121=1; -v122=1; v123=1; v124=1; v125=1; v126=1; v127=1; v128=1; v129=1; -v130=1; v131=1; v132=1; v133=1; v134=1; v135=1; v136=1; v137=1; -v138=1; v139=1; v140=1; v141=1; v142=1; v143=1; v144=1; v145=1; -v146=1; v147=1; v148=1; v149=1; v150=1; v151=1; v152=1; v153=1; -v154=1; v155=1; v156=1; v157=1; v158=1; v159=1; v160=1; v161=1; -v162=1; v163=1; v164=1; v165=1; v166=1; v167=1; v168=1; v169=1; -v170=1; v171=1; v172=1; v173=1; v174=1; v175=1; v176=1; v177=1; -v178=1; v179=1; v180=1; v181=1; v182=1; v183=1; v184=1; v185=1; -v186=1; v187=1; v188=1; v189=1; v190=1; v191=1; v192=1; v193=1; -v194=1; v195=1; v196=1; v197=1; v198=1; v199=1; v200=1; v201=1; -v202=1; v203=1; v204=1; v205=1; v206=1; v207=1; v208=1; v209=1; -v210=1; v211=1; v212=1; v213=1; v214=1; v215=1; v216=1; v217=1; -v218=1; v219=1; v220=1; v221=1; v222=1; v223=1; v224=1; v225=1; -v226=1; v227=1; v228=1; v229=1; v230=1; v231=1; v232=1; v233=1; -v234=1; v235=1; v236=1; v237=1; v238=1; v239=1; v240=1; v241=1; -v242=1; v243=1; v244=1; v245=1; v246=1; v247=1; v248=1; v249=1; -v250=1; -v251={k1 = 1}; -v252=1; -print(2 * v251.k1, v251.k1 * 2); -- 2 2, OK -v253=1; -print(2 * v251.k1, v251.k1 * 2); -- 1 2, ??? -]], -patch = [[ -*lcode.c: -@@ -657,10 +657,16 @@ - if (constfolding(op, e1, e2)) - return; - else { -- int o1 = luaK_exp2RK(fs, e1); - int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; -- freeexp(fs, e2); -- freeexp(fs, e1); -+ int o1 = luaK_exp2RK(fs, e1); -+ if (o1 > o2) { -+ freeexp(fs, e1); -+ freeexp(fs, e2); -+ } -+ else { -+ freeexp(fs, e2); -+ freeexp(fs, e1); -+ } - e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); - e1->k = VRELOCABLE; - } -@@ -718,10 +724,15 @@ - luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ - break; - } -- default: { -+ case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: -+ case OPR_MOD: case OPR_POW: { - if (!isnumeral(v)) luaK_exp2RK(fs, v); - break; - } -+ default: { -+ luaK_exp2RK(fs, v); -+ break; -+ } - } - } -]], -} - -Bug{ -what = [[assignment of nil to parameter may be optimized away]], -report = [[Thomas Lauer, on 03/2007]], -since = [[5.1]], -example = [[ -function f (a) - a=nil - return a -end - -print(f("test")) -]], -patch = [[ -*lcode.c: -@@ -35,16 +35,20 @@ - void luaK_nil (FuncState *fs, int from, int n) { - Instruction *previous; - if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ -- if (fs->pc == 0) /* function start? */ -- return; /* positions are already clean */ -- previous = &fs->f->code[fs->pc-1]; -- if (GET_OPCODE(*previous) == OP_LOADNIL) { -- int pfrom = GETARG_A(*previous); -- int pto = GETARG_B(*previous); -- if (pfrom <= from && from <= pto+1) { /* can connect both? */ -- if (from+n-1 > pto) -- SETARG_B(*previous, from+n-1); -- return; -+ if (fs->pc == 0) { /* function start? */ -+ if (from >= fs->nactvar) -+ return; /* positions are already clean */ -+ } -+ else { -+ previous = &fs->f->code[fs->pc-1]; -+ if (GET_OPCODE(*previous) == OP_LOADNIL) { -+ int pfrom = GETARG_A(*previous); -+ int pto = GETARG_B(*previous); -+ if (pfrom <= from && from <= pto+1) { /* can connect both? */ -+ if (from+n-1 > pto) -+ SETARG_B(*previous, from+n-1); -+ return; -+ } - } - } - } -]], -} - - -Bug{ -what = [[__concat metamethod converts numbers to strings]], -report = [[Paul Winwood, on 12/2006]], -since = [[5.0]], -example = [[ -a = {} -setmetatable(a, {__concat = function (a,b) print(type(a), type(b)) end}) -a = 4 .. a -]], -patch = [[ -*lvm.c: -@@ -281,10 +281,12 @@ - do { - StkId top = L->base + last + 1; - int n = 2; /* number of elements handled in this pass (at least 2) */ -- if (!tostring(L, top-2) || !tostring(L, top-1)) { -+ if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { - if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) - luaG_concaterror(L, top-2, top-1); -- } else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */ -+ } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ -+ (void)tostring(L, top - 2); /* result is first op (as string) */ -+ else { - /* at least two string values; get as many as possible */ - size_t tl = tsvalue(top-1)->len; - char *buffer; -]], -} - - -Bug{ -what = [[As a library, loadlib.c should not access Lua internals -(via lobject.h)]], -report = [[Jérôme Vuarand, on 03/2007]], -since = [[5.0]], -example = [[the bug has no effect on external behavior]], -patch = [[remove the '#include "lobject.h" and use -'lua_pushfstring' instead of 'luaO_pushfstring']], -} - - - ------------------------------------------------------------------ --- Lua 5.1.2 - -Bug{ -what = [[Lua may close standard files, -which then may be used by C]], -report = [[David Manura/Ross Berteig, on 04/2007]], -since = [[]], -example = [[ -io.close(io.stderr) --- in some systems, following attempts to write to 'stderr' may crash -a = a + 1 -]], -patch = [[ -]], -} - -Bug{ -what = [[code generated for "-nil", "-true", and "-false" is wrong]], -report = [[David Manura/Rici Lake, on 04/2007]], -since = [[5.1]], -example = [[print(-nil)]], -patch = [[ -lcode.c: -@@ -699,7 +699,7 @@ - e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; - switch (op) { - case OPR_MINUS: { -- if (e->k == VK) -+ if (!isnumeral(e)) - luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ - codearith(fs, OP_UNM, e, &e2); - break; -]], -} - -Bug{ -what = [[Count hook may be called without being set.]], -report = [[Mike Pall, on 05/2007]], -since = [[?]], -example = [[]], -patch = [[ -lvm.c: -@@ -61,11 +61,9 @@ - lu_byte mask = L->hookmask; - const Instruction *oldpc = L->savedpc; - L->savedpc = pc; -- if (mask > LUA_MASKLINE) { /* instruction-hook set? */ -- if (L->hookcount == 0) { -- resethookcount(L); -- luaD_callhook(L, LUA_HOOKCOUNT, -1); -- } -+ if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { -+ resethookcount(L); -+ luaD_callhook(L, LUA_HOOKCOUNT, -1); - } - if (mask & LUA_MASKLINE) { - Proto *p = ci_func(L->ci)->l.p; -]], -} - -Bug{ -what = [[recursive coroutines may overflow C stack]], -report = [[ , on ]], -since = [[5.0]], -example = [[ -a = function(a) coroutine.wrap(a)(a) end -a(a) -]], -patch = [[The 'nCcalls' counter should be shared by all threads. -(That is, it should be declared in the 'global_State' structure, -not in 'lua_State'.) -]], -} - -Bug{ -what = [[wrong error message in some concatenations]], -report = [[Alex Davies, on 05/2007]], -since = [[5.1.2]], -example = [[a = nil; a = (1)..a]], -patch = [[ -ldebug.c: -@@ -563,8 +563,8 @@ - - - void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { -- if (ttisstring(p1)) p1 = p2; -- lua_assert(!ttisstring(p1)); -+ if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; -+ lua_assert(!ttisstring(p1) && !ttisnumber(p1)); - luaG_typeerror(L, p1, "concatenate"); - } - -]], -} - -Bug{ -what = [[Very small numbers all collide in the hash function. -(This creates only performance problems; the behavoir is correct.)]], -report = [[, on ]], -since = [[5.0]], -example = [[]], -patch = [[ -ltable.c: -87,88c87,88 -< n += 1; /* normalize number (avoid -0) */ -< lua_assert(sizeof(a) <= sizeof(n)); ---- -> if (luai_numeq(n, 0)) /* avoid problems with -0 */ -> return gnode(t, 0); -]], -} - -Bug{ -what = [[Too many variables in an assignment may cause a -C stack overflow]], -report = [[Mike Pall, on 07/2007]], -since = [[5.0]], -example = [[ -$ ulimit -s 1024 # Reduce C stack to 1MB for quicker results -$ lua -e 'local s = "a,"; for i=1,18 do s = s..s end print(loadstring("local a;"..s.."a=nil", ""))' -]], -patch = [[ -lparser.c: -@@ -938,6 +938,8 @@ - primaryexp(ls, &nv.v); - if (nv.v.k == VLOCAL) - check_conflict(ls, lh, &nv.v); -+ luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls, -+ "variable names"); - assignment(ls, &nv, nvars+1); - } - else { /* assignment -> `=' explist1 */ -]], -} - -Bug{ -what = [[An error in a module loaded through the '-l' option -shows no traceback]], -report = [[David Manura, on 08/2007]], -since = [[5.1]], -example = [[lua -ltemp (assuming temp.lua has an error)]], -patch = [[ -lua.c: -@@ -144,7 +144,7 @@ - static int dolibrary (lua_State *L, const char *name) { - lua_getglobal(L, "require"); - lua_pushstring(L, name); -- return report(L, lua_pcall(L, 1, 0, 0)); -+ return report(L, docall(L, 1, 1)); - } -]], -} - -Bug{ -what = [['gsub' may go wild when wrongly called without its third -argument and with a large subject]], -report = [[Florian Berger, on 10/2007]], -since = [[5.1]], -example = [[ -x = string.rep('a', 10000) .. string.rep('b', 10000) -print(#string.gsub(x, 'b')) -]], -patch = [[ -lstrlib.c: -@@ -631,6 +631,2 @@ - } -- default: { -- luaL_argerror(L, 3, "string/function/table expected"); -- return; -- } - } -@@ -650,2 +646,3 @@ - const char *p = luaL_checkstring(L, 2); -+ int tr = lua_type(L, 3); - int max_s = luaL_optint(L, 4, srcl+1); -@@ -655,2 +652,5 @@ - luaL_Buffer b; -+ luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || -+ tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, -+ "string/function/table expected"); - luaL_buffinit(L, &b); -]], -} - -Bug{ -what = [[table.remove removes last element of a table when given -an out-of-bound index]], -report = [[Patrick Donnelly, on 11/2007]], -since = [[5.0]], -example = [[ -a = {1,2,3} -table.remove(a, 4) -print(a[3]) --> nil (should be 3) -]], -patch = [[ -ltablib.c: -@@ -118,7 +118,8 @@ - static int tremove (lua_State *L) { - int e = aux_getn(L, 1); - int pos = luaL_optint(L, 2, e); -- if (e == 0) return 0; /* table is `empty' */ -+ if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ -+ return 0; /* nothing to remove */ - luaL_setn(L, 1, e - 1); /* t.n = n-1 */ - lua_rawgeti(L, 1, pos); /* result = t[pos] */ - for ( ;pos debug.setfenv(3, {}) -]], -patch = [[ -lapi.c: -@@ -749,7 +749,7 @@ - res = 0; - break; - } -- luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); -+ if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); - L->top--; - lua_unlock(L); - return res; -]], -} - -Bug{ -what = [[stand-alone interpreter shows incorrect error message -when the "message" is a coroutine]], -report = [[Patrick Donnelly, on 17/12/2007]], -since = [[5.1]], -example = [[> error(coroutine.create(function() end))]], -patch = [[ -lua.c: -@@ -74,6 +74,8 @@ - - - static int traceback (lua_State *L) { -+ if (!lua_isstring(L, 1)) /* 'message' not a string? */ -+ return 1; /* keep it intact */ - lua_getfield(L, LUA_GLOBALSINDEX, "debug"); - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - -]], -} - -Bug{ -what = [[debug.sethook/gethook may overflow the thread's stack]], -report = [[Ivko Stanilov, on 2008/01/04]], -since = [[5.1]], -example = [[ -a = coroutine.create(function() yield() end) -coroutine.resume(a) -debug.sethook(a) -- may overflow the stack of 'a' -]], -patch = [[ -ldblib.c: -@@ -268,12 +268,11 @@ - count = luaL_optint(L, arg+3, 0); - func = hookf; mask = makemask(smask, count); - } -- gethooktable(L1); -- lua_pushlightuserdata(L1, L1); -+ gethooktable(L); -+ lua_pushlightuserdata(L, L1); - lua_pushvalue(L, arg+1); -- lua_xmove(L, L1, 1); -- lua_rawset(L1, -3); /* set new hook */ -- lua_pop(L1, 1); /* remove hook table */ -+ lua_rawset(L, -3); /* set new hook */ -+ lua_pop(L, 1); /* remove hook table */ - lua_sethook(L1, func, mask, count); /* set hooks */ - return 0; - } -@@ -288,11 +287,10 @@ - if (hook != NULL && hook != hookf) /* external hook? */ - lua_pushliteral(L, "external hook"); - else { -- gethooktable(L1); -- lua_pushlightuserdata(L1, L1); -- lua_rawget(L1, -2); /* get hook */ -- lua_remove(L1, -2); /* remove hook table */ -- lua_xmove(L1, L, 1); -+ gethooktable(L); -+ lua_pushlightuserdata(L, L1); -+ lua_rawget(L, -2); /* get hook */ -+ lua_remove(L, -2); /* remove hook table */ - } - lua_pushstring(L, unmakemask(mask, buff)); - lua_pushinteger(L, lua_gethookcount(L1)); -]] -} - - - ------------------------------------------------------------------ --- Lua 5.1.3 - -Bug{ -what = [[LUAI_MAXCSTACK must be smaller than -LUA_REGISTRYINDEX]], -report = [[Patrick Donnelly, on 2008/02/11]], -since = [[5.1.3]], -example = [[ -j = 1e4 -co = coroutine.create(function() - t = {} - for i = 1, j do t[i] = i end - return unpack(t) -end) -print(coroutine.resume(co)) -]], -patch = [[ -luaconf.h: -443c443,444 -< ** functions to consume unlimited stack space. ---- -> ** functions to consume unlimited stack space. (must be smaller than -> ** -LUA_REGISTRYINDEX) -445,446c446 -< #define LUAI_MCS_AUX ((int)(INT_MAX / (4*sizeof(LUA_NUMBER)))) -< #define LUAI_MAXCSTACK (LUAI_MCS_AUX > SHRT_MAX ? SHRT_MAX : LUAI_MCS_AUX) ---- -> #define LUAI_MAXCSTACK 8000 -]], -} - -Bug{ -what = [[coroutine.resume pushes element without ensuring stack size]], -report = [[on 2008/02/11]], -since = [[5.0]], -example = [[(this bug cannot be detected without internal assertions)]], -patch = [[ -lbaselib.c: -@@ -526,7 +526,7 @@ - status = lua_resume(co, narg); - if (status == 0 || status == LUA_YIELD) { - int nres = lua_gettop(co); -- if (!lua_checkstack(L, nres)) -+ if (!lua_checkstack(L, nres + 1)) - luaL_error(L, "too many results to resume"); - lua_xmove(co, L, nres); /* move yielded values */ - return nres; -]], -} - -Bug{ -what = [[lua_checkstack may have arithmetic overflow for large 'size']], -report = [[Patrick Donnelly, on 2008/02/12]], -since = [[5.0]], -example = [[ -print(unpack({1,2,3}, 0, 2^31-3)) -]], -patch = [[ ---- lapi.c 2008/01/03 15:20:39 2.55.1.3 -+++ lapi.c 2008/02/14 16:05:21 -@@ -93,15 +93,14 @@ - - - LUA_API int lua_checkstack (lua_State *L, int size) { -- int res; -+ int res = 1; - lua_lock(L); -- if ((L->top - L->base + size) > LUAI_MAXCSTACK) -+ if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK) - res = 0; /* stack overflow */ -- else { -+ else if (size > 0) { - luaD_checkstack(L, size); - if (L->ci->top < L->top + size) - L->ci->top = L->top + size; -- res = 1; - } - lua_unlock(L); - return res; -]], -} - -Bug{ -what = [[unpack with maximum indices may crash due to arithmetic overflow]], -report = [[Patrick Donnelly, on 2008/02/12]], -since = [[5.1]], -example = [[ -print(unpack({1,2,3}, 2^31-1, 2^31-1)) -]], -patch = [[ ---- lbaselib.c 2008/02/11 16:24:24 1.191.1.5 -+++ lbaselib.c 2008/02/14 16:10:25 -@@ -344,10 +344,12 @@ - luaL_checktype(L, 1, LUA_TTABLE); - i = luaL_optint(L, 2, 1); - e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); -+ if (i > e) return 0; /* empty range */ - n = e - i + 1; /* number of elements */ -- if (n <= 0) return 0; /* empty range */ -- luaL_checkstack(L, n, "table too big to unpack"); -- for (; i<=e; i++) /* push arg[i...e] */ -+ if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ -+ return luaL_error(L, "too many results to unpack"); -+ lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ -+ while (i++ < e) /* push arg[i + 1...e] */ - lua_rawgeti(L, 1, i); - return n; - } -]], -} - -Bug{ -what = [[The validator for precompiled code has several flaws that -allow malicious binary code to crash the application]], -report = [[Peter Cawley, on 2008/03/24]], -since = [[5.0]], -example = [[ -a = string.dump(function()return;end) -a = a:gsub(string.char(30,37,122,128), string.char(34,0,0), 1) -loadstring(a)() -]], -patch = [[ ---- ldebug.c 2007/12/28 15:32:23 2.29.1.3 -+++ ldebug.c 2008/04/04 15:15:40 -@@ -275,12 +275,12 @@ - - static int precheck (const Proto *pt) { - check(pt->maxstacksize <= MAXSTACK); -- lua_assert(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); -- lua_assert(!(pt->is_vararg & VARARG_NEEDSARG) || -+ check(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); -+ check(!(pt->is_vararg & VARARG_NEEDSARG) || - (pt->is_vararg & VARARG_HASARG)); - check(pt->sizeupvalues <= pt->nups); - check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); -- check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); -+ check(pt->sizecode > 0 && GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); - return 1; - } - -@@ -363,7 +363,11 @@ - } - switch (op) { - case OP_LOADBOOL: { -- check(c == 0 || pc+2 < pt->sizecode); /* check its jump */ -+ if (c == 1) { /* does it jump? */ -+ check(pc+2 < pt->sizecode); /* check its jump */ -+ check(GET_OPCODE(pt->code[pc+1]) != OP_SETLIST || -+ GETARG_C(pt->code[pc+1]) != 0); -+ } - break; - } - case OP_LOADNIL: { -@@ -428,7 +432,10 @@ - } - case OP_SETLIST: { - if (b > 0) checkreg(pt, a + b); -- if (c == 0) pc++; -+ if (c == 0) { -+ pc++; -+ check(pc < pt->sizecode - 1); -+ } - break; - } - case OP_CLOSURE: { -]], -} - -Bug{ -what = [[maliciously crafted precompiled code can blow the C stack]], -report = [[Greg Falcon, on 2008/03/25]], -since = [[5.0]], -example = [[ -function crash(depth) - local init = '\27\76\117\97\81\0\1\4\4\4\8\0\7\0\0\0\61\115\116' .. - '\100\105\110\0\1\0\0\0\1\0\0\0\0\0\0\2\2\0\0\0\36' .. - '\0\0\0\30\0\128\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0' .. - '\1\0\0\0\0\0\0\2' - local mid = '\1\0\0\0\30\0\128\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\0' - local fin = '\0\0\0\0\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0' .. - '\0\0\97\0\1\0\0\0\1\0\0\0\0\0\0\0' - local lch = '\2\0\0\0\36\0\0\0\30\0\128\0\0\0\0\0\1\0\0\0\0\0\0' .. - '\0\1\0\0\0\1\0\0\0\0\0\0\2' - local rch = '\0\0\0\0\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0' .. - '\0\0\97\0\1\0\0\0\1' - for i=1,depth do lch,rch = lch..lch,rch..rch end - loadstring(init .. lch .. mid .. rch .. fin) -end -for i=1,25 do print(i); crash(i) end -]], -patch = [[ ---- lundump.c 2008/04/04 16:00:45 2.7.1.3 -+++ lundump.c 2008/04/04 19:51:41 2.7.1.4 -@@ -161,7 +161,9 @@ - - static Proto* LoadFunction(LoadState* S, TString* p) - { -- Proto* f=luaF_newproto(S->L); -+ Proto* f; -+ if (++S->L->nCcalls > LUAI_MAXCCALLS) error(S,"code too deep"); -+ f=luaF_newproto(S->L); - setptvalue2s(S->L,S->L->top,f); incr_top(S->L); - f->source=LoadString(S); if (f->source==NULL) f->source=p; - f->linedefined=LoadInt(S); -@@ -175,6 +177,7 @@ - LoadDebug(S,f); - IF (!luaG_checkcode(f), "bad code"); - S->L->top--; -+ S->L->nCcalls--; - return f; - } -]], -} - -Bug{ -what = [[code validator may reject (maliciously crafted) correct code]], -report = [[Greg Falcon, on 2008/03/26]], -since = [[5.0]], -example = [[ -z={} -for i=1,27290 do z[i]='1,' end -z = 'if 1+1==2 then local a={' .. table.concat(z) .. '} end' -func = loadstring(z) -print(loadstring(string.dump(func))) -]], -patch = [[ ---- ldebug.c 2008/04/04 15:30:05 2.29.1.4 -+++ ldebug.c 2008/04/04 15:47:10 -@@ -346,9 +346,18 @@ - int dest = pc+1+b; - check(0 <= dest && dest < pt->sizecode); - if (dest > 0) { -- /* cannot jump to a setlist count */ -- Instruction d = pt->code[dest-1]; -- check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)); -+ int j; -+ /* check that it does not jump to a setlist count; this -+ is tricky, because the count from a previous setlist may -+ have the same value of an invalid setlist; so, we must -+ go all the way back to the first of them (if any) */ -+ for (j = 0; j < dest; j++) { -+ Instruction d = pt->code[dest-1-j]; -+ if (!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)) break; -+ } -+ /* if 'j' is even, previous value is not a setlist (even if -+ it looks like one) */ -+ check((j&1) == 0); - } - } - break; -]], -} - -Bug{ -what = [[maliciously crafted precompiled code can inject invalid boolean -values into Lua code]], -report = [[Greg Falcon, on 2008/03/27]], -since = [[5.0]], -example = [[ -maybe = string.dump(function() return ({[true]=true})[true] end) -maybe = maybe:gsub('\1\1','\1\2') -maybe = loadstring(maybe)() -assert(type(maybe) == "boolean" and maybe ~= true and maybe ~= false) -]], -patch = [[ ---- lundump.c 2008/01/18 16:39:11 2.7.1.2 -+++ lundump.c 2008/04/04 15:50:39 -@@ -115,7 +115,7 @@ - setnilvalue(o); - break; - case LUA_TBOOLEAN: -- setbvalue(o,LoadChar(S)); -+ setbvalue(o,LoadChar(S)!=0); - break; - case LUA_TNUMBER: - setnvalue(o,LoadNumber(S)); -]], -} - - -Bug{ -what = [['string.byte' gets confused with some out-of-range negative indices]], -report = [[Mike Pall, on 2008/06/03]], -since = [[5.1]], -example = [[ -print(string.byte("abc", -5)) --> 97 98 99 (should print nothing) -]], -patch = [[ ---- lstrlib.c 2007/12/28 15:32:23 1.132.1.3 -+++ lstrlib.c 2008/07/05 11:53:42 -@@ -35,7 +35,8 @@ - - static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { - /* relative string position: negative means back from end */ -- return (pos>=0) ? pos : (ptrdiff_t)len+pos+1; -+ if (pos < 0) pos += (ptrdiff_t)len + 1; -+ return (pos >= 0) ? pos : 0; - } - - -]], -} - - -Bug{ -what = [[user-requested GC step may loop forever]], -report = [[Makoto Hamanaka, on 2008/07/01]], -since = [[5.1]], -example = [[ -collectgarbage("setpause", 100) -- small value -collectgarbage("setstepmul", 2000) -- large value -collectgarbage("step",0) -]], -patch = [[ ---- lapi.c 2008/02/14 16:46:39 2.55.1.4 -+++ lapi.c 2008/07/04 18:34:48 -@@ -929,10 +929,13 @@ - g->GCthreshold = g->totalbytes - a; - else - g->GCthreshold = 0; -- while (g->GCthreshold <= g->totalbytes) -+ while (g->GCthreshold <= g->totalbytes) { - luaC_step(L); -- if (g->gcstate == GCSpause) /* end of cycle? */ -- res = 1; /* signal it */ -+ if (g->gcstate == GCSpause) { /* end of cycle? */ -+ res = 1; /* signal it */ -+ break; -+ } -+ } - break; - } - case LUA_GCSETPAUSE: { -]], -} - - -Bug{ -what = [['module' may change the environment of a C function]], -report = [[Peter Cawley, on 2008/07/16]], -since = [[5.1]], -example = [[ -pcall(module, "xuxu") -assert(debug.getfenv(pcall) == xuxu) -]], -patch = [[ ---- loadlib.c 2007/12/28 14:58:43 1.52.1.2 -+++ loadlib.c 2008/08/05 19:39:00 -@@ -506,8 +506,11 @@ - - static void setfenv (lua_State *L) { - lua_Debug ar; -- lua_getstack(L, 1, &ar); -- lua_getinfo(L, "f", &ar); -+ if (lua_getstack(L, 1, &ar) == 0 || -+ lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ -+ lua_iscfunction(L, -1)) -+ luaL_error(L, "function " LUA_QL("module") -+ " not called from a Lua function"); - lua_pushvalue(L, -2); - lua_setfenv(L, -2); - lua_pop(L, 1); -]], -} - - -Bug{ -what = [[internal macro 'svalue' is wrong]], -report = [[Martijn van Buul, on 2008/08/04]], -since = [[5.1]], -example = [[ -/* in luaconf.h */ -#define LUAI_USER_ALIGNMENT_T union { char b[32]; } -]], -patch = [[ ---- lobject.h 2007/12/27 13:02:25 2.20.1.1 -+++ lobject.h 2008/08/05 19:40:48 -@@ -210,3 +210,3 @@ - #define getstr(ts) cast(const char *, (ts) + 1) --#define svalue(o) getstr(tsvalue(o)) -+#define svalue(o) getstr(rawtsvalue(o)) - -]], -} - - ------------------------------------------------------------------ --- Lua 5.1.4 - -Bug{ -what = [[malicious zero-length string in binary code may segfault Lua]], -report = [[Peter Cawley, on 2008/09/01]], -since = [[5.1]], -example = [[ -loadstring(('').dump(function()X''end):gsub('\2%z%z%zX','\0\0\0'))() -]], -patch = [[ -]], -} - - -Bug{ -what = [[wrong code generation for some particular boolean expressions]], -report = [[Brian Kelley, on 2009/04/15]], -since = [[5.0]], -example = [[ -print(((1 or false) and true) or false) --> 1 --- should be 'true' -]], -patch = [[ ---- lcode.c 2007/12/28 15:32:23 2.25.1.3 -+++ lcode.c 2009/06/15 14:07:34 -@@ -544,15 +544,18 @@ - pc = NO_JUMP; /* always true; do nothing */ - break; - } -- case VFALSE: { -- pc = luaK_jump(fs); /* always jump */ -- break; -- } - case VJMP: { - invertjump(fs, e); - pc = e->u.s.info; - break; - } -+ case VFALSE: { -+ if (!hasjumps(e)) { -+ pc = luaK_jump(fs); /* always jump */ -+ break; -+ } -+ /* else go through */ -+ } - default: { - pc = jumponcond(fs, e, 0); - break; -@@ -572,14 +575,17 @@ - pc = NO_JUMP; /* always false; do nothing */ - break; - } -- case VTRUE: { -- pc = luaK_jump(fs); /* always jump */ -- break; -- } - case VJMP: { - pc = e->u.s.info; - break; - } -+ case VTRUE: { -+ if (!hasjumps(e)) { -+ pc = luaK_jump(fs); /* always jump */ -+ break; -+ } -+ /* else go through */ -+ } - default: { - pc = jumponcond(fs, e, 1); - break; -]], -} - -Bug{ -what = [['luaV_settable' may invalidate a reference to a table and try -to reuse it]], -report = [[Mark Feldman, on 2009/06/27]], -since = [[5.0]], -example = [[ -grandparent = {} -grandparent.__newindex = function(s,_,_) print(s) end - -parent = {} -parent.__newindex = parent -setmetatable(parent, grandparent) - -child = setmetatable({}, parent) -child.foo = 10 --> (crash on some machines) -]], -patch = [[ ---- lvm.c 2007/12/28 15:32:23 2.63.1.3 -+++ lvm.c 2009/07/01 20:36:59 -@@ -133,6 +133,7 @@ - - void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { - int loop; -+ TValue temp; - for (loop = 0; loop < MAXTAGLOOP; loop++) { - const TValue *tm; - if (ttistable(t)) { /* `t' is a table? */ -@@ -152,7 +153,9 @@ - callTM(L, tm, t, key, val); - return; - } -- t = tm; /* else repeat with `tm' */ -+ /* else repeat with `tm' */ -+ setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ -+ t = &temp; - } - luaG_runerror(L, "loop in settable"); - } -]], -} - -Bug{ -what = [[smart use of varargs may create functions that return too -many arguments and overflow the stack of C functions]], -report = [[Patrick Donnelly, on 2008/12/10]], -since = [[]], -example = [[ -local function lunpack(i, ...) - if i == 0 then return ... - else - return lunpack(i-1, 1, ...) - end -end - -Now, if C calls lunpack(n) with a huge n, it may end with -too many values in its stack and confuse its stack indices. -]], -patch = [[ -]], -} - -Bug{ -what = [['debug.getfenv' does not check whether it has an argument]], -report = [[Patrick Donnelly, 2009/07/30]], -since = [[5.1]], -example = [[debug.getfenv() -- should raise an error]], -patch = [[ ---- ldblib.c 2008/01/21 13:11:21 1.104.1.3 -+++ ldblib.c 2009/08/04 18:43:12 -@@ -45,6 +45,7 @@ - - - static int db_getfenv (lua_State *L) { -+ luaL_checkany(L, 1); - lua_getfenv(L, 1); - return 1; - } -]], -} - -Bug{ -what = [[GC may get stuck during a parser and avoids proper resizing of -the string table, -making its lists grow too much and degrading performance]], -report = [[Sean Conner, 2009/11/10]], -since = [[5.1]], -example = [[See http://lua-users.org/lists/lua-l/2009-11/msg00463.html]], -patch = [[ ---- llex.c 2007/12/27 13:02:25 2.20.1.1 -+++ llex.c 2009/11/23 14:49:40 -@@ -118,8 +118,10 @@ - lua_State *L = ls->L; - TString *ts = luaS_newlstr(L, str, l); - TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ -- if (ttisnil(o)) -+ if (ttisnil(o)) { - setbvalue(o, 1); /* make sure `str' will not be collected */ -+ luaC_checkGC(L); -+ } - return ts; - } - -]] -} - -Bug{ -what = [['string.format' may get buffer as an argument when there are -missing arguments and format string is too long]], -report = [[Roberto I., 2010/04/12]], -since = [[5.0]], -example = [[ -x = string.rep("x", 10000) .. "%d" -print(string.format(x)) -- gives wrong error message -]], -patch = [[ ---- lstrlib.c 2008/07/11 17:27:21 1.132.1.4 -+++ lstrlib.c 2010/05/14 15:12:53 -@@ -754,6 +754,7 @@ - - - static int str_format (lua_State *L) { -+ int top = lua_gettop(L); - int arg = 1; - size_t sfl; - const char *strfrmt = luaL_checklstring(L, arg, &sfl); -@@ -768,7 +769,8 @@ - else { /* format item */ - char form[MAX_FORMAT]; /* to store the format (`%...') */ - char buff[MAX_ITEM]; /* to store the formatted item */ -- arg++; -+ if (++arg > top) -+ luaL_argerror(L, arg, "no value"); - strfrmt = scanformat(L, strfrmt, form); - switch (*strfrmt++) { - case 'c': { -]] -} - -Bug{ -what = [['io.read(op, "*n")' may return garbage if second read fails]], -report = [[Roberto I., 2010/04/12]], -since = [[5.0]], -example = [[ -print(io.read("*n", "*n")) --<< enter "10 hi" ---> file (0x884420) nil -]], -patch = [[ ---- liolib.c 2008/01/18 17:47:43 2.73.1.3 -+++ liolib.c 2010/05/14 15:29:29 -@@ -276,7 +276,10 @@ - lua_pushnumber(L, d); - return 1; - } -- else return 0; /* read fails */ -+ else { -+ lua_pushnil(L); /* "result" to be removed */ -+ return 0; /* read fails */ -+ } - } - - -]] -} - -Bug{ -what = [[wrong code generation for some particular boolean expressions]], -report = [[Thierry Van Elsuwe, 2011/01/20]], -since = [[5.0]], -example = [[ -print((('hi' or true) and true) or true) ---> hi (should be true) -print(((nil and nil) or false) and true) ---> nil (should be false) -]], -patch = [[ ---- lcode.c 2009/06/15 14:12:25 2.25.1.4 -+++ lcode.c 2011/01/31 14:44:25 -@@ -549,13 +549,6 @@ - pc = e->u.s.info; - break; - } -- case VFALSE: { -- if (!hasjumps(e)) { -- pc = luaK_jump(fs); /* always jump */ -- break; -- } -- /* else go through */ -- } - default: { - pc = jumponcond(fs, e, 0); - break; -@@ -579,13 +572,6 @@ - pc = e->u.s.info; - break; - } -- case VTRUE: { -- if (!hasjumps(e)) { -- pc = luaK_jump(fs); /* always jump */ -- break; -- } -- /* else go through */ -- } - default: { - pc = jumponcond(fs, e, 1); - break; -]] -} - -Bug{ -what = [[__newindex metamethod may not work if metatable is its own -metatable]], -report = [[Cuero Bugot, 2011/08/09]], -since = [[5.1]], -example = [[ -meta={} -setmetatable(meta, meta) -meta.__newindex = function(t, key, value) print("set") end -o = setmetatable({}, meta) -o.x = 10 -- should print 'set' -]], -patch = [[ ---- lvm.c 2009/07/01 21:10:33 2.63.1.4 -+++ lvm.c 2011/08/17 20:36:28 -@@ -142,6 +142,7 @@ - if (!ttisnil(oldval) || /* result is no nil? */ - (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ - setobj2t(L, oldval, val); -+ h->flags = 0; - luaC_barriert(L, h, val); - return; - } -]] -} - -Bug{ -what = [[parser may collect a prototype while building it]], -report = [[Ingo van Lil, 2011/10/13]], -since = [[5.1.4 (caused by patch 5.1.4-6)]], -example = nil, -patch = [[ ---- lparser.c 2007/12/28 15:32:23 2.42.1.3 -+++ lparser.c 2011/10/17 13:10:43 -@@ -374,9 +374,9 @@ - lua_assert(luaG_checkcode(f)); - lua_assert(fs->bl == NULL); - ls->fs = fs->prev; -- L->top -= 2; /* remove table and prototype from the stack */ - /* last token read was anchored in defunct function; must reanchor it */ - if (fs) anchor_token(ls); -+ L->top -= 2; /* remove table and prototype from the stack */ - } - - -]] -} - - -Bug{ -what = [[When loading a file, -Lua may call the reader function again after it returned end of input -]], -report = [[Chris Howie, 2013/06/05]], -since = [[5.1]], -fix = [[5.2]], -example = [[ -load(function () print("called"); return nil end) ---> called ---> called (should be called only once!) -]], -patch = [[ ---- lzio.h 2007/12/27 13:02:25 1.21.1.1 -+++ lzio.h 2013/07/04 13:55:59 -@@ -59,6 +59,7 @@ - lua_Reader reader; - void* data; /* additional data */ - lua_State *L; /* Lua state (for reader) */ -+ int eoz; /* true if reader has no more data */ - }; - - ---- lzio.c 2007/12/27 13:02:25 1.31.1.1 -+++ lzio.c 2013/07/04 13:53:06 -@@ -22,10 +22,14 @@ - size_t size; - lua_State *L = z->L; - const char *buff; -+ if (z->eoz) return EOZ; - lua_unlock(L); - buff = z->reader(L, z->data, &size); - lua_lock(L); -- if (buff == NULL || size == 0) return EOZ; -+ if (buff == NULL || size == 0) { -+ z->eoz = 1; /* avoid calling reader function next time */ -+ return EOZ; -+ } - z->n = size - 1; - z->p = buff; - return char2int(*(z->p++)); -@@ -51,6 +55,7 @@ - z->data = data; - z->n = 0; - z->p = NULL; -+ z->eoz = 0; - } -]] -} - - ------------------------------------------------------------------ --- Lua 5.2.0 - -Bug{ -what = [[memory hoarding when creating Lua hooks for coroutines]], -report = [[Arseny Vakhrushev, 2012/01/16]], -since = [[5.1]], -fix = [[5.2.1]], -example = [[ -collectgarbage(); print(collectgarbage'count' * 1024) - -for i = 1, 100 do - local co = coroutine.create(function () end) - local x = {} - for j=1,1000 do x[j] = j end - debug.sethook(co, function () return x end, 'l') -end - -collectgarbage(); print(collectgarbage'count' * 1024) --- value should back to near the original level -]], -patch = [[ --- For 5.2 - ---- ldblib.c 2011/10/24 14:54:05 1.131 -+++ ldblib.c 2012/01/18 02:36:59 -@@ -253,14 +253,15 @@ - } - - --#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY); -+#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY) - - - static void hookf (lua_State *L, lua_Debug *ar) { - static const char *const hooknames[] = - {"call", "return", "line", "count", "tail call"}; - gethooktable(L); -- lua_rawgetp(L, -1, L); -+ lua_pushthread(L); -+ lua_rawget(L, -2); - if (lua_isfunction(L, -1)) { - lua_pushstring(L, hooknames[(int)ar->event]); - if (ar->currentline >= 0) -@@ -306,10 +307,15 @@ - count = luaL_optint(L, arg+3, 0); - func = hookf; mask = makemask(smask, count); - } -- gethooktable(L); -+ if (gethooktable(L) == 0) { /* creating hook table? */ -+ lua_pushstring(L, "k"); -+ lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ -+ lua_pushvalue(L, -1); -+ lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ -+ } -+ lua_pushthread(L1); lua_xmove(L1, L, 1); - lua_pushvalue(L, arg+1); -- lua_rawsetp(L, -2, L1); /* set new hook */ -- lua_pop(L, 1); /* remove hook table */ -+ lua_rawset(L, -3); /* set new hook */ - lua_sethook(L1, func, mask, count); /* set hooks */ - return 0; - } -@@ -325,7 +331,8 @@ - lua_pushliteral(L, "external hook"); - else { - gethooktable(L); -- lua_rawgetp(L, -1, L1); /* get hook */ -+ lua_pushthread(L1); lua_xmove(L1, L, 1); -+ lua_rawget(L, -2); /* get hook */ - lua_remove(L, -2); /* remove hook table */ - } - lua_pushstring(L, unmakemask(mask, buff)); -]] -} - -Bug{ -what = [[Lexical gets confused with some combination of arithmetic -operators and hexadecimal numbers]], -report = [[Alexandra Barros, 2012/01/17]], -since = [[5.2.0]], -fix = [[5.2.1]], -example = [[print(0xE+1)]], -patch = [[ ---- llex.c 2011/11/30 12:43:51 2.59 -+++ llex.c 2012/01/20 18:22:50 -@@ -223,12 +223,19 @@ - - /* LUA_NUMBER */ - static void read_numeral (LexState *ls, SemInfo *seminfo) { -+ const char *expo = "Ee"; -+ int first = ls->current; - lua_assert(lisdigit(ls->current)); -- do { -- save_and_next(ls); -- if (check_next(ls, "EePp")) /* exponent part? */ -+ save_and_next(ls); -+ if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */ -+ expo = "Pp"; -+ for (;;) { -+ if (check_next(ls, expo)) /* exponent part? */ - check_next(ls, "+-"); /* optional exponent sign */ -- } while (lislalnum(ls->current) || ls->current == '.'); -+ if (lisxdigit(ls->current) || ls->current == '.') -+ save_and_next(ls); -+ else break; -+ } - save(ls, '\0'); - buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ - if (!buff2d(ls->buff, &seminfo->r)) /* format error? */ -]] -} - -Bug{ -what = [[Finalizers may call functions from a dynamic library after -the library has been unloaded]], -report = [[Josh Haberman, 2012/04/08]], -since = [[5.1]], -fix = [[5.2.1]], -example = [[ -local u = setmetatable({}, {__gc = function () foo() end}) -local m = require 'mod' -- 'mod' may be any dynamic library written in C -foo = m.foo -- 'foo' may be any function from 'mod' --- end program; it crashes -]], -patch = [[ -loadlib.c: -95c95 -< #define LIBPREFIX "LOADLIB: " ---- -> #define CLIBS "_CLIBS" -251,266c251,256 -< -< static void **ll_register (lua_State *L, const char *path) { -< void **plib; -< lua_pushfstring(L, "%s%s", LIBPREFIX, path); -< lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ -< if (!lua_isnil(L, -1)) /* is there an entry? */ -< plib = (void **)lua_touserdata(L, -1); -< else { /* no entry yet; create one */ -< lua_pop(L, 1); /* remove result from gettable */ -< plib = (void **)lua_newuserdata(L, sizeof(const void *)); -< *plib = NULL; -< luaL_setmetatable(L, "_LOADLIB"); -< lua_pushfstring(L, "%s%s", LIBPREFIX, path); -< lua_pushvalue(L, -2); -< lua_settable(L, LUA_REGISTRYINDEX); -< } ---- -> static void *ll_checkclib (lua_State *L, const char *path) { -> void *plib; -> lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); -> lua_getfield(L, -1, path); -> plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ -> lua_pop(L, 2); /* pop CLIBS table and 'plib' */ -270a261,270 -> static void ll_addtoclib (lua_State *L, const char *path, void *plib) { -> lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); -> lua_pushlightuserdata(L, plib); -> lua_pushvalue(L, -1); -> lua_setfield(L, -3, path); /* CLIBS[path] = plib */ -> lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ -> lua_pop(L, 1); /* pop CLIBS table */ -> } -> -> -272,273c272,273 -< ** __gc tag method: calls library's `ll_unloadlib' function with the lib -< ** handle ---- -> ** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib -> ** handles in list CLIBS -276,278c276,281 -< void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); -< if (*lib) ll_unloadlib(*lib); -< *lib = NULL; /* mark library as closed */ ---- -> int n = luaL_len(L, 1); -> for (; n >= 1; n--) { /* for each handle, in reverse order */ -> lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ -> ll_unloadlib(lua_touserdata(L, -1)); -> lua_pop(L, 1); /* pop handle */ -> } -284,286c287,292 -< void **reg = ll_register(L, path); -< if (*reg == NULL) *reg = ll_load(L, path, *sym == '*'); -< if (*reg == NULL) return ERRLIB; /* unable to load library */ ---- -> void *reg = ll_checkclib(L, path); /* check loaded C libraries */ -> if (reg == NULL) { /* must load library? */ -> reg = ll_load(L, path, *sym == '*'); -> if (reg == NULL) return ERRLIB; /* unable to load library */ -> ll_addtoclib(L, path, reg); -> } -292c298 -< lua_CFunction f = ll_sym(L, *reg, sym); ---- -> lua_CFunction f = ll_sym(L, reg, sym); -675,676c681,683 -< /* create new type _LOADLIB */ -< luaL_newmetatable(L, "_LOADLIB"); ---- -> /* create table CLIBS to keep track of loaded C libraries */ -> luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); -> lua_createtable(L, 0, 1); /* metatable for CLIBS */ -678a686 -> lua_setmetatable(L, -2); -]] -} - -Bug{ -what = [[wrong handling of 'nCcalls' in coroutines]], -report = [[Alexander Gavrilov, 2012/04/18]], -since = [[5.2.0]], -fix = [[5.2.1]], -example = [[ -coroutine.wrap(function() - print(pcall(pcall,pcall,pcall,pcall,pcall,error,3)) -end)() -]], -patch = [[ ---- ldo.c 2011/11/29 15:55:08 2.102 -+++ ldo.c 2012/04/26 20:38:32 -@@ -402,8 +402,6 @@ - int n; - lua_assert(ci->u.c.k != NULL); /* must have a continuation */ - lua_assert(L->nny == 0); -- /* finish 'luaD_call' */ -- L->nCcalls--; - /* finish 'lua_callk' */ - adjustresults(L, ci->nresults); - /* call continuation function */ -@@ -513,7 +511,6 @@ - api_checknelems(L, n); - firstArg = L->top - n; /* yield results come from continuation */ - } -- L->nCcalls--; /* finish 'luaD_call' */ - luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ - } - unroll(L, NULL); -]] -} - -Bug{ -what = [[Internal Lua values may escape through the debug API]], -report = [[Dan Tull, 2012/04/20]], -since = [[5.1]], -fix = [[5.2.1]], -example = [[ --- for Lua 5.1 -local firsttime = true -local function foo () - if firsttime then - firsttime = false - return "a = 1" - else - for i = 1, 10 do - print(debug.getlocal(2, i)) - end - end -end - -print(load(foo)) -- prints some lines and then seg. fault. -]], -patch = [[ -]] -} - -Bug{ -what = [[Problems when yielding from debug hooks]], -report = [[Erik Cassel, 2012/06/05]], -since = [[5.2.0]], -fix = [[5.2.1]], -example = [[ -Set, in C, a line hook that simply yields, -and then call any Lua function. -You get an infinite loop of yields. -]], -patch = [[ -]] -} - - ------------------------------------------------------------------ --- Lua 5.2.1 - -Bug{ -what = [[Some patterns can overflow the C stack, due to recursion]], -report = [[Tim Starling, 2012/07/08]], -since = [[2.5]], -fix = [[5.2.2]], -example = [[print(string.find(string.rep("a", 2^20), string.rep(".?", 2^20)))]], -patch = [[ -]] -} - - -Bug{ -what = [['pcall' may not restore previous error function when -inside coroutines]], -report = [[Alexander Gavrilov, 2012/06/12]], -since = [[5.2.0]], -fix = [[5.2.2]], -example = [[ -function errfunc(x) - return 'errfunc' -end - -function test(do_yield) - print(do_yield and "yielding" or "not yielding") - pcall(function() -- this pcall sets errfunc back to none - if do_yield then - coroutine.yield() -- stops errfunc from being restored - end - end) - error('fail!') -end - -coro = coroutine.wrap(function() - print(xpcall(test, errfunc, false)) - print(xpcall(test, errfunc, true)) - print(xpcall(test, errfunc, false)) -end) - -coro() ---> not yielding ---> false errfunc ---> yielding -coro() ---> false temp:12: fail! <<<< should be 'errfunc' too ---> not yielding ---> false errfunc -]], -patch = [[ ---- ldo.c 2012/08/28 18:30:45 2.107 -+++ ldo.c 2012/09/23 15:49:55 -@@ -403,7 +403,11 @@ - int n; - lua_assert(ci->u.c.k != NULL); /* must have a continuation */ - lua_assert(L->nny == 0); -- /* finish 'lua_callk' */ -+ if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ -+ ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */ -+ L->errfunc = ci->u.c.old_errfunc; -+ } -+ /* finish 'lua_callk'/'lua_pcall' */ - adjustresults(L, ci->nresults); - /* call continuation function */ - if (!(ci->callstatus & CIST_STAT)) /* no call status? */ -]] -} - -Bug{ -what = [[Check for garbage collector in function calls does not cover -all paths]], -report = [[Roberto, 2012/08/15]], -since = [[5.2.1]], -fix = [[5.2.2]], -example = [[ -See -http://lua-users.org/lists/lua-l/2012-08/msg00149.html -]], -patch = [[ -@@ -311,6 +311,7 @@ - ci->top = L->top + LUA_MINSTACK; - lua_assert(ci->top <= L->stack_last); - ci->callstatus = 0; -+ luaC_checkGC(L); /* stack grow uses memory */ - if (L->hookmask & LUA_MASKCALL) - luaD_hook(L, LUA_HOOKCALL, -1); - lua_unlock(L); -@@ -338,6 +339,7 @@ - ci->u.l.savedpc = p->code; /* starting point */ - ci->callstatus = CIST_LUA; - L->top = ci->top; -+ luaC_checkGC(L); /* stack grow uses memory */ - if (L->hookmask & LUA_MASKCALL) - callhook(L, ci); - return 0; -@@ -393,7 +395,6 @@ - luaV_execute(L); /* call it */ - if (!allowyield) L->nny--; - L->nCcalls--; -- luaC_checkGC(L); - } -]] -} - -Bug{ -what = [[load/loadfile returns wrong result when given an environment -for a binary chunk with no upvalues]], -report = [[Vladimir Strakh, 2012/11/28]], -since = [[5.2.0]], -fix = [[5.2.2]], -example = [[ -f = load(string.dump(function () return 1 end), nil, "b", {}) -print(type(f)) --> table (whould be a function) -]], -patch = [[ ---- lbaselib.c 2012/04/27 14:13:19 1.274 -+++ lbaselib.c 2012/12/03 20:08:15 -@@ -244,5 +244,11 @@ - --static int load_aux (lua_State *L, int status) { -- if (status == LUA_OK) -+static int load_aux (lua_State *L, int status, int envidx) { -+ if (status == LUA_OK) { -+ if (envidx != 0) { /* 'env' parameter? */ -+ lua_pushvalue(L, envidx); /* environment for loaded function */ -+ if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ -+ lua_pop(L, 1); /* remove 'env' if not used by previous call */ -+ } - return 1; -+ } - else { -@@ -258,9 +264,5 @@ - const char *mode = luaL_optstring(L, 2, NULL); -- int env = !lua_isnone(L, 3); /* 'env' parameter? */ -+ int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ - int status = luaL_loadfilex(L, fname, mode); -- if (status == LUA_OK && env) { /* 'env' parameter? */ -- lua_pushvalue(L, 3); -- lua_setupvalue(L, -2, 1); /* set it as 1st upvalue of loaded chunk */ -- } -- return load_aux(L, status); -+ return load_aux(L, status, env); - } -@@ -309,5 +311,5 @@ - size_t l; -- int top = lua_gettop(L); - const char *s = lua_tolstring(L, 1, &l); - const char *mode = luaL_optstring(L, 3, "bt"); -+ int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ - if (s != NULL) { /* loading a string? */ -@@ -322,7 +324,3 @@ - } -- if (status == LUA_OK && top >= 4) { /* is there an 'env' argument */ -- lua_pushvalue(L, 4); /* environment for loaded function */ -- lua_setupvalue(L, -2, 1); /* set it as 1st upvalue */ -- } -- return load_aux(L, status); -+ return load_aux(L, status, env); - } -]] -} - -Bug{ -what = [[Lua does not check memory use when creating error messages]], -report = [[John Dunn, 2012/09/24]], -since = [[5.2.0]], -fix = nil, -example = [[ -local code = "function test()\n bob.joe.larry = 23\n end" - -load(code)() - --- memory will grow steadly -for i = 1, math.huge do - pcall(test) - if i % 100000 == 0 then - io.write(collectgarbage'count'*1024, "\n") - end -end -]], -patch = [[ -]] -} - - - - - ------------------------------------------------------------------ --- Lua 5.2.2 - - -Bug{ -what = [[stack overflow in vararg functions with many fixed -parameters called with few arguments]], -report = [[云风, 2013/04/17]], -since = [[5.1]], -fix = [[5.2.3]], -example = [[ -function f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, - p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, - p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, - p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, - p41, p42, p43, p44, p45, p46, p48, p49, p50, ...) - local a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14 -end - -f() -- seg. fault (on some machines) -]], -patch = [[ ---- ldo.c 2012/10/01 14:05:04 2.108 -+++ ldo.c 2013/04/19 20:56:06 -@@ -324,7 +324,7 @@ - case LUA_TLCL: { /* Lua function: prepare its call */ - StkId base; - Proto *p = clLvalue(func)->p; -- luaD_checkstack(L, p->maxstacksize); -+ luaD_checkstack(L, p->maxstacksize + p->numparams); - func = restorestack(L, funcr); - n = cast_int(L->top - func) - 1; /* number of real arguments */ - for (; n < p->numparams; n++) -]], -} - -Bug{ -what = [[garbage collector can trigger too many times in recursive loops]], -report = [[Roberto, 2013/04/25]], -since = [[5.2.2]], -fix = [[5.2.3]], -example = [[ -function f() f() end -f() -- it takes too long before a "stack overflow" error -]], -patch = [[ ---- lgc.c 2013/04/12 18:48:47 2.140.1.1 -+++ lgc.c 2013/04/25 21:30:20 -@@ -495,2 +495,3 @@ - static lu_mem traversestack (global_State *g, lua_State *th) { -+ int n = 0; - StkId o = th->stack; -@@ -505,3 +506,9 @@ - } -- return sizeof(lua_State) + sizeof(TValue) * th->stacksize; -+ else { /* count call infos to compute size */ -+ CallInfo *ci; -+ for (ci = &th->base_ci; ci != th->ci; ci = ci->next) -+ n++; -+ } -+ return sizeof(lua_State) + sizeof(TValue) * th->stacksize + -+ sizeof(CallInfo) * n; - } -]] -} - --- [[]] -Bug{ -what = [[Wrong assert when reporting concatenation errors -(manifests only when Lua is compiled in debug mode)]], -report = [[Roberto, 2013/05/05]], -since = [[?]], -fix = [[5.2.3]], -example = [[ --- only with Lua compiled in debug mode -print({} .. 2) -]], -patch = [[ ---- ldebug.c 2013/04/12 18:48:47 2.90.1.1 -+++ ldebug.c 2013/05/05 14:38:30 -@@ -519,5 +519,5 @@ - l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) { - if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; -- lua_assert(!ttisstring(p1) && !ttisnumber(p2)); -+ lua_assert(!ttisstring(p1) && !ttisnumber(p1)); - luaG_typeerror(L, p1, "concatenate"); - } -]] -} - -Bug{ -what = [[Wrong error message in some short-cut expressions]], -report = [[Egor Skriptunoff, 2013/05/10]], -since = [[5.0]], -fix = [[5.2.3]], -example = [[ -> a,b,c = true,true,true -> (a and b or c)('', '') -stdin:1: attempt to call a boolean value (global 'c') - - (It should be global 'b' instead of 'c'.) -]], -patch = [[ ---- ldebug.c 2013/05/06 17:20:22 2.90.1.2 -+++ ldebug.c 2013/05/14 19:52:48 -@@ -327,12 +327,20 @@ - } - - -+static int filterpc (int pc, int jmptarget) { -+ if (pc < jmptarget) /* is code conditional (inside a jump)? */ -+ return -1; /* cannot know who sets that register */ -+ else return pc; /* current position sets that register */ -+} -+ -+ - /* - ** try to find last instruction before 'lastpc' that modified register 'reg' - */ - static int findsetreg (Proto *p, int lastpc, int reg) { - int pc; - int setreg = -1; /* keep last instruction that changed 'reg' */ -+ int jmptarget = 0; /* any code before this address is conditional */ - for (pc = 0; pc < lastpc; pc++) { - Instruction i = p->code[pc]; - OpCode op = GET_OPCODE(i); -@@ -341,33 +349,38 @@ - case OP_LOADNIL: { - int b = GETARG_B(i); - if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ -- setreg = pc; -+ setreg = filterpc(pc, jmptarget); - break; - } - case OP_TFORCALL: { -- if (reg >= a + 2) setreg = pc; /* affect all regs above its base */ -+ if (reg >= a + 2) /* affect all regs above its base */ -+ setreg = filterpc(pc, jmptarget); - break; - } - case OP_CALL: - case OP_TAILCALL: { -- if (reg >= a) setreg = pc; /* affect all registers above base */ -+ if (reg >= a) /* affect all registers above base */ -+ setreg = filterpc(pc, jmptarget); - break; - } - case OP_JMP: { - int b = GETARG_sBx(i); - int dest = pc + 1 + b; - /* jump is forward and do not skip `lastpc'? */ -- if (pc < dest && dest <= lastpc) -- pc += b; /* do the jump */ -+ if (pc < dest && dest <= lastpc) { -+ if (dest > jmptarget) -+ jmptarget = dest; /* update 'jmptarget' */ -+ } - break; - } - case OP_TEST: { -- if (reg == a) setreg = pc; /* jumped code can change 'a' */ -+ if (reg == a) /* jumped code can change 'a' */ -+ setreg = filterpc(pc, jmptarget); - break; - } - default: - if (testAMode(op) && reg == a) /* any instruction that set A */ -- setreg = pc; -+ setreg = filterpc(pc, jmptarget); - break; - } - } -]] -} - -Bug{ -what = [[luac listings choke on long strings]], -report = [[Ashwin Hirschi, 2013/07/03]], -since = [[5.1.2]], -fix = [[5.2.3]], -example = [[ --- When you call 'luac -l' over this chunk, it chokes the output -s="Lorem ipsum dolor sit amet, consectetur, " -]], -patch = [[ ---- luac.c 2011-11-29 15:46:33 -0200 1.69 -+++ luac.c 2013-07-03 21:26:01 -0300 -@@ -251,7 +251,7 @@ - static void PrintConstant(const Proto* f, int i) - { - const TValue* o=&f->k[i]; -- switch (ttype(o)) -+ switch (ttypenv(o)) - { - case LUA_TNIL: - printf("nil"); -]] -} - -Bug{ -what = [[GC can collect a long string still in use during parser]], -report = [[Roberto, 2013/08/30]], -since = [[5.2]], -fix = [[5.2.3]], -example = [[This bug is very difficult to happen (and to reproduce), -because it depends on the GC running in a very specific way when -parsing a source code with long (larger than 40 characters) identifiers.]], -patch = [[ ---- ltable.h 2013/04/12 18:48:47 2.16.1.1 -+++ ltable.h 2013/08/30 15:34:24 -@@ -18,4 +18,8 @@ - #define invalidateTMcache(t) ((t)->flags = 0) - -+/* returns the key, given the value of a table entry */ -+#define keyfromval(v) \ -+ (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) -+ - - LUAI_FUNC const TValue *luaH_getint (Table *t, int key); - ---- llex.c 2013/04/12 18:48:47 2.63.1.1 -+++ llex.c 2013/08/30 15:34:59 -@@ -134,4 +134,7 @@ - luaC_checkGC(L); - } -+ else { /* string already present */ -+ ts = rawtsvalue(keyfromval(o)); /* re-use value previously stored */ -+ } - L->top--; /* remove string from stack */ - return ts; -]] -} - - -Bug{ -what = [[Call to macro 'luai_userstateclose' should be done only -after the calls to __gc methods.]], -report = [[Jean-Luc Jumpertz, 2013/09/02]], -since = [[ ]], -fix = nil, -example = [[No example]], -patch = [[ ---- lstate.c 2013/04/12 18:48:47 2.99.1.1 -+++ lstate.c 2013/11/08 17:39:57 -@@ -194,2 +194,4 @@ - g->gcrunning = 1; /* allow gc */ -+ g->version = lua_version(NULL); -+ luai_userstateopen(L); - } -@@ -224,2 +226,4 @@ - luaC_freeallobjects(L); /* collect all objects */ -+ if (g->version) /* closing a fully built state? */ -+ luai_userstateclose(L); - luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); -@@ -289,3 +293,3 @@ - g->panic = NULL; -- g->version = lua_version(NULL); -+ g->version = NULL; - g->gcstate = GCSpause; -@@ -308,4 +312,2 @@ - } -- else -- luai_userstateopen(L); - return L; -@@ -317,3 +319,2 @@ - lua_lock(L); -- luai_userstateclose(L); - close_state(L); -]] -} - - -Bug{ -what = [[Resuming the running coroutine makes it unyieldable]], -report = [[Florian Nücke, 2013/10/28]], -since = [[5.2]], -fix = [[5.2.3]], -example = [[ --- should print 'true' -print(coroutine.resume(coroutine.create(function() - coroutine.resume(coroutine.running()) - coroutine.yield() -end))) -]], -patch = [[ ---- ldo.c 2013/04/19 21:03:23 2.108.1.2 -+++ ldo.c 2013/11/08 18:20:57 -@@ -536,2 +536,3 @@ - int status; -+ int oldnny = L->nny; /* save 'nny' */ - lua_lock(L); -@@ -557,3 +558,3 @@ - } -- L->nny = 1; /* do not allow yields */ -+ L->nny = oldnny; /* restore 'nny' */ - L->nCcalls--; -]] -} - - - ------------------------------------------------------------------ --- Lua 5.2.3 - -Bug{ -what = [[compiler can optimize away overflow check in 'table.unpack']], -report = [[Paige DePol, 2014/03/30]], -since = [[5.1 (at least)]], -fix = nil, -example = [[ -> unpack({}, 0, 2^31 - 1) -(segfaults on some platforms with some compiler options) -]], -patch = [[ ---- ltablib.c 2013/04/12 18:48:47 1.65.1.1 -+++ ltablib.c 2014/05/07 16:32:55 1.65.1.2 -@@ -134,13 +135,14 @@ - - - static int unpack (lua_State *L) { -- int i, e, n; -+ int i, e; -+ unsigned int n; - luaL_checktype(L, 1, LUA_TTABLE); - i = luaL_optint(L, 2, 1); - e = luaL_opt(L, luaL_checkint, 3, luaL_len(L, 1)); - if (i > e) return 0; /* empty range */ -- n = e - i + 1; /* number of elements */ -- if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ -+ n = (unsigned int)e - (unsigned int)i; /* number of elements minus 1 */ -+ if (n > (INT_MAX - 10) || !lua_checkstack(L, ++n)) - return luaL_error(L, "too many results to unpack"); - lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ - while (i++ < e) /* push arg[i + 1...e] */ -]] -} - -Bug{ -what = [[Ephemeron table can wrongly collect entry with strong key]], -report = [[Jörg Richter, 2014/08/22]], -since = [[5.2]], -fix = nil, -example = [[ -(This bug is very hard to reproduce, -because it depends on a specific interleaving of -events between the incremental collector and the program.) -]], -patch = [[ ---- lgc.c 2013/04/26 18:22:05 2.140.1.2 -+++ lgc.c 2014/09/01 13:24:33 -@@ -403,7 +403,7 @@ - reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ - } - } -- if (prop) -+ if (g->gcstate != GCSatomic || prop) - linktable(h, &g->ephemeron); /* have to propagate again */ - else if (hasclears) /* does table have white keys? */ - linktable(h, &g->allweak); /* may have to clean white keys */ -]] -} - -Bug{ -what = [[Chunk with too many lines can seg. fault]], -report = [[Roberto, 2014/11/14]], -since = [[5.1 (at least)]], -fix = nil, -example = [[ --- the cause of the bug is the use of an unitialized variable, so --- it cannot be reproduced reliably -local s = string.rep("\n", 2^24) -print(load(function () return s end)) -]], -patch = [[ ---- llex.c 2013/08/30 15:49:41 2.63.1.2 -+++ llex.c 2015/02/09 17:05:31 -@@ -153,5 +153,5 @@ - next(ls); /* skip `\n\r' or `\r\n' */ - if (++ls->linenumber >= MAX_INT) -- luaX_syntaxerror(ls, "chunk has too many lines"); -+ lexerror(ls, "chunk has too many lines", 0); - } - -]] -} - - ------------------------------------------------------------------ --- Lua 5.3.0 - -Bug{ -what = [['string.format("%f")' can cause a buffer overflow -(only when 'lua_Number' is long double!)]], -report = [[Roberto, 2015/01/13]], -since = [[5.3]], -fix = nil, -example = [[string.format("%.99f", 1e4000) -- when floats are long double]], -patch = [[ ---- lstrlib.c 2014/12/11 14:03:07 1.221 -+++ lstrlib.c 2015/02/23 19:01:42 -@@ -800,3 +800,4 @@ - /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ --#define MAX_ITEM 512 -+#define MAX_ITEM \ -+ (sizeof(lua_Number) <= 4 ? 150 : sizeof(lua_Number) <= 8 ? 450 : 5050) - -]] -} - -Bug{ -what = [['debug.getlocal' on a coroutine suspended in a hook -can crash the interpreter]], -report = [[云风, 2015/02/11]], -since = [[5.2]], -fix = nil, -example = [[see http://lua-users.org/lists/lua-l/2015-02/msg00146.html]], -patch = [[ ---- ldebug.c 2015/01/02 12:52:22 2.110 -+++ ldebug.c 2015/02/13 16:03:23 -@@ -49,4 +49,14 @@ - - -+static void swapextra (lua_State *L) { -+ if (L->status == LUA_YIELD) { -+ CallInfo *ci = L->ci; /* get function that yielded */ -+ StkId temp = ci->func; /* exchange its 'func' and 'extra' values */ -+ ci->func = restorestack(L, ci->extra); -+ ci->extra = savestack(L, temp); -+ } -+} -+ -+ - /* - ** this function can be called asynchronous (e.g. during a signal) -@@ -145,4 +155,5 @@ - const char *name; - lua_lock(L); -+ swapextra(L); - if (ar == NULL) { /* information about non-active function? */ - if (!isLfunction(L->top - 1)) /* not a Lua function? */ -@@ -159,4 +170,5 @@ - } - } -+ swapextra(L); - lua_unlock(L); - return name; -@@ -166,10 +178,13 @@ - LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { - StkId pos = 0; /* to avoid warnings */ -- const char *name = findlocal(L, ar->i_ci, n, &pos); -+ const char *name; - lua_lock(L); -+ swapextra(L); -+ name = findlocal(L, ar->i_ci, n, &pos); - if (name) { - setobjs2s(L, pos, L->top - 1); - L->top--; /* pop value */ - } -+ swapextra(L); - lua_unlock(L); - return name; -@@ -271,4 +286,5 @@ - StkId func; - lua_lock(L); -+ swapextra(L); - if (*what == '>') { - ci = NULL; -@@ -289,4 +305,5 @@ - api_incr_top(L); - } -+ swapextra(L); - if (strchr(what, 'L')) - collectvalidlines(L, cl); -]] -} - - -Bug{ -what = [[suspended '__le' metamethod can give wrong result]], -report = [[Eric Zhong, 2015/04/07]], -since = [[5.2]], -fix = nil, - -example = [[ -mt = {__le = function (a,b) coroutine.yield("yield"); return a.x <= b.x end} -t1 = setmetatable({x=1}, mt) -t2 = {x=2} -co = coroutine.wrap(function (a,b) return t2 <= t1 end) -co() -print(co()) --> true (should be false) -]], - -patch = [[ ---- lstate.h 2014/10/30 18:53:28 2.119 -+++ lstate.h 2015/04/13 15:58:40 -@@ -94,6 +94,7 @@ - #define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ - #define CIST_TAIL (1<<5) /* call was tail called */ - #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ -+#define CIST_LEQ (1<<7) /* using __lt for __le */ - - #define isLua(ci) ((ci)->callstatus & CIST_LUA) - ---- lvm.c 2014/12/27 20:30:38 2.232 -+++ lvm.c 2015/04/13 15:51:30 -@@ -292,9 +292,14 @@ - return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; - else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try 'le' */ - return res; -- else if ((res = luaT_callorderTM(L, r, l, TM_LT)) < 0) /* else try 'lt' */ -- luaG_ordererror(L, l, r); -- return !res; -+ else { /* try 'lt': */ -+ L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ -+ res = luaT_callorderTM(L, r, l, TM_LT); -+ L->ci->callstatus ^= CIST_LEQ; /* clear mark */ -+ if (res < 0) -+ luaG_ordererror(L, l, r); -+ return !res; /* result is negated */ -+ } - } - - -@@ -553,11 +558,11 @@ - case OP_LE: case OP_LT: case OP_EQ: { - int res = !l_isfalse(L->top - 1); - L->top--; -- /* metamethod should not be called when operand is K */ -- lua_assert(!ISK(GETARG_B(inst))); -- if (op == OP_LE && /* "<=" using "<" instead? */ -- ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE))) -- res = !res; /* invert result */ -+ if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ -+ lua_assert(op == OP_LE); -+ ci->callstatus ^= CIST_LEQ; /* clear mark */ -+ res = !res; /* negate result */ -+ } - lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); - if (res != GETARG_A(inst)) /* condition failed? */ - ci->u.l.savedpc++; /* skip jump instruction */ -]] -} - - -Bug{ -what = [[return hook may not see correct values for - active local variables when function returns]], -report = [[Philipp Janda/Peng Yi, 2015/05/19]], -since = [[5.0]], -fix = nil, -example = [[ -see messasge http://lua-users.org/lists/lua-l/2015-05/msg00376.html]], -patch = [[ -]] -} - - - ------------------------------------------------------------------ --- Lua 5.3.1 - -Bug{ -what = [['io.lines' does not check maximum number of options]], -report = [[Patrick Donnell, 2015/07/10]], -since = [[5.3.0]], -fix = nil, -example = [[ --- can segfault in some machines -t ={}; for i = 1, 253 do t[i] = 1 end -io.lines("someexistingfile", table.unpack(t))() -]], -patch = [[ ---- liolib.c 2015/07/07 17:03:34 2.146 -+++ liolib.c 2015/07/15 14:40:28 2.147 -@@ -318,8 +318,15 @@ - static int io_readline (lua_State *L); - - -+/* -+** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit -+** in the limit for upvalues of a closure) -+*/ -+#define MAXARGLINE 250 -+ - static void aux_lines (lua_State *L, int toclose) { - int n = lua_gettop(L) - 1; /* number of arguments to read */ -+ luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); - lua_pushinteger(L, n); /* number of arguments to read */ - lua_pushboolean(L, toclose); /* close/not close file when finished */ - lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ -]] -} - - ------------------------------------------------------------------ --- Lua 5.3.2 - -Bug{ -what = [[Metatable may access its own dealocated field when -it has a self reference in __newindex]], -report = [[actboy168@gmail.com, 2016/01/01]], -since = [[5.3.2]], -fix = nil, -example = [[ -local mt = {} -mt.__newindex = mt -local t = setmetatable({}, mt) -t[1] = 1 -- will segfault on some machines -]], -patch = [[ ---- lvm.c 2015/11/23 11:30:45 2.265 -+++ lvm.c 2016/01/01 14:34:12 -@@ -190,18 +190,19 @@ - for (loop = 0; loop < MAXTAGLOOP; loop++) { - const TValue *tm; - if (oldval != NULL) { -- lua_assert(ttistable(t) && ttisnil(oldval)); -+ Table *h = hvalue(t); /* save 't' table */ -+ lua_assert(ttisnil(oldval)); - /* must check the metamethod */ -- if ((tm = fasttm(L, hvalue(t)->metatable, TM_NEWINDEX)) == NULL && -+ if ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL && - /* no metamethod; is there a previous entry in the table? */ - (oldval != luaO_nilobject || - /* no previous entry; must create one. (The next test is - always true; we only need the assignment.) */ -- (oldval = luaH_newkey(L, hvalue(t), key), 1))) { -+ (oldval = luaH_newkey(L, h, key), 1))) { - /* no metamethod and (now) there is an entry with given key */ - setobj2t(L, cast(TValue *, oldval), val); -- invalidateTMcache(hvalue(t)); -- luaC_barrierback(L, hvalue(t), val); -+ invalidateTMcache(h); -+ luaC_barrierback(L, h, val); - return; - } - /* else will try the metamethod */ -]] -} - - -Bug{ -what = [[label between local definitions can mix-up their initializations]], -report = [[Karel Tuma, 2016/03/01]], -since = [[5.2]], -fix = nil, -example = [[ -do - local k = 0 - local x - ::foo:: - local y -- should be reset to nil after goto, but it is not - assert(not y) - y = true - k = k + 1 - if k < 2 then goto foo end -end -]], -patch = [[ ---- lparser.c 2015/11/02 16:09:30 2.149 -+++ lparser.c 2016/03/03 12:03:37 -@@ -1226,7 +1226,7 @@ - checkrepeated(fs, ll, label); /* check for repeated labels */ - checknext(ls, TK_DBCOLON); /* skip double colon */ - /* create new entry for this label */ -- l = newlabelentry(ls, ll, label, line, fs->pc); -+ l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs)); - skipnoopstat(ls); /* skip other no-op statements */ - if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ - /* assume that locals are already out of scope */ -]] -} - - -Bug{ -what = [['gmatch' iterator fails when called from a coroutine different -from the one that created it]], -report = [[Nagaev Boris, 2016/03/18]], -since = [[5.3.2]], -fix = nil, -example = [[ -local f = string.gmatch("1 2 3 4 5", "%d+") -print(f()) --> 1 -co = coroutine.wrap(f) -print(co()) --> ??? (should be 2) -]], -patch = [[ ---- lstrlib.c 2015/11/25 16:28:17 1.239 -+++ lstrlib.c 2016/04/11 15:29:41 -@@ -688,6 +688,7 @@ - static int gmatch_aux (lua_State *L) { - GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); - const char *src; -+ gm->ms.L = L; - for (src = gm->src; src <= gm->ms.src_end; src++) { - const char *e; - reprepstate(&gm->ms); -]] -} - - ------------------------------------------------------------------ --- Lua 5.3.3 - - -Bug{ -what = [[expression list with four or more expressions in -a 'for' loop can crash the interpreter]], -report = [[Marco Schöpl, 2016/06/17]], -since = [[5.2]], -fix = nil, -example = [[ --- the next loop will probably crash the interpreter -repeat until load "for _ in _,_,_,_ do local function _() end" -]], -patch = [[ ---- lparser.c 2016/05/13 19:10:16 2.153 -+++ lparser.c 2016/06/17 19:52:48 -@@ -323,6 +323,8 @@ - luaK_nil(fs, reg, extra); - } - } -+ if (nexps > nvars) -+ ls->fs->freereg -= nexps - nvars; /* remove extra values */ - } - - -@@ -1160,11 +1162,8 @@ - int nexps; - checknext(ls, '='); - nexps = explist(ls, &e); -- if (nexps != nvars) { -+ if (nexps != nvars) - adjust_assign(ls, nvars, nexps, &e); -- if (nexps > nvars) -- ls->fs->freereg -= nexps - nvars; /* remove extra values */ -- } - else { - luaK_setoneret(ls->fs, &e); /* close last expression */ - luaK_storevar(ls->fs, &lh->v, &e); -]] -} - - -Bug{ -what = [[Checking a format for 'os.date' may read pass the format string]], -report = [[Nagaev Boris, 2016/07/10]], -since = [[5.3.3]], -fix = nil, -example = [[ -This bug does not seem to happen with regular compilers. -It needs an "interceptor" 'memcmp' function that continues -reading memory after a difference is found.]], -patch = [[ -2c2 -< ** $Id: bugs,v 1.160 2018/05/24 20:25:14 roberto Exp roberto $ ---- -> ** $Id: bugs,v 1.160 2018/05/24 20:25:14 roberto Exp roberto $ -263c263,264 -< for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) { ---- -> int convlen = (int)strlen(conv); -> for (option = LUA_STRFTIMEOPTIONS; *option != '\0' && oplen <= convlen; option += oplen) { -]] -} - - -Bug{ -what = [[Lua can generate wrong code in functions with too many constants]], -report = [[Marco Schöpl, 2016/07/17]], -since = [[5.3.3]], -fix = nil, -example = [[See http://lua-users.org/lists/lua-l/2016-07/msg00303.html]], -patch = [[ ---- lcode.c 2016/06/20 19:12:46 2.110 -+++ lcode.c 2016/07/18 15:43:41 -@@ -1018,8 +1018,8 @@ - */ - static void codebinexpval (FuncState *fs, OpCode op, - expdesc *e1, expdesc *e2, int line) { -- int rk1 = luaK_exp2RK(fs, e1); /* both operands are "RK" */ -- int rk2 = luaK_exp2RK(fs, e2); -+ int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ -+ int rk1 = luaK_exp2RK(fs, e1); - freeexps(fs, e1, e2); - e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */ - e1->k = VRELOCABLE; /* all those operations are relocatable */ -]] -} - - -Bug{ -what = [[When a coroutine tries to resume a non-suspended coroutine, -it can do some mess (and break C assertions) before detecting the error]], -report = [[Marco Schöpl, 2016/07/20]], -since = [[ ]], -fix = nil, -example = [[ --- with C assertions on -A = coroutine.running() -B = coroutine.create(function() coroutine.resume(A) end) -coroutine.resume(B) - --- or -A = coroutine.wrap(function() pcall(A, _) end) -A() -]], -patch = [[ -]] -} - - ------------------------------------------------------------------ --- Lua 5.3.4 - - -Bug{ -what = [[Wrong code for a goto followed by a label inside an 'if']], -report = [[云风, 2017/04/13]], -since = [[5.2]], -fix = nil, -example = [[ --- should print 32323232..., but prints only '3' -if true then - goto LBL - ::loop:: - print(2) - ::LBL:: - print(3) - goto loop -end -]], -patch = [[ ---- lparser.c 2017/04/19 17:20:42 2.155.1.1 -+++ lparser.c 2017/04/29 18:11:40 2.155.1.2 -@@ -1392,7 +1392,7 @@ - luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ - enterblock(fs, &bl, 0); /* must enter block before 'goto' */ - gotostat(ls, v.t); /* handle goto/break */ -- skipnoopstat(ls); /* skip other no-op statements */ -+ while (testnext(ls, ';')) {} /* skip semicolons */ - if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ - leaveblock(fs); - return; /* and that is it */ -]] -} - - -Bug{ -what = [[Lua crashes when building sequences with more than 2^30 elements.]], -report = [[Viacheslav Usov, 2017/05/11]], -since = [[ ]], -fix = nil, -example = [[ --- crashes if machine has enough memory -local t = {} -for i = 1, 0x7fffffff do - t[i] = i -end -]], -patch = [[ ---- ltable.c 2017/04/19 17:20:42 2.118.1.1 -+++ ltable.c 2018/05/24 18:34:38 -@@ -223,7 +223,9 @@ - unsigned int na = 0; /* number of elements to go to array part */ - unsigned int optimal = 0; /* optimal size for array part */ - /* loop while keys can fill more than half of total size */ -- for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) { -+ for (i = 0, twotoi = 1; -+ twotoi > 0 && *pna > twotoi / 2; -+ i++, twotoi *= 2) { - if (nums[i] > 0) { - a += nums[i]; - if (a > twotoi/2) { /* more than half elements present? */ -]] -} - - -Bug{ -what = [[Table length computation overflows for sequences larger than -2^31 elements.]], -report = [[Viacheslav Usov, 2017/05/12]], -since = [[ ]], -fix = nil, -example = [[ --- on a machine with enough memory -local t = {} -for i = 1, 2147483681 do - t[i] = i -end -print(#t) -]], -patch = [[ ---- ltable.h 2017/04/19 17:20:42 2.23.1.1 -+++ ltable.h 2018/05/24 19:31:50 -@@ -56,3 +56,3 @@ - LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); --LUAI_FUNC int luaH_getn (Table *t); -+LUAI_FUNC lua_Unsigned luaH_getn (Table *t); - ---- ltable.c 2018/05/24 19:22:37 2.118.1.2 -+++ ltable.c 2018/05/24 19:25:05 -@@ -614,4 +614,4 @@ - --static int unbound_search (Table *t, unsigned int j) { -- unsigned int i = j; /* i is zero or a present index */ -+static lua_Unsigned unbound_search (Table *t, lua_Unsigned j) { -+ lua_Unsigned i = j; /* i is zero or a present index */ - j++; -@@ -620,3 +620,3 @@ - i = j; -- if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */ -+ if (j > l_castS2U(LUA_MAXINTEGER) / 2) { /* overflow? */ - /* table was built with bad purposes: resort to linear search */ -@@ -630,3 +630,3 @@ - while (j - i > 1) { -- unsigned int m = (i+j)/2; -+ lua_Unsigned m = (i+j)/2; - if (ttisnil(luaH_getint(t, m))) j = m; -@@ -642,3 +642,3 @@ - */ --int luaH_getn (Table *t) { -+lua_Unsigned luaH_getn (Table *t) { - unsigned int j = t->sizearray; -]] -} - - -Bug{ -what = [[Lua does not check GC when creating error messages]], -report = [[Viacheslav Usov, 2017/07/06]], -since = [[5.3.2]], -fix = nil, -example = [[ -function test() - bob.joe.larry = 23 -end - --- memory will grow steadly -for i = 1, math.huge do - pcall(test) - if i % 100000 == 0 then - io.write(collectgarbage'count'*1024, "\n") - end -end -]], -patch = [[ ---- ldebug.c 2017/04/19 17:20:42 2.121.1.1 -+++ ldebug.c 2017/07/10 17:08:39 -@@ -653,6 +653,7 @@ - CallInfo *ci = L->ci; - const char *msg; - va_list argp; -+ luaC_checkGC(L); /* error message uses memory */ - va_start(argp, fmt); - msg = luaO_pushvfstring(L, fmt, argp); /* format message */ - va_end(argp); -]] -} - - -Bug{ -what = [[dead keys with nil values can stay in weak tables]], -report = [[云风 Cloud Wu, 2017/08/15]], -since = [[5.2]], -fix = nil, -example = [[ --- The following chunk, under a memory checker like valgrind, --- produces a memory access violation. - -local a = setmetatable({}, {__mode = 'kv'}) - -a['ABCDEFGHIJKLMNOPQRSTUVWXYZ' .. 'abcdefghijklmnopqrstuvwxyz'] = {} -a[next(a)] = nil -collectgarbage() -print(a['BCDEFGHIJKLMNOPQRSTUVWXYZ' .. 'abcdefghijklmnopqrstuvwxyz']) -]], -patch = [[ ---- lgc.c 2016/12/22 13:08:50 2.215 -+++ lgc.c 2017/08/31 16:08:23 -@@ -643,8 +643,9 @@ - for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { - setnilvalue(gval(n)); /* remove value ... */ -- removeentry(n); /* and remove entry from table */ - } -+ if (ttisnil(gval(n))) /* is entry empty? */ -+ removeentry(n); /* remove entry from table */ - } - } - } -]] -} - - -Bug{ -what = [['lua_pushcclosure' should not call the garbage collector when -'n' is zero.]], -report = [[Andrew Gierth, 2017/12/05]], -since = [[5.3.3]], -fix = nil, -example = [[ ]], -patch = [[ ---- lapi.c 2017/04/19 17:13:00 2.259.1.1 -+++ lapi.c 2017/12/06 18:14:45 -@@ -533,6 +533,7 @@ - lua_lock(L); - if (n == 0) { - setfvalue(L->top, fn); -+ api_incr_top(L); - } - else { - CClosure *cl; -@@ -546,9 +547,9 @@ - /* does not need barrier because closure is white */ - } - setclCvalue(L, L->top, cl); -+ api_incr_top(L); -+ luaC_checkGC(L); - } -- api_incr_top(L); -- luaC_checkGC(L); - lua_unlock(L); - } -]] -} - - -Bug{ -what = [[memory-allocation error when resizing a table can leave it -in an inconsistent state.]], -report = [[Roberto, 2017/12/08]], -since = [[5.0]], -fix = nil, -example = [[ -local a = {x = 1, y = 1, z = 1} -a[1] = 10 -- goes to the hash part (which has 4 slots) -print(a[1]) --> 10 - --- assume that the 2nd memory allocation from now fails -pcall(rawset, a, 2, 20) -- forces a rehash - --- a[1] now exists both in the array part (because the array part --- grew) and in the hash part (because the allocation of the hash --- part failed, keeping it as it was). --- This makes the following traversal goes forever... -for k,v in pairs(a) do print(k,v) end -]], -patch = [[ ---- ltable.c 2018/05/24 19:39:05 2.118.1.3 -+++ ltable.c 2018/06/04 16:00:25 -@@ -332,17 +332,34 @@ - } - - -+typedef struct { -+ Table *t; -+ unsigned int nhsize; -+} AuxsetnodeT; -+ -+ -+static void auxsetnode (lua_State *L, void *ud) { -+ AuxsetnodeT *asn = cast(AuxsetnodeT *, ud); -+ setnodevector(L, asn->t, asn->nhsize); -+} -+ -+ - void luaH_resize (lua_State *L, Table *t, unsigned int nasize, - unsigned int nhsize) { - unsigned int i; - int j; -+ AuxsetnodeT asn; - unsigned int oldasize = t->sizearray; - int oldhsize = allocsizenode(t); - Node *nold = t->node; /* save old hash ... */ - if (nasize > oldasize) /* array part must grow? */ - setarrayvector(L, t, nasize); - /* create new hash part with appropriate size */ -- setnodevector(L, t, nhsize); -+ asn.t = t; asn.nhsize = nhsize; -+ if (luaD_rawrunprotected(L, auxsetnode, &asn) != LUA_OK) { /* mem. error? */ -+ setarrayvector(L, t, oldasize); /* array back to its original size */ -+ luaD_throw(L, LUA_ERRMEM); /* rethrow memory error */ -+ } - if (nasize < oldasize) { /* array part must shrink? */ - t->sizearray = nasize; - /* re-insert elements from vanishing slice */ -]] -} - - - ---[=[ -Bug{ -what = [[Long brackets with a huge number of '=' overflow some -internal buffer arithmetic]], -report = [[Marco, 2018/12/12]], -since = [[5.1]], -fix = nil, -example = [[ -local eqs = string.rep("=", 0x3ffffffe) -local code = "return [" .. eqs .. "[a]" .. eqs .. "]" -print(#assert(load(code))()) -]], -patch = [[ -]] -} -]=] - - - - ---[=[ -Bug{ -what = [[ ]], -report = [[ ]], -since = [[ ]], -fix = nil, -example = [[ ]], -patch = [[ -]] -} -]=] - -