Hello community, here is the log from the commit of package lua54 for openSUSE:Factory checked in at 2020-10-12 13:46:38 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/lua54 (Old) and /work/SRC/openSUSE:Factory/.lua54.new.3486 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lua54" Mon Oct 12 13:46:38 2020 rev:5 rq:840777 version:5.4.1 Changes: -------- --- /work/SRC/openSUSE:Factory/lua54/lua54.changes 2020-08-28 23:44:51.903506140 +0200 +++ /work/SRC/openSUSE:Factory/.lua54.new.3486/lua54.changes 2020-10-12 13:46:52.197910487 +0200 @@ -1,0 +2,7 @@ +Sat Oct 10 13:10:50 UTC 2020 - Callum Farmer <callumjfarme...@gmail.com> + +- Update to version 5.4.1: + * Fixes bugs found in Lua 5.4.0 +- Removed upstream-bugs.patch: new release (no bugs found yet) + +------------------------------------------------------------------- Old: ---- lua-5.4.0-tests.tar.gz lua-5.4.0.tar.gz upstream-bugs.patch New: ---- lua-5.4.1-tests.tar.gz lua-5.4.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ lua54.spec ++++++ --- /var/tmp/diff_new_pack.smUT5o/_old 2020-10-12 13:46:52.905910775 +0200 +++ /var/tmp/diff_new_pack.smUT5o/_new 2020-10-12 13:46:52.909910776 +0200 @@ -19,14 +19,14 @@ %define major_version 5.4 %define libname liblua5_4-5 Name: lua54 -Version: 5.4.0 +Version: 5.4.1 Release: 0 Summary: Small Embeddable Language with Procedural Syntax License: MIT Group: Development/Languages/Other URL: http://www.lua.org -Source: http://www.lua.org/ftp/lua-5.4.0.tar.gz -Source1: http://www.lua.org/tests/lua-5.4.0-tests.tar.gz +Source: http://www.lua.org/ftp/lua-%{version}.tar.gz +Source1: http://www.lua.org/tests/lua-%{version}-tests.tar.gz Source99: baselibs.conf # PATCH-FIX-SUSE tweak the buildsystem to produce what is needed for SUSE Patch0: lua-build-system.patch @@ -34,8 +34,8 @@ # Fix failing test Patch1: attrib_test.patch Patch2: files_test.patch -# PATCH-FIX-UPSTREAM https://www.lua.org/bugs.html -Patch3: upstream-bugs.patch +# PATCH-FIX-UPSTREAM https://www.lua.org/bugs.html#5.4.1 +#Patch3: upstream-bugs.patch BuildRequires: libtool BuildRequires: lua-macros BuildRequires: pkgconfig ++++++ attrib_test.patch ++++++ --- /var/tmp/diff_new_pack.smUT5o/_old 2020-10-12 13:46:52.937910788 +0200 +++ /var/tmp/diff_new_pack.smUT5o/_new 2020-10-12 13:46:52.937910788 +0200 @@ -1,5 +1,5 @@ ---- a/lua-5.4.0-tests/attrib.lua -+++ b/lua-5.4.0-tests/attrib.lua +--- a/lua-5.4.1-tests/attrib.lua ++++ b/lua-5.4.1-tests/attrib.lua @@ -269,7 +269,7 @@ local p = "" -- On Mac OS X, redefine local st, err, when = package.loadlib(DC"lib1", "*") if not st then ++++++ files_test.patch ++++++ --- /var/tmp/diff_new_pack.smUT5o/_old 2020-10-12 13:46:52.961910798 +0200 +++ /var/tmp/diff_new_pack.smUT5o/_new 2020-10-12 13:46:52.965910799 +0200 @@ -1,7 +1,7 @@ -Index: lua-5.4.0/lua-5.4.0-tests/files.lua +Index: lua-5.4.1/lua-5.4.1-tests/files.lua =================================================================== ---- lua-5.4.0.orig/lua-5.4.0-tests/files.lua -+++ lua-5.4.0/lua-5.4.0-tests/files.lua +--- lua-5.4.1.orig/lua-5.4.1-tests/files.lua ++++ lua-5.4.1/lua-5.4.1-tests/files.lua @@ -81,7 +81,7 @@ assert(io.output() ~= io.stdout) if not _port then -- invalid seek ++++++ lua-5.4.0-tests.tar.gz -> lua-5.4.1-tests.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/api.lua new/lua-5.4.1-tests/api.lua --- old/lua-5.4.0-tests/api.lua 2020-06-18 16:25:54.000000000 +0200 +++ new/lua-5.4.1-tests/api.lua 2020-09-30 11:36:52.000000000 +0200 @@ -11,6 +11,9 @@ local pack = table.pack +-- standard error message for memory errors +local MEMERRMSG = "not enough memory" + function tcheck (t1, t2) assert(t1.n == (t2.n or #t2) + 1) for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end @@ -408,7 +411,7 @@ -- memory error T.totalmem(T.totalmem()+10000) -- set low memory limit (+10k) - assert(T.checkpanic("newuserdata 20000") == "not enough memory") + assert(T.checkpanic("newuserdata 20000") == MEMERRMSG) T.totalmem(0) -- restore high limit -- stack error @@ -1153,40 +1156,74 @@ end -------------------------------------------------------------------------- --- testing memory limits -------------------------------------------------------------------------- +--[[ +** {================================================================== +** Testing memory limits +** =================================================================== +--]] + print("memory-allocation errors") checkerr("block too big", T.newuserdata, math.maxinteger) collectgarbage() local f = load"local a={}; for i=1,100000 do a[i]=i end" T.alloccount(10) -checkerr("not enough memory", f) +checkerr(MEMERRMSG, f) T.alloccount() -- remove limit + +-- test memory errors; increase limit for maximum memory by steps, +-- o that we get memory errors in all allocations of a given +-- task, until there is enough memory to complete the task without +-- errors. +function testbytes (s, f) + collectgarbage() + local M = T.totalmem() + local oldM = M + local a,b = nil + while true do + collectgarbage(); collectgarbage() + T.totalmem(M) + a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f) + T.totalmem(0) -- remove limit + if a and b == "OK" then break end -- stop when no more errors + if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error? + error(a, 0) -- propagate it + end + M = M + 7 -- increase memory limit + end + print(string.format("minimum memory for %s: %d bytes", s, M - oldM)) + return a +end + -- test memory errors; increase limit for number of allocations one -- by one, so that we get memory errors in all allocations of a given -- task, until there is enough allocations to complete the task without -- errors. -function testamem (s, f) - collectgarbage(); collectgarbage() +function testalloc (s, f) + collectgarbage() local M = 0 local a,b = nil while true do + collectgarbage(); collectgarbage() T.alloccount(M) - a, b = pcall(f) + a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f) T.alloccount() -- remove limit - if a and b then break end -- stop when no more errors - if not a and not -- `real' error? - (string.find(b, "memory") or string.find(b, "overflow")) then - error(b, 0) -- propagate it + if a and b == "OK" then break end -- stop when no more errors + if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error? + error(a, 0) -- propagate it end M = M + 1 -- increase allocation limit end - print(string.format("limit for %s: %d allocations", s, M)) - return b + print(string.format("minimum allocations for %s: %d allocations", s, M)) + return a +end + + +local function testamem (s, f) + testalloc(s, f) + return testbytes(s, f) end @@ -1196,8 +1233,11 @@ -- testing memory errors when creating a new state -b = testamem("state creation", T.newstate) -T.closestate(b); -- close new state +testamem("state creation", function () + local st = T.newstate() + if st then T.closestate(st) end -- close new state + return st +end) testamem("empty-table creation", function () return {} @@ -1345,6 +1385,9 @@ return foo(100) end) +-- }================================================================== + + do -- testing failing in 'lua_checkstack' local res = T.testC([[rawcheckstack 500000; return 1]]) assert(res == false) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/calls.lua new/lua-5.4.1-tests/calls.lua --- old/lua-5.4.0-tests/calls.lua 2020-06-18 16:25:54.000000000 +0200 +++ new/lua-5.4.1-tests/calls.lua 2020-09-30 11:36:53.000000000 +0200 @@ -317,6 +317,16 @@ assert(type(f) == "function" and f() == 1) +do -- another bug (in 5.4.0) + -- loading a binary long string interrupted by GC cycles + local f = string.dump(function () + return '01234567890123456789012345678901234567890123456789' + end) + f = load(read1(f)) + assert(f() == '01234567890123456789012345678901234567890123456789') +end + + x = string.dump(load("x = 1; return x")) a = assert(load(read1(x), nil, "b")) assert(a() == 1 and _G.x == 1) @@ -358,8 +368,12 @@ end end ]] +a = assert(load(read1(x), "read", "t")) +assert(a()(2)(3)(10) == 15) -a = assert(load(read1(x))) +-- repeat the test loading a binary chunk +x = string.dump(a) +a = assert(load(read1(x), "read", "b")) assert(a()(2)(3)(10) == 15) @@ -422,20 +436,30 @@ print("testing binary chunks") do - local header = string.pack("c4BBc6BBBj", + local header = string.pack("c4BBc6BBB", "\27Lua", -- signature 0x54, -- version 5.4 (0x54) 0, -- format "\x19\x93\r\n\x1a\n", -- data 4, -- size of instruction string.packsize("j"), -- sizeof(lua integer) - string.packsize("n"), -- sizeof(lua number) - 0x5678 -- LUAC_INT - -- LUAC_NUM may not have a unique binary representation (padding...) + string.packsize("n") -- sizeof(lua number) ) - local c = string.dump(function () local a = 1; local b = 3; return a+b*3 end) + local c = string.dump(function () + local a = 1; local b = 3; + local f = function () return a + b + _ENV.c; end -- upvalues + local s1 = "a constant" + local s2 = "another constant" + return a + b * 3 + end) + assert(assert(load(c))() == 10) + + -- check header assert(string.sub(c, 1, #header) == header) + -- check LUAC_INT and LUAC_NUM + local ci, cn = string.unpack("jn", c, #header + 1) + assert(ci == 0x5678 and cn == 370.5) -- corrupted header for i = 1, #header do @@ -451,7 +475,6 @@ local st, msg = load(string.sub(c, 1, i)) assert(not st and string.find(msg, "truncated")) end - assert(assert(load(c))() == 10) end print('OK') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/coroutine.lua new/lua-5.4.1-tests/coroutine.lua --- old/lua-5.4.0-tests/coroutine.lua 2020-06-18 16:25:54.000000000 +0200 +++ new/lua-5.4.1-tests/coroutine.lua 2020-09-30 11:36:53.000000000 +0200 @@ -184,7 +184,7 @@ if not T then warn("@on") else -- test library - assert(string.find(_WARN, "200")); _WARN = nil + assert(string.find(_WARN, "200")); _WARN = false warn("@normal") end assert(st == false and coroutine.status(co) == "dead" and msg == 111) @@ -407,7 +407,8 @@ if not T then - (Message or print)('\n >>> testC not active: skipping yield/hook tests <<<\n') + (Message or print) + ('\n >>> testC not active: skipping coroutine API tests <<<\n') else print "testing yields inside hooks" @@ -564,8 +565,17 @@ c == "ERRRUN" and d == 4) - -- using a main thread as a coroutine + -- using a main thread as a coroutine (dubious use!) local state = T.newstate() + + -- check that yielddable is working correctly + assert(T.testC(state, "newthread; isyieldable -1; remove 1; return 1")) + + -- main thread is not yieldable + assert(not T.testC(state, "rawgeti R 1; isyieldable -1; remove 1; return 1")) + + T.testC(state, "settop 0") + T.loadlib(state) assert(T.doremote(state, [[ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/cstack.lua new/lua-5.4.1-tests/cstack.lua --- old/lua-5.4.0-tests/cstack.lua 2020-06-18 16:25:54.000000000 +0200 +++ new/lua-5.4.1-tests/cstack.lua 2020-09-30 11:36:53.000000000 +0200 @@ -105,6 +105,22 @@ print("\tfinal count: ", count) end +do -- bug in 5.4.0 + print("testing limits in coroutines inside deep calls") + count = 0 + local lim = 1000 + local function stack (n) + progress() + if n > 0 then return stack(n - 1) + 1 + else coroutine.wrap(function () + stack(lim) + end)() + end + end + + print(xpcall(stack, function () return "ok" end, lim)) +end + do print("testing changes in C-stack limit") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/db.lua new/lua-5.4.1-tests/db.lua --- old/lua-5.4.0-tests/db.lua 2020-06-18 16:25:54.000000000 +0200 +++ new/lua-5.4.1-tests/db.lua 2020-09-30 11:36:53.000000000 +0200 @@ -884,7 +884,7 @@ print("testing debug functions on chunk without debug info") -prog = [[-- program to be loaded without debug information +prog = [[-- program to be loaded without debug information (strip) local debug = require'debug' local a = 12 -- a local variable @@ -927,6 +927,23 @@ assert(f() == 13) +do -- bug in 5.4.0: line hooks in stripped code + local function foo () + local a = 1 + local b = 2 + return b + end + + local s = load(string.dump(foo, true)) + local line = true + debug.sethook(function (e, l) + assert(e == "line") + line = l + end, "l") + assert(s() == 2); debug.sethook(nil) + assert(line == nil) -- hook called withoug debug info for 1st instruction +end + do -- tests for 'source' in binary dumps local prog = [[ return function (x) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/events.lua new/lua-5.4.1-tests/events.lua --- old/lua-5.4.0-tests/events.lua 2020-06-18 16:25:54.000000000 +0200 +++ new/lua-5.4.1-tests/events.lua 2020-09-30 11:36:53.000000000 +0200 @@ -305,6 +305,17 @@ assert(t[Set{1,3,5}] == undef) +do -- test invalidating flags + local mt = {__eq = true} + local a = setmetatable({10}, mt) + local b = setmetatable({10}, mt) + mt.__eq = nil + assert(a ~= b) -- no metamethod + mt.__eq = function (x,y) return x[1] == y[1] end + assert(a == b) -- must use metamethod now +end + + if not T then (Message or print)('\n >>> testC not active: skipping tests for \z userdata <<<\n') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/files.lua new/lua-5.4.1-tests/files.lua --- old/lua-5.4.0-tests/files.lua 2020-06-18 16:25:54.000000000 +0200 +++ new/lua-5.4.1-tests/files.lua 2020-09-30 11:36:53.000000000 +0200 @@ -721,6 +721,21 @@ progname = '"' .. arg[i + 1] .. '"' end print("testing popen/pclose and execute") + -- invalid mode for popen + checkerr("invalid mode", io.popen, "cat", "") + checkerr("invalid mode", io.popen, "cat", "r+") + checkerr("invalid mode", io.popen, "cat", "rw") + do -- basic tests for popen + local file = os.tmpname() + local f = assert(io.popen("cat - > " .. file, "w")) + f:write("a line") + assert(f:close()) + local f = assert(io.popen("cat - < " .. file, "r")) + assert(f:read("a") == "a line") + assert(f:close()) + assert(os.remove(file)) + end + local tests = { -- command, what, code {"ls > /dev/null", "ok"}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/gc.lua new/lua-5.4.1-tests/gc.lua --- old/lua-5.4.0-tests/gc.lua 2020-06-18 16:25:54.000000000 +0200 +++ new/lua-5.4.1-tests/gc.lua 2020-09-30 11:36:53.000000000 +0200 @@ -372,7 +372,7 @@ warn("@on"); warn("@store") collectgarbage() assert(string.find(_WARN, "error in __gc metamethod")) - assert(string.match(_WARN, "@(.-)@") == "expected"); _WARN = nil + assert(string.match(_WARN, "@(.-)@") == "expected"); _WARN = false for i = 8, 10 do assert(s[i]) end for i = 1, 5 do @@ -481,7 +481,7 @@ u = setmetatable({}, {__gc = function () error "@expected error" end}) u = nil collectgarbage() - assert(string.find(_WARN, "@expected error")); _WARN = nil + assert(string.find(_WARN, "@expected error")); _WARN = false warn("@normal") end @@ -657,14 +657,14 @@ n = n + 1 assert(n == o[1]) if n == 1 then - _WARN = nil + _WARN = false elseif n == 2 then assert(find(_WARN, "@expected warning")) lastmsg = _WARN -- get message from previous error (first 'o') else assert(lastmsg == _WARN) -- subsequent error messages are equal end - warn("@store"); _WARN = nil + warn("@store"); _WARN = false error"@expected warning" end} for i = 10, 1, -1 do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/gengc.lua new/lua-5.4.1-tests/gengc.lua --- old/lua-5.4.0-tests/gengc.lua 2020-06-18 16:25:54.000000000 +0200 +++ new/lua-5.4.1-tests/gengc.lua 2020-09-30 11:36:53.000000000 +0200 @@ -37,6 +37,92 @@ end +do + -- ensure that 'firstold1' is corrected when object is removed from + -- the 'allgc' list + local function foo () end + local old = {10} + collectgarbage() -- make 'old' old + assert(not T or T.gcage(old) == "old") + setmetatable(old, {}) -- new table becomes OLD0 (barrier) + assert(not T or T.gcage(getmetatable(old)) == "old0") + collectgarbage("step", 0) -- new table becomes OLD1 and firstold1 + assert(not T or T.gcage(getmetatable(old)) == "old1") + setmetatable(getmetatable(old), {__gc = foo}) -- get it out of allgc list + collectgarbage("step", 0) -- should not seg. fault +end + + +do -- bug in 5.4.0 +-- When an object aged OLD1 is finalized, it is moved from the list +-- 'finobj' to the *beginning* of the list 'allgc', but that part of the +-- list was not being visited by 'markold'. + local A = {} + A[1] = false -- old anchor for object + + -- obj finalizer + local function gcf (obj) + A[1] = obj -- anchor object + assert(not T or T.gcage(obj) == "old1") + obj = nil -- remove it from the stack + collectgarbage("step", 0) -- do a young collection + print(getmetatable(A[1]).x) -- metatable was collected + end + + collectgarbage() -- make A old + local obj = {} -- create a new object + collectgarbage("step", 0) -- make it a survival + assert(not T or T.gcage(obj) == "survival") + setmetatable(obj, {__gc = gcf, x = "+"}) -- create its metatable + assert(not T or T.gcage(getmetatable(obj)) == "new") + obj = nil -- clear object + collectgarbage("step", 0) -- will call obj's finalizer +end + + +do -- another bug in 5.4.0 + local old = {10} + collectgarbage() -- make 'old' old + local co = coroutine.create( + function () + local x = nil + local f = function () + return x[1] + end + x = coroutine.yield(f) + coroutine.yield() + end + ) + local _, f = coroutine.resume(co) -- create closure over 'x' in coroutine + collectgarbage("step", 0) -- make upvalue a survival + old[1] = {"hello"} -- 'old' go to grayagain as 'touched1' + coroutine.resume(co, {123}) -- its value will be new + co = nil + collectgarbage("step", 0) -- hit the barrier + assert(f() == 123 and old[1][1] == "hello") + collectgarbage("step", 0) -- run the collector once more + -- make sure old[1] was not collected + assert(f() == 123 and old[1][1] == "hello") +end + + +do -- bug introduced in commit 9cf3299fa + local t = setmetatable({}, {__mode = "kv"}) -- all-weak table + collectgarbage() -- full collection + assert(not T or T.gcage(t) == "old") + t[1] = {10} + assert(not T or (T.gcage(t) == "touched1" and T.gccolor(t) == "gray")) + collectgarbage("step", 0) -- minor collection + assert(not T or (T.gcage(t) == "touched2" and T.gccolor(t) == "black")) + collectgarbage("step", 0) -- minor collection + assert(not T or T.gcage(t) == "old") -- t should be black, but it was gray + t[1] = {10} -- no barrier here, so t was still old + collectgarbage("step", 0) -- minor collection + -- t, being old, is ignored by the collection, so it is not cleared + assert(t[1] == nil) -- fails with the bug +end + + if T == nil then (Message or print)('\n >>> testC not active: \z skipping some generational tests <<<\n') @@ -72,6 +158,9 @@ assert(debug.getuservalue(U).x[1] == 234) end +-- just to make sure +assert(collectgarbage'isrunning') + -- just to make sure diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/locals.lua new/lua-5.4.1-tests/locals.lua --- old/lua-5.4.0-tests/locals.lua 2020-06-18 16:25:55.000000000 +0200 +++ new/lua-5.4.1-tests/locals.lua 2020-09-30 11:36:54.000000000 +0200 @@ -337,7 +337,7 @@ if not T then warn("@on") -- back to normal else - assert(_WARN == nil) + assert(_WARN == false) warn("@normal") end end @@ -346,7 +346,7 @@ local function checkwarn (msg) if T then assert(string.find(_WARN, msg)) - _WARN = nil -- reset variable to check next warning + _WARN = false -- reset variable to check next warning end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/ltests/ltests.c new/lua-5.4.1-tests/ltests/ltests.c --- old/lua-5.4.0-tests/ltests/ltests.c 2020-06-18 16:25:54.000000000 +0200 +++ new/lua-5.4.1-tests/ltests/ltests.c 2020-09-30 11:36:51.000000000 +0200 @@ -121,7 +121,8 @@ strcat(buff, msg); /* add new message to current warning */ if (!tocont) { /* message finished? */ lua_unlock(L); - if (lua_getglobal(L, "_WARN") == LUA_TNIL) + lua_getglobal(L, "_WARN"); + if (!lua_toboolean(L, -1)) lua_pop(L, 1); /* ok, no previous unexpected warning */ else { badexit("Unhandled warning in store mode: %s\naborting...\n", @@ -144,7 +145,6 @@ lua_pushstring(L, buff); lua_setglobal(L, "_WARN"); /* assign message to global '_WARN' */ lua_lock(L); - buff[0] = '\0'; /* prepare buffer for next warning */ break; } } @@ -186,7 +186,8 @@ Memcontrol l_memcontrol = - {0UL, 0UL, 0UL, 0UL, (~0UL), {0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL}}; + {0, 0UL, 0UL, 0UL, 0UL, (~0UL), + {0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL}}; static void freeblock (Memcontrol *mc, Header *block) { @@ -225,6 +226,10 @@ freeblock(mc, block); return NULL; } + if (mc->failnext) { + mc->failnext = 0; + return NULL; /* fake a single memory allocation error */ + } if (mc->countlimit != ~0UL && size != oldsize) { /* count limit in use? */ if (mc->countlimit == 0) return NULL; /* fake a memory allocation error */ @@ -309,6 +314,10 @@ } +void lua_printobj (lua_State *L, struct GCObject *o) { + printobj(G(L), o); +} + static int testobjref (global_State *g, GCObject *f, GCObject *t) { int r1 = testobjref1(g, f, t); if (!r1) { @@ -509,10 +518,16 @@ } -static void checkgraylist (global_State *g, GCObject *o) { +static lu_mem checkgraylist (global_State *g, GCObject *o) { + int total = 0; /* count number of elements in the list */ ((void)g); /* better to keep it available if we need to print an object */ while (o) { - lua_assert(isgray(o) || getage(o) == G_TOUCHED2); + lua_assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2)); + //lua_assert(isgray(o) || getage(o) == G_TOUCHED2); + lua_assert(!testbit(o->marked, TESTBIT)); + if (keepinvariant(g)) + l_setbit(o->marked, TESTBIT); /* mark that object is in a gray list */ + total++; switch (o->tt) { case LUA_VTABLE: o = gco2t(o)->gclist; break; case LUA_VLCL: o = gco2lcl(o)->gclist; break; @@ -526,40 +541,72 @@ default: lua_assert(0); /* other objects cannot be in a gray list */ } } + return total; } /* ** Check objects in gray lists. */ -static void checkgrays (global_State *g) { - if (!keepinvariant(g)) return; - checkgraylist(g, g->gray); - checkgraylist(g, g->grayagain); - checkgraylist(g, g->weak); - checkgraylist(g, g->ephemeron); +static lu_mem checkgrays (global_State *g) { + int total = 0; /* count number of elements in all lists */ + if (!keepinvariant(g)) return total; + total += checkgraylist(g, g->gray); + total += checkgraylist(g, g->grayagain); + total += checkgraylist(g, g->weak); + total += checkgraylist(g, g->allweak); + total += checkgraylist(g, g->ephemeron); + return total; } -static void checklist (global_State *g, int maybedead, int tof, +/* +** Check whether 'o' should be in a gray list. If so, increment +** 'count' and check its TESTBIT. (It must have been previously set by +** 'checkgraylist'.) +*/ +static void incifingray (global_State *g, GCObject *o, lu_mem *count) { + if (!keepinvariant(g)) + return; /* gray lists not being kept in these phases */ + if (o->tt == LUA_VUPVAL) { + /* only open upvalues can be gray */ + lua_assert(!isgray(o) || upisopen(gco2upv(o))); + return; /* upvalues are never in gray lists */ + } + /* these are the ones that must be in gray lists */ + if (isgray(o) || getage(o) == G_TOUCHED2) { + (*count)++; + lua_assert(testbit(o->marked, TESTBIT)); + resetbit(o->marked, TESTBIT); /* prepare for next cycle */ + } +} + + +static lu_mem checklist (global_State *g, int maybedead, int tof, GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) { GCObject *o; + lu_mem total = 0; /* number of object that should be in gray lists */ for (o = newl; o != survival; o = o->next) { checkobject(g, o, maybedead, G_NEW); + incifingray(g, o, &total); lua_assert(!tof == !tofinalize(o)); } for (o = survival; o != old; o = o->next) { checkobject(g, o, 0, G_SURVIVAL); + incifingray(g, o, &total); lua_assert(!tof == !tofinalize(o)); } for (o = old; o != reallyold; o = o->next) { checkobject(g, o, 0, G_OLD1); + incifingray(g, o, &total); lua_assert(!tof == !tofinalize(o)); } for (o = reallyold; o != NULL; o = o->next) { checkobject(g, o, 0, G_OLD); + incifingray(g, o, &total); lua_assert(!tof == !tofinalize(o)); } + return total; } @@ -567,13 +614,15 @@ global_State *g = G(L); GCObject *o; int maybedead; + lu_mem totalin; /* total of objects that are in gray lists */ + lu_mem totalshould; /* total of objects that should be in gray lists */ if (keepinvariant(g)) { lua_assert(!iswhite(g->mainthread)); lua_assert(!iswhite(gcvalue(&g->l_registry))); } lua_assert(!isdead(g, gcvalue(&g->l_registry))); lua_assert(g->sweepgc == NULL || issweepphase(g)); - checkgrays(g); + totalin = checkgrays(g); /* check 'fixedgc' list */ for (o = g->fixedgc; o != NULL; o = o->next) { @@ -582,17 +631,22 @@ /* check 'allgc' list */ maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSswpallgc); - checklist(g, maybedead, 0, g->allgc, g->survival, g->old, g->reallyold); + totalshould = checklist(g, maybedead, 0, g->allgc, + g->survival, g->old1, g->reallyold); /* check 'finobj' list */ - checklist(g, 0, 1, g->finobj, g->finobjsur, g->finobjold, g->finobjrold); + totalshould += checklist(g, 0, 1, g->finobj, + g->finobjsur, g->finobjold1, g->finobjrold); /* check 'tobefnz' list */ for (o = g->tobefnz; o != NULL; o = o->next) { checkobject(g, o, 0, G_NEW); + incifingray(g, o, &totalshould); lua_assert(tofinalize(o)); lua_assert(o->tt == LUA_VUSERDATA || o->tt == LUA_VTABLE); } + if (keepinvariant(g)) + lua_assert(totalin == totalshould); return 0; } @@ -748,11 +802,12 @@ static void printstack (lua_State *L) { int i; int n = lua_gettop(L); + printf("stack: >>\n"); for (i = 1; i <= n; i++) { printf("%3d: %s\n", i, luaL_tolstring(L, i, NULL)); lua_pop(L, 1); } - printf("\n"); + printf("<<\n"); } @@ -802,6 +857,13 @@ l_memcontrol.countlimit = luaL_checkinteger(L, 1); return 0; } + + +static int alloc_failnext (lua_State *L) { + UNUSED(L); + l_memcontrol.failnext = 1; + return 0; +} static int settrick (lua_State *L) { @@ -1282,10 +1344,19 @@ } -static void pushcode (lua_State *L, int code) { - static const char *const codes[] = {"OK", "YIELD", "ERRRUN", - "ERRSYNTAX", MEMERRMSG, "ERRGCMM", "ERRERR"}; - lua_pushstring(L, codes[code]); +static const char *const statcodes[] = {"OK", "YIELD", "ERRRUN", + "ERRSYNTAX", MEMERRMSG, "ERRGCMM", "ERRERR"}; + +/* +** Avoid these stat codes from being collected, to avoid possible +** memory error when pushing them. +*/ +static void regcodes (lua_State *L) { + unsigned int i; + for (i = 0; i < sizeof(statcodes) / sizeof(statcodes[0]); i++) { + lua_pushboolean(L, 1); + lua_setfield(L, LUA_REGISTRYINDEX, statcodes[i]); + } } @@ -1508,7 +1579,7 @@ lua_pushnumber(L1, (lua_Number)getnum); } else if EQ("pushstatus") { - pushcode(L1, status); + lua_pushstring(L1, statcodes[status]); } else if EQ("pushstring") { lua_pushstring(L1, getstring); @@ -1668,6 +1739,9 @@ if (n == 0) n = lua_gettop(fs); lua_xmove(fs, ts, n); } + else if EQ("isyieldable") { + lua_pushboolean(L1, lua_isyieldable(lua_tothread(L1, getindex))); + } else if EQ("yield") { return lua_yield(L1, getnum); } @@ -1710,7 +1784,7 @@ static int Cfunck (lua_State *L, int status, lua_KContext ctx) { - pushcode(L, status); + lua_pushstring(L, statcodes[status]); lua_setglobal(L, "status"); lua_pushinteger(L, ctx); lua_setglobal(L, "ctx"); @@ -1847,6 +1921,7 @@ {"makeCfunc", makeCfunc}, {"totalmem", mem_query}, {"alloccount", alloc_count}, + {"allocfailnext", alloc_failnext}, {"trick", settrick}, {"udataval", udataval}, {"unref", unref}, @@ -1865,6 +1940,9 @@ void *ud; lua_atpanic(L, &tpanic); lua_setwarnf(L, &warnf, L); + lua_pushboolean(L, 0); + lua_setglobal(L, "_WARN"); /* _WARN = false */ + regcodes(L); atexit(checkfinalmem); lua_assert(lua_getallocf(L, &ud) == debug_realloc); lua_assert(ud == cast_voidp(&l_memcontrol)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/ltests/ltests.h new/lua-5.4.1-tests/ltests/ltests.h --- old/lua-5.4.0-tests/ltests/ltests.h 2020-06-18 16:25:54.000000000 +0200 +++ new/lua-5.4.1-tests/ltests/ltests.h 2020-09-30 11:36:51.000000000 +0200 @@ -20,9 +20,7 @@ /* turn on assertions */ -#undef NDEBUG -#include <assert.h> -#define lua_assert(c) assert(c) +#define LUAI_ASSERT @@ -53,6 +51,7 @@ /* memory-allocator control variables */ typedef struct Memcontrol { + int failnext; unsigned long numblocks; unsigned long total; unsigned long maxmem; @@ -74,7 +73,13 @@ /* ** Function to traverse and check all memory used by Lua */ -int lua_checkmemory (lua_State *L); +LUAI_FUNC int lua_checkmemory (lua_State *L); + +/* +** Function to print an object GC-friendly +*/ +struct GCObject; +LUAI_FUNC void lua_printobj (lua_State *L, struct GCObject *o); /* test for lock/unlock */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/main.lua new/lua-5.4.1-tests/main.lua --- old/lua-5.4.0-tests/main.lua 2020-06-18 16:25:55.000000000 +0200 +++ new/lua-5.4.1-tests/main.lua 2020-09-30 11:36:54.000000000 +0200 @@ -393,12 +393,12 @@ -- testing 'warn' warn("@store") warn("@123", "456", "789") - assert(_WARN == "@123456789"); _WARN = nil + assert(_WARN == "@123456789"); _WARN = false warn("zip", "", " ", "zap") - assert(_WARN == "zip zap"); _WARN = nil + assert(_WARN == "zip zap"); _WARN = false warn("ZIP", "", " ", "ZAP") - assert(_WARN == "ZIP ZAP"); _WARN = nil + assert(_WARN == "ZIP ZAP"); _WARN = false warn("@normal") end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/nextvar.lua new/lua-5.4.1-tests/nextvar.lua --- old/lua-5.4.0-tests/nextvar.lua 2020-06-18 16:25:55.000000000 +0200 +++ new/lua-5.4.1-tests/nextvar.lua 2020-09-30 11:36:54.000000000 +0200 @@ -88,6 +88,7 @@ arr[1 + sa + sh + 1] = "}" local prog = table.concat(arr) local f = assert(load(prog)) + collectgarbage("stop") f() -- call once to ensure stack space -- make sure table is not resized after being created if sa == 0 or sh == 0 then @@ -97,6 +98,7 @@ end local t = f() T.alloccount(); + collectgarbage("restart") assert(#t == sa) check(t, sa, mp2(sh)) end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lua-5.4.0-tests/strings.lua new/lua-5.4.1-tests/strings.lua --- old/lua-5.4.0-tests/strings.lua 2020-06-18 16:25:55.000000000 +0200 +++ new/lua-5.4.1-tests/strings.lua 2020-09-30 11:36:54.000000000 +0200 @@ -438,7 +438,7 @@ -- formats %U, %f, %I already tested elsewhere - local blen = 400 -- internal buffer length in 'luaO_pushfstring' + local blen = 200 -- internal buffer length in 'luaO_pushfstring' local function callpfs (op, fmt, n) local x = {T.testC("pushfstring" .. op .. "; return *", fmt, n)} ++++++ lua-5.4.0-tests.tar.gz -> lua-5.4.1.tar.gz ++++++ ++++ 60560 lines of diff (skipped)