--[=[ ** 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; } ]], } ----------------------------------------------------------------- -- 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; ]] }