forked from pool/lua54
Accepting request 949765 from devel:languages:lua
- Ensure shared library is installed with executable bit set - Update to Lua 5.4.4: * fixes all bugs found in Lua 5.4.3 - Removed upstream-bugs.patch: new release (no bugs found yet) - Removed upstream-bugs-test.patch: new release (no bugs found yet) OBS-URL: https://build.opensuse.org/request/show/949765 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/lua54?expand=0&rev=15
This commit is contained in:
commit
73f8db06e7
@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:5d29c3022897a8290f280ebe1c6853248dfa35a668e1fc02ba9c8cde4e7bf110
|
|
||||||
size 131911
|
|
@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:f8612276169e3bfcbcfb8f226195bfc6e466fe13042f1076cbde92b7ec96bbfb
|
|
||||||
size 358216
|
|
BIN
lua-5.4.4-tests.tar.gz
(Stored with Git LFS)
Normal file
BIN
lua-5.4.4-tests.tar.gz
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
lua-5.4.4.tar.gz
(Stored with Git LFS)
Normal file
BIN
lua-5.4.4.tar.gz
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -4,7 +4,7 @@ Subject: build system
|
|||||||
|
|
||||||
--- a/Makefile
|
--- a/Makefile
|
||||||
+++ b/Makefile
|
+++ b/Makefile
|
||||||
@@ -10,19 +12,20 @@
|
@@ -10,19 +12,19 @@
|
||||||
# so take care if INSTALL_TOP is not an absolute path. See the local target.
|
# so take care if INSTALL_TOP is not an absolute path. See the local target.
|
||||||
# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with
|
# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with
|
||||||
# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h.
|
# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h.
|
||||||
@ -27,7 +27,6 @@ Subject: build system
|
|||||||
-INSTALL_EXEC= $(INSTALL) -m 0755
|
-INSTALL_EXEC= $(INSTALL) -m 0755
|
||||||
+INSTALL_EXEC= $(LIBTOOL) --mode=install install -m 0755
|
+INSTALL_EXEC= $(LIBTOOL) --mode=install install -m 0755
|
||||||
INSTALL_DATA= $(INSTALL) -m 0644
|
INSTALL_DATA= $(INSTALL) -m 0644
|
||||||
+INSTALL_LIBTOOL= $(LIBTOOL) --mode=install install -m 0644
|
|
||||||
#
|
#
|
||||||
# If you don't have "install" you can use "cp" instead.
|
# If you don't have "install" you can use "cp" instead.
|
||||||
# INSTALL= cp -p
|
# INSTALL= cp -p
|
||||||
@ -54,7 +53,7 @@ Subject: build system
|
|||||||
|
|
||||||
install: dummy
|
install: dummy
|
||||||
cd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD)
|
cd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD)
|
||||||
+ cd src && $(INSTALL_LIBTOOL) $(TO_LIB) $(INSTALL_LIB)
|
+ cd src && $(INSTALL_EXEC) $(TO_LIB) $(INSTALL_LIB)
|
||||||
cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN)
|
cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN)
|
||||||
cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC)
|
cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC)
|
||||||
- cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB)
|
- cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB)
|
||||||
|
@ -1,3 +1,16 @@
|
|||||||
|
-------------------------------------------------------------------
|
||||||
|
Wed Jan 26 19:15:13 UTC 2022 - Callum Farmer <gmbr3@opensuse.org>
|
||||||
|
|
||||||
|
- Ensure shared library is installed with executable bit set
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Wed Jan 26 18:35:13 UTC 2022 - Callum Farmer <gmbr3@opensuse.org>
|
||||||
|
|
||||||
|
- Update to Lua 5.4.4:
|
||||||
|
* fixes all bugs found in Lua 5.4.3
|
||||||
|
- Removed upstream-bugs.patch: new release (no bugs found yet)
|
||||||
|
- Removed upstream-bugs-test.patch: new release (no bugs found yet)
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
Thu Dec 30 18:34:01 UTC 2021 - Callum Farmer <gmbr3@opensuse.org>
|
Thu Dec 30 18:34:01 UTC 2021 - Callum Farmer <gmbr3@opensuse.org>
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
%define libname liblua5_4-5
|
%define libname liblua5_4-5
|
||||||
%define lua_docdir %{_datadir}/doc/lua%{major_version}
|
%define lua_docdir %{_datadir}/doc/lua%{major_version}
|
||||||
Name: lua54%{name_ext}
|
Name: lua54%{name_ext}
|
||||||
Version: 5.4.3
|
Version: 5.4.4
|
||||||
Release: 0
|
Release: 0
|
||||||
Summary: Small Embeddable Language with Procedural Syntax
|
Summary: Small Embeddable Language with Procedural Syntax
|
||||||
License: GPL-3.0-or-later
|
License: GPL-3.0-or-later
|
||||||
@ -42,9 +42,6 @@ Patch0: lua-build-system.patch
|
|||||||
Patch1: attrib_test.patch
|
Patch1: attrib_test.patch
|
||||||
Patch2: files_test.patch
|
Patch2: files_test.patch
|
||||||
Patch3: main_test.patch
|
Patch3: main_test.patch
|
||||||
# PATCH-FIX-UPSTREAM https://www.lua.org/bugs.html#5.4.3
|
|
||||||
Patch4: upstream-bugs.patch
|
|
||||||
Patch5: upstream-bugs-test.patch
|
|
||||||
Patch6: shared_link.patch
|
Patch6: shared_link.patch
|
||||||
%if "%{flavor}" == "test"
|
%if "%{flavor}" == "test"
|
||||||
BuildRequires: lua54
|
BuildRequires: lua54
|
||||||
@ -145,11 +142,9 @@ of C functions, written in ANSI C.
|
|||||||
%patch1 -p1
|
%patch1 -p1
|
||||||
%patch2 -p1
|
%patch2 -p1
|
||||||
%patch3 -p1
|
%patch3 -p1
|
||||||
%patch5 -p1
|
|
||||||
%else
|
%else
|
||||||
%setup -q -n lua-%{version}
|
%setup -q -n lua-%{version}
|
||||||
%patch0 -p1
|
%patch0 -p1
|
||||||
%patch4 -p1
|
|
||||||
%patch6 -p1
|
%patch6 -p1
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
@ -20,3 +20,14 @@
|
|||||||
void* data, int strip);
|
void* data, int strip);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
--- a/src/lmem.h
|
||||||
|
+++ b/src/lmem.h
|
||||||
|
@@ -81,7 +81,7 @@
|
||||||
|
size_t size);
|
||||||
|
LUAI_FUNC void *luaM_saferealloc_ (lua_State *L, void *block, size_t oldsize,
|
||||||
|
size_t size);
|
||||||
|
-LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize);
|
||||||
|
+LUA_API void luaM_free_ (lua_State *L, void *block, size_t osize);
|
||||||
|
LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems,
|
||||||
|
int *size, int size_elem, int limit,
|
||||||
|
const char *what);
|
||||||
|
@ -1,370 +0,0 @@
|
|||||||
diff --git a/testes/locals.lua b/testes/locals.lua
|
|
||||||
index 2c67edbdb..6aad5d253 100644
|
|
||||||
--- a/locals.lua
|
|
||||||
+++ b/locals.lua
|
|
||||||
@@ -335,6 +335,29 @@ do
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
+do
|
|
||||||
+ -- bug in 5.4.3: previous condition (calls cannot be tail in the
|
|
||||||
+ -- scope of to-be-closed variables) must be valid for tbc variables
|
|
||||||
+ -- created by 'for' loops.
|
|
||||||
+
|
|
||||||
+ local closed = false
|
|
||||||
+
|
|
||||||
+ local function foo ()
|
|
||||||
+ return function () return true end, 0, 0,
|
|
||||||
+ func2close(function () closed = true end)
|
|
||||||
+ end
|
|
||||||
+
|
|
||||||
+ local function tail() return closed end
|
|
||||||
+
|
|
||||||
+ local function foo1 ()
|
|
||||||
+ for k in foo() do return tail() end
|
|
||||||
+ end
|
|
||||||
+
|
|
||||||
+ assert(foo1() == false)
|
|
||||||
+ assert(closed == true)
|
|
||||||
+end
|
|
||||||
+
|
|
||||||
+
|
|
||||||
do print("testing errors in __close")
|
|
||||||
|
|
||||||
-- original error is in __close
|
|
||||||
diff --git a/testes/locals.lua b/testes/locals.lua
|
|
||||||
index 6aad5d253..6151f64d0 100644
|
|
||||||
--- a/locals.lua
|
|
||||||
+++ b/locals.lua
|
|
||||||
@@ -813,6 +813,65 @@ do
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
+do
|
|
||||||
+ -- yielding inside closing metamethods while returning
|
|
||||||
+ -- (bug in 5.4.3)
|
|
||||||
+
|
|
||||||
+ local extrares -- result from extra yield (if any)
|
|
||||||
+
|
|
||||||
+ local function check (body, extra, ...)
|
|
||||||
+ local t = table.pack(...) -- expected returns
|
|
||||||
+ local co = coroutine.wrap(body)
|
|
||||||
+ if extra then
|
|
||||||
+ extrares = co() -- runs until first (extra) yield
|
|
||||||
+ end
|
|
||||||
+ local res = table.pack(co()) -- runs until yield inside '__close'
|
|
||||||
+ assert(res.n == 2 and res[2] == nil)
|
|
||||||
+ local res2 = table.pack(co()) -- runs until end of function
|
|
||||||
+ assert(res2.n == t.n)
|
|
||||||
+ for i = 1, #t do
|
|
||||||
+ if t[i] == "x" then
|
|
||||||
+ assert(res2[i] == res[1]) -- value that was closed
|
|
||||||
+ else
|
|
||||||
+ assert(res2[i] == t[i])
|
|
||||||
+ end
|
|
||||||
+ end
|
|
||||||
+ end
|
|
||||||
+
|
|
||||||
+ local function foo ()
|
|
||||||
+ local x <close> = func2close(coroutine.yield)
|
|
||||||
+ local extra <close> = func2close(function (self)
|
|
||||||
+ assert(self == extrares)
|
|
||||||
+ coroutine.yield(100)
|
|
||||||
+ end)
|
|
||||||
+ extrares = extra
|
|
||||||
+ return table.unpack{10, x, 30}
|
|
||||||
+ end
|
|
||||||
+ check(foo, true, 10, "x", 30)
|
|
||||||
+ assert(extrares == 100)
|
|
||||||
+
|
|
||||||
+ local function foo ()
|
|
||||||
+ local x <close> = func2close(coroutine.yield)
|
|
||||||
+ return
|
|
||||||
+ end
|
|
||||||
+ check(foo, false)
|
|
||||||
+
|
|
||||||
+ local function foo ()
|
|
||||||
+ local x <close> = func2close(coroutine.yield)
|
|
||||||
+ local y, z = 20, 30
|
|
||||||
+ return x
|
|
||||||
+ end
|
|
||||||
+ check(foo, false, "x")
|
|
||||||
+
|
|
||||||
+ local function foo ()
|
|
||||||
+ local x <close> = func2close(coroutine.yield)
|
|
||||||
+ local extra <close> = func2close(coroutine.yield)
|
|
||||||
+ return table.unpack({}, 1, 100) -- 100 nils
|
|
||||||
+ end
|
|
||||||
+ check(foo, true, table.unpack({}, 1, 100))
|
|
||||||
+
|
|
||||||
+end
|
|
||||||
+
|
|
||||||
do
|
|
||||||
-- yielding inside closing metamethods after an error
|
|
||||||
|
|
||||||
diff --git a/testes/locals.lua b/testes/locals.lua
|
|
||||||
index 6151f64d0..62a88df57 100644
|
|
||||||
--- a/locals.lua
|
|
||||||
+++ b/locals.lua
|
|
||||||
@@ -187,6 +187,8 @@ do -- constants
|
|
||||||
checkro("y", "local x, y <const>, z = 10, 20, 30; x = 11; y = 12")
|
|
||||||
checkro("x", "local x <const>, y, z <const> = 10, 20, 30; x = 11")
|
|
||||||
checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
|
|
||||||
+ checkro("foo", "local foo <const> = 10; function foo() end")
|
|
||||||
+ checkro("foo", "local foo <const> = {}; function foo() end")
|
|
||||||
|
|
||||||
checkro("z", [[
|
|
||||||
local a, z <const>, b = 10;
|
|
||||||
diff --git a/testes/bitwise.lua b/testes/bitwise.lua
|
|
||||||
index 59781f5df..9509f7f04 100644
|
|
||||||
--- a/bitwise.lua
|
|
||||||
+++ b/bitwise.lua
|
|
||||||
@@ -45,6 +45,11 @@ assert(-1 >> numbits == 0 and
|
|
||||||
-1 << numbits == 0 and
|
|
||||||
-1 << -numbits == 0)
|
|
||||||
|
|
||||||
+assert(1 >> math.mininteger == 0)
|
|
||||||
+assert(1 >> math.maxinteger == 0)
|
|
||||||
+assert(1 << math.mininteger == 0)
|
|
||||||
+assert(1 << math.maxinteger == 0)
|
|
||||||
+
|
|
||||||
assert((2^30 - 1) << 2^30 == 0)
|
|
||||||
assert((2^30 - 1) >> 2^30 == 0)
|
|
||||||
|
|
||||||
diff --git a/testes/errors.lua b/testes/errors.lua
|
|
||||||
index 825f37c29..a7dc479a2 100644
|
|
||||||
--- a/errors.lua
|
|
||||||
+++ b/errors.lua
|
|
||||||
@@ -228,6 +228,22 @@ do -- named objects (field '__name')
|
|
||||||
checkmessage("return {} < XX", "table with My Type")
|
|
||||||
checkmessage("return XX < io.stdin", "My Type with FILE*")
|
|
||||||
_G.XX = nil
|
|
||||||
+
|
|
||||||
+ if T then -- extra tests for 'luaL_tolstring'
|
|
||||||
+ -- bug in 5.4.3; 'luaL_tolstring' with negative indices
|
|
||||||
+ local x = setmetatable({}, {__name="TABLE"})
|
|
||||||
+ assert(T.testC("Ltolstring -1; return 1", x) == tostring(x))
|
|
||||||
+
|
|
||||||
+ local a, b = T.testC("pushint 10; Ltolstring -2; return 2", x)
|
|
||||||
+ assert(a == 10 and b == tostring(x))
|
|
||||||
+
|
|
||||||
+ setmetatable(x, {__tostring=function (o)
|
|
||||||
+ assert(o == x)
|
|
||||||
+ return "ABC"
|
|
||||||
+ end})
|
|
||||||
+ a, b, c = T.testC("pushint 10; Ltolstring -2; return 3", x)
|
|
||||||
+ assert(a == x and b == 10 and c == "ABC")
|
|
||||||
+ end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- global functions
|
|
||||||
diff --git a/ltests.c b/ltests.c
|
|
||||||
index a50f78304..97834e380 100644
|
|
||||||
--- a/ltests/ltests.c
|
|
||||||
+++ b/ltests/ltests.c
|
|
||||||
@@ -1743,6 +1743,9 @@ static struct X { int x; } x;
|
|
||||||
(void)s1; /* to avoid warnings */
|
|
||||||
lua_longassert((s == NULL && s1 == NULL) || strcmp(s, s1) == 0);
|
|
||||||
}
|
|
||||||
+ else if EQ("Ltolstring") {
|
|
||||||
+ luaL_tolstring(L1, getindex, NULL);
|
|
||||||
+ }
|
|
||||||
else if EQ("type") {
|
|
||||||
lua_pushstring(L1, luaL_typename(L1, getnum));
|
|
||||||
}
|
|
||||||
diff --git a/testes/cstack.lua b/testes/cstack.lua
|
|
||||||
index 213d15d47..ca76c8729 100644
|
|
||||||
--- a/cstack.lua
|
|
||||||
+++ b/cstack.lua
|
|
||||||
@@ -103,6 +103,20 @@ do
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
+do -- bug in 5.4.2
|
|
||||||
+ print("nesting coroutines running after recoverable errors")
|
|
||||||
+ local count = 0
|
|
||||||
+ local function foo()
|
|
||||||
+ count = count + 1
|
|
||||||
+ pcall(1) -- create an error
|
|
||||||
+ -- running now inside 'precover' ("protected recover")
|
|
||||||
+ coroutine.wrap(foo)() -- call another coroutine
|
|
||||||
+ end
|
|
||||||
+ checkerror("C stack overflow", foo)
|
|
||||||
+ print("final count: ", count)
|
|
||||||
+end
|
|
||||||
+
|
|
||||||
+
|
|
||||||
if T then
|
|
||||||
print("testing stack recovery")
|
|
||||||
local N = 0 -- trace number of calls
|
|
||||||
diff --git a/testes/coroutine.lua b/testes/coroutine.lua
|
|
||||||
index 461e03770..76c9d6e63 100644
|
|
||||||
--- a/coroutine.lua
|
|
||||||
+++ b/coroutine.lua
|
|
||||||
@@ -136,6 +136,10 @@ do
|
|
||||||
assert(coroutine.status(co) == "dead")
|
|
||||||
local st, msg = coroutine.close(co)
|
|
||||||
assert(st and msg == nil)
|
|
||||||
+ -- also ok to close it again
|
|
||||||
+ st, msg = coroutine.close(co)
|
|
||||||
+ assert(st and msg == nil)
|
|
||||||
+
|
|
||||||
|
|
||||||
-- cannot close the running coroutine
|
|
||||||
local st, msg = pcall(coroutine.close, coroutine.running())
|
|
||||||
@@ -149,6 +153,22 @@ do
|
|
||||||
assert(not st and string.find(msg, "normal"))
|
|
||||||
end))()
|
|
||||||
|
|
||||||
+ -- cannot close a coroutine while closing it
|
|
||||||
+ do
|
|
||||||
+ local co
|
|
||||||
+ co = coroutine.create(
|
|
||||||
+ function()
|
|
||||||
+ local x <close> = func2close(function()
|
|
||||||
+ coroutine.close(co) -- try to close it again
|
|
||||||
+ end)
|
|
||||||
+ coroutine.yield(20)
|
|
||||||
+ end)
|
|
||||||
+ local st, msg = coroutine.resume(co)
|
|
||||||
+ assert(st and msg == 20)
|
|
||||||
+ st, msg = coroutine.close(co)
|
|
||||||
+ assert(not st and string.find(msg, "running coroutine"))
|
|
||||||
+ end
|
|
||||||
+
|
|
||||||
-- to-be-closed variables in coroutines
|
|
||||||
local X
|
|
||||||
|
|
||||||
@@ -158,6 +178,9 @@ do
|
|
||||||
assert(not st and msg == 100)
|
|
||||||
st, msg = coroutine.close(co)
|
|
||||||
assert(not st and msg == 100)
|
|
||||||
+ -- after closing, no more errors
|
|
||||||
+ st, msg = coroutine.close(co)
|
|
||||||
+ assert(st and msg == nil)
|
|
||||||
|
|
||||||
co = coroutine.create(function ()
|
|
||||||
local x <close> = func2close(function (self, err)
|
|
||||||
@@ -189,6 +212,9 @@ do
|
|
||||||
local st, msg = coroutine.close(co)
|
|
||||||
assert(st == false and coroutine.status(co) == "dead" and msg == 200)
|
|
||||||
assert(x == 200)
|
|
||||||
+ -- after closing, no more errors
|
|
||||||
+ st, msg = coroutine.close(co)
|
|
||||||
+ assert(st and msg == nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
do
|
|
||||||
@@ -419,7 +445,7 @@ do
|
|
||||||
|
|
||||||
local X = false
|
|
||||||
A = coroutine.wrap(function()
|
|
||||||
- local _ <close> = setmetatable({}, {__close = function () X = true end})
|
|
||||||
+ local _ <close> = func2close(function () X = true end)
|
|
||||||
return pcall(A, 1)
|
|
||||||
end)
|
|
||||||
st, res = A()
|
|
||||||
@@ -427,6 +453,22 @@ do
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
+-- bug in 5.4.1
|
|
||||||
+do
|
|
||||||
+ -- coroutine ran close metamethods with invalid status during a
|
|
||||||
+ -- reset.
|
|
||||||
+ local co
|
|
||||||
+ co = coroutine.wrap(function()
|
|
||||||
+ local x <close> = func2close(function() return pcall(co) end)
|
|
||||||
+ error(111)
|
|
||||||
+ end)
|
|
||||||
+ local st, errobj = pcall(co)
|
|
||||||
+ assert(not st and errobj == 111)
|
|
||||||
+ st, errobj = pcall(co)
|
|
||||||
+ assert(not st and string.find(errobj, "dead coroutine"))
|
|
||||||
+end
|
|
||||||
+
|
|
||||||
+
|
|
||||||
-- attempt to resume 'normal' coroutine
|
|
||||||
local co1, co2
|
|
||||||
co1 = coroutine.create(function () return co2() end)
|
|
||||||
diff --git a/testes/api.lua b/testes/api.lua
|
|
||||||
index c1bcb4b7b..bd85a923c 100644
|
|
||||||
--- a/api.lua
|
|
||||||
+++ b/api.lua
|
|
||||||
@@ -804,15 +804,14 @@ F = function (x)
|
|
||||||
d = nil
|
|
||||||
assert(debug.getmetatable(x).__gc == F)
|
|
||||||
assert(load("table.insert({}, {})"))() -- create more garbage
|
|
||||||
- collectgarbage() -- force a GC during GC
|
|
||||||
- assert(debug.getmetatable(x).__gc == F) -- previous GC did not mess this?
|
|
||||||
+ assert(not collectgarbage()) -- GC during GC (no op)
|
|
||||||
local dummy = {} -- create more garbage during GC
|
|
||||||
if A ~= nil then
|
|
||||||
assert(type(A) == "userdata")
|
|
||||||
assert(T.udataval(A) == B)
|
|
||||||
debug.getmetatable(A) -- just access it
|
|
||||||
end
|
|
||||||
- A = x -- ressucita userdata
|
|
||||||
+ A = x -- ressurect userdata
|
|
||||||
B = udval
|
|
||||||
return 1,2,3
|
|
||||||
end
|
|
||||||
diff --git a/testes/gc.lua b/testes/gc.lua
|
|
||||||
index 2332c939a..d865cb28d 100644
|
|
||||||
--- a/gc.lua
|
|
||||||
+++ b/gc.lua
|
|
||||||
@@ -676,11 +676,13 @@ end
|
|
||||||
-- just to make sure
|
|
||||||
assert(collectgarbage'isrunning')
|
|
||||||
|
|
||||||
-do -- check that the collector is reentrant in incremental mode
|
|
||||||
+do -- check that the collector is not reentrant in incremental mode
|
|
||||||
+ local res = true
|
|
||||||
setmetatable({}, {__gc = function ()
|
|
||||||
- collectgarbage()
|
|
||||||
+ res = collectgarbage()
|
|
||||||
end})
|
|
||||||
collectgarbage()
|
|
||||||
+ assert(not res)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/testes/main.lua b/testes/main.lua
|
|
||||||
index 52c779541..9def63860 100644
|
|
||||||
--- a/main.lua
|
|
||||||
+++ b/main.lua
|
|
||||||
@@ -261,6 +261,34 @@ u2 = setmetatable({}, {__gc = function () error("ZYX") end})
|
|
||||||
RUN('lua -W %s 2> %s', prog, out)
|
|
||||||
checkprogout("ZYX)\nXYZ)\n")
|
|
||||||
|
|
||||||
+-- bug since 5.2: finalizer called when closing a state could
|
|
||||||
+-- subvert finalization order
|
|
||||||
+prepfile[[
|
|
||||||
+-- should be called last
|
|
||||||
+print("creating 1")
|
|
||||||
+setmetatable({}, {__gc = function () print(1) end})
|
|
||||||
+
|
|
||||||
+print("creating 2")
|
|
||||||
+setmetatable({}, {__gc = function ()
|
|
||||||
+ print("2")
|
|
||||||
+ print("creating 3")
|
|
||||||
+ -- this finalizer should not be called, as object will be
|
|
||||||
+ -- created after 'lua_close' has been called
|
|
||||||
+ setmetatable({}, {__gc = function () print(3) end})
|
|
||||||
+ print(collectgarbage()) -- cannot call collector here
|
|
||||||
+ os.exit(0, true)
|
|
||||||
+end})
|
|
||||||
+]]
|
|
||||||
+RUN('lua -W %s > %s', prog, out)
|
|
||||||
+checkout[[
|
|
||||||
+creating 1
|
|
||||||
+creating 2
|
|
||||||
+2
|
|
||||||
+creating 3
|
|
||||||
+nil
|
|
||||||
+1
|
|
||||||
+]]
|
|
||||||
+
|
|
||||||
|
|
||||||
-- test many arguments
|
|
||||||
prepfile[[print(({...})[30])]]
|
|
@ -1,665 +0,0 @@
|
|||||||
From 47cffdc723c2e0c6dfaf62b7775ca1c1d338c0a4 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
|
|
||||||
Date: Wed, 7 Apr 2021 14:59:26 -0300
|
|
||||||
Subject: [PATCH] Bug: tbc variables in "for" loops don't avoid tail calls
|
|
||||||
|
|
||||||
---
|
|
||||||
lparser.c | 21 +++++++++++++++------
|
|
||||||
testes/locals.lua | 23 +++++++++++++++++++++++
|
|
||||||
2 files changed, 38 insertions(+), 6 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/lparser.c b/lparser.c
|
|
||||||
index 284ef1f0c..df9473c27 100644
|
|
||||||
--- a/src/lparser.c
|
|
||||||
+++ b/src/lparser.c
|
|
||||||
@@ -416,6 +416,17 @@ static void markupval (FuncState *fs, int level) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+** Mark that current block has a to-be-closed variable.
|
|
||||||
+*/
|
|
||||||
+static void marktobeclosed (FuncState *fs) {
|
|
||||||
+ BlockCnt *bl = fs->bl;
|
|
||||||
+ bl->upval = 1;
|
|
||||||
+ bl->insidetbc = 1;
|
|
||||||
+ fs->needclose = 1;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
** Find a variable with the given name 'n'. If it is an upvalue, add
|
|
||||||
** this upvalue into all intermediate functions. If it is a global, set
|
|
||||||
@@ -1599,7 +1610,7 @@ static void forlist (LexState *ls, TString *indexname) {
|
|
||||||
line = ls->linenumber;
|
|
||||||
adjust_assign(ls, 4, explist(ls, &e), &e);
|
|
||||||
adjustlocalvars(ls, 4); /* control variables */
|
|
||||||
- markupval(fs, fs->nactvar); /* last control var. must be closed */
|
|
||||||
+ marktobeclosed(fs); /* last control var. must be closed */
|
|
||||||
luaK_checkstack(fs, 3); /* extra space to call generator */
|
|
||||||
forbody(ls, base, line, nvars - 4, 1);
|
|
||||||
}
|
|
||||||
@@ -1703,11 +1714,9 @@ static int getlocalattribute (LexState *ls) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
-static void checktoclose (LexState *ls, int level) {
|
|
||||||
+static void checktoclose (FuncState *fs, int level) {
|
|
||||||
if (level != -1) { /* is there a to-be-closed variable? */
|
|
||||||
- FuncState *fs = ls->fs;
|
|
||||||
- markupval(fs, level + 1);
|
|
||||||
- fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
|
|
||||||
+ marktobeclosed(fs);
|
|
||||||
luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1751,7 +1760,7 @@ static void localstat (LexState *ls) {
|
|
||||||
adjust_assign(ls, nvars, nexps, &e);
|
|
||||||
adjustlocalvars(ls, nvars);
|
|
||||||
}
|
|
||||||
- checktoclose(ls, toclose);
|
|
||||||
+ checktoclose(fs, toclose);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
From d205f3a4847bc8b835fda91f51ba1cf45b796baf Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
|
|
||||||
Date: Sat, 10 Apr 2021 10:19:21 -0300
|
|
||||||
Subject: [PATCH] Bug: Lua source should not use C99 comments ("//")
|
|
||||||
|
|
||||||
---
|
|
||||||
lvm.c | 6 ++++--
|
|
||||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/lvm.c b/lvm.c
|
|
||||||
index c9729bcca..16e01d683 100644
|
|
||||||
--- a/src/lvm.c
|
|
||||||
+++ b/src/lvm.c
|
|
||||||
@@ -1156,8 +1156,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|
||||||
Instruction i; /* instruction being executed */
|
|
||||||
StkId ra; /* instruction's A register */
|
|
||||||
vmfetch();
|
|
||||||
-// low-level line tracing for debugging Lua
|
|
||||||
-// printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
|
|
||||||
+ #if 0
|
|
||||||
+ /* low-level line tracing for debugging Lua */
|
|
||||||
+ printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
|
|
||||||
+ #endif
|
|
||||||
lua_assert(base == ci->func + 1);
|
|
||||||
lua_assert(base <= L->top && L->top < L->stack_last);
|
|
||||||
/* invalidate top for instructions not expecting it */
|
|
||||||
From 681297187ec45268e872b26753c441586c12bdd8 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
|
|
||||||
Date: Fri, 16 Apr 2021 15:41:44 -0300
|
|
||||||
Subject: [PATCH] Bug: yielding in '__close' mess up number of returns
|
|
||||||
|
|
||||||
Yielding in a __close metamethod called when returning vararg results
|
|
||||||
changes the top and so messes up the number of returned values.
|
|
||||||
---
|
|
||||||
lstate.h | 2 +-
|
|
||||||
lvm.c | 12 +++++++++-
|
|
||||||
testes/locals.lua | 59 +++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
3 files changed, 71 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/lstate.h b/lstate.h
|
|
||||||
index c1283bb6b..44cf939cb 100644
|
|
||||||
--- a/src/lstate.h
|
|
||||||
+++ b/src/lstate.h
|
|
||||||
@@ -165,7 +165,7 @@ typedef struct stringtable {
|
|
||||||
** - field 'nyield' is used only while a function is "doing" an
|
|
||||||
** yield (from the yield until the next resume);
|
|
||||||
** - field 'nres' is used only while closing tbc variables when
|
|
||||||
-** returning from a C function;
|
|
||||||
+** returning from a function;
|
|
||||||
** - field 'transferinfo' is used only during call/returnhooks,
|
|
||||||
** before the function starts or after it ends.
|
|
||||||
*/
|
|
||||||
diff --git a/lvm.c b/lvm.c
|
|
||||||
index 16e01d683..e4b1903e7 100644
|
|
||||||
--- a/src/lvm.c
|
|
||||||
+++ b/src/lvm.c
|
|
||||||
@@ -847,10 +847,19 @@ void luaV_finishOp (lua_State *L) {
|
|
||||||
luaV_concat(L, total); /* concat them (may yield again) */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
- case OP_CLOSE: case OP_RETURN: { /* yielded closing variables */
|
|
||||||
+ case OP_CLOSE: { /* yielded closing variables */
|
|
||||||
ci->u.l.savedpc--; /* repeat instruction to close other vars. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
+ case OP_RETURN: { /* yielded closing variables */
|
|
||||||
+ StkId ra = base + GETARG_A(inst);
|
|
||||||
+ /* adjust top to signal correct number of returns, in case the
|
|
||||||
+ return is "up to top" ('isIT') */
|
|
||||||
+ L->top = ra + ci->u2.nres;
|
|
||||||
+ /* repeat instruction to close other vars. and complete the return */
|
|
||||||
+ ci->u.l.savedpc--;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
default: {
|
|
||||||
/* only these other opcodes can yield */
|
|
||||||
lua_assert(op == OP_TFORCALL || op == OP_CALL ||
|
|
||||||
@@ -1672,6 +1681,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|
||||||
n = cast_int(L->top - ra); /* get what is available */
|
|
||||||
savepc(ci);
|
|
||||||
if (TESTARG_k(i)) { /* may there be open upvalues? */
|
|
||||||
+ ci->u2.nres = n; /* save number of returns */
|
|
||||||
if (L->top < ci->top)
|
|
||||||
L->top = ci->top;
|
|
||||||
luaF_close(L, base, CLOSEKTOP, 1);
|
|
||||||
From 6a0dace25a4b5b77f0fa6911de2ba26ef0fdff2c Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
|
|
||||||
Date: Sun, 20 Jun 2021 15:36:36 -0300
|
|
||||||
Subject: [PATCH] Bug: 'local function' can assign to '<const>' variables
|
|
||||||
|
|
||||||
---
|
|
||||||
lparser.c | 1 +
|
|
||||||
testes/locals.lua | 2 ++
|
|
||||||
2 files changed, 3 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/lparser.c b/lparser.c
|
|
||||||
index df9473c27..3abe3d751 100644
|
|
||||||
--- a/src/lparser.c
|
|
||||||
+++ b/src/lparser.c
|
|
||||||
@@ -1785,6 +1785,7 @@ static void funcstat (LexState *ls, int line) {
|
|
||||||
luaX_next(ls); /* skip FUNCTION */
|
|
||||||
ismethod = funcname(ls, &v);
|
|
||||||
body(ls, &b, ismethod, line);
|
|
||||||
+ check_readonly(ls, &v);
|
|
||||||
luaK_storevar(ls->fs, &v, &b);
|
|
||||||
luaK_fixline(ls->fs, line); /* definition "happens" in the first line */
|
|
||||||
}
|
|
||||||
From 62fb93442753cbfb828335cd172e71471dffd536 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
|
|
||||||
Date: Thu, 22 Jul 2021 13:44:53 -0300
|
|
||||||
Subject: [PATCH] Bug: Negation in 'luaV_shiftr' may overflow
|
|
||||||
|
|
||||||
Negation of an unchecked lua_Integer overflows with mininteger.
|
|
||||||
---
|
|
||||||
lvm.c | 2 +-
|
|
||||||
testes/bitwise.lua | 5 +++++
|
|
||||||
2 files changed, 6 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/lvm.c b/lvm.c
|
|
||||||
index ec83f4159..c84a665f5 100644
|
|
||||||
--- a/src/lvm.c
|
|
||||||
+++ b/src/lvm.c
|
|
||||||
@@ -766,7 +766,7 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
|
|
||||||
/*
|
|
||||||
** Shift left operation. (Shift right just negates 'y'.)
|
|
||||||
*/
|
|
||||||
-#define luaV_shiftr(x,y) luaV_shiftl(x,-(y))
|
|
||||||
+#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
|
|
||||||
|
|
||||||
lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
|
|
||||||
if (y < 0) { /* shift right? */
|
|
||||||
From 439e45a2f69549b674d6a6e2023e8debfa00a2b8 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
|
|
||||||
Date: Thu, 22 Jul 2021 13:48:43 -0300
|
|
||||||
Subject: [PATCH] Bug: luaL_tolstring may get confused with negative index
|
|
||||||
|
|
||||||
When object has a '__name' metafield, 'luaL_tolstring' used the
|
|
||||||
received index after pushing a string on the stack.
|
|
||||||
---
|
|
||||||
lauxlib.c | 1 +
|
|
||||||
ltests.c | 3 +++
|
|
||||||
testes/errors.lua | 16 ++++++++++++++++
|
|
||||||
3 files changed, 20 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/lauxlib.c b/lauxlib.c
|
|
||||||
index 94835ef93..8ed1da112 100644
|
|
||||||
--- a/src/lauxlib.c
|
|
||||||
+++ b/src/lauxlib.c
|
|
||||||
@@ -881,6 +881,7 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
|
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
|
|
||||||
+ idx = lua_absindex(L,idx);
|
|
||||||
if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */
|
|
||||||
if (!lua_isstring(L, -1))
|
|
||||||
luaL_error(L, "'__tostring' must return a string");
|
|
||||||
From 74d99057a5146755e737c479850f87fd0e3b6868 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
|
|
||||||
Date: Wed, 3 Nov 2021 15:04:18 -0300
|
|
||||||
Subject: [PATCH] Bug: C stack overflow with coroutines
|
|
||||||
|
|
||||||
'coroutine.resume' did not increment counter of C calls when
|
|
||||||
continuing execution after a protected error (that is,
|
|
||||||
while running 'precover').
|
|
||||||
---
|
|
||||||
ldo.c | 6 ++++--
|
|
||||||
testes/cstack.lua | 14 ++++++++++++++
|
|
||||||
2 files changed, 18 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/ldo.c b/ldo.c
|
|
||||||
index d0edc8b4f..66f890364 100644
|
|
||||||
--- a/src/ldo.c
|
|
||||||
+++ b/src/ldo.c
|
|
||||||
@@ -759,11 +759,10 @@ static void resume (lua_State *L, void *ud) {
|
|
||||||
StkId firstArg = L->top - n; /* first argument */
|
|
||||||
CallInfo *ci = L->ci;
|
|
||||||
if (L->status == LUA_OK) /* starting a coroutine? */
|
|
||||||
- ccall(L, firstArg - 1, LUA_MULTRET, 1); /* just call its body */
|
|
||||||
+ ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
|
|
||||||
else { /* resuming from previous yield */
|
|
||||||
lua_assert(L->status == LUA_YIELD);
|
|
||||||
L->status = LUA_OK; /* mark that it is running (again) */
|
|
||||||
- luaE_incCstack(L); /* control the C stack */
|
|
||||||
if (isLua(ci)) { /* yielded inside a hook? */
|
|
||||||
L->top = firstArg; /* discard arguments */
|
|
||||||
luaV_execute(L, ci); /* just continue running Lua code */
|
|
||||||
@@ -814,6 +813,9 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
|
|
||||||
else if (L->status != LUA_YIELD) /* ended with errors? */
|
|
||||||
return resume_error(L, "cannot resume dead coroutine", nargs);
|
|
||||||
L->nCcalls = (from) ? getCcalls(from) : 0;
|
|
||||||
+ if (getCcalls(L) >= LUAI_MAXCCALLS)
|
|
||||||
+ return resume_error(L, "C stack overflow", nargs);
|
|
||||||
+ L->nCcalls++;
|
|
||||||
luai_userstateresume(L, nargs);
|
|
||||||
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
|
|
||||||
status = luaD_rawrunprotected(L, resume, &nargs);
|
|
||||||
From bfbff3703edae789fa5efa9bf174f8e7cff4ded8 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
|
|
||||||
Date: Mon, 8 Nov 2021 11:55:25 -0300
|
|
||||||
Subject: [PATCH] Bug: Wrong status in coroutine during reset
|
|
||||||
|
|
||||||
When closing variables during 'coroutine.close' or 'lua_resetthread',
|
|
||||||
the status of a coroutine must be set to LUA_OK; a coroutine should
|
|
||||||
not run with any other status. (See assertion in 'lua_callk'.)
|
|
||||||
|
|
||||||
After the reset, the status should be kept as normal, as any error
|
|
||||||
was already reported.
|
|
||||||
---
|
|
||||||
lcorolib.c | 4 ++--
|
|
||||||
lstate.c | 4 ++--
|
|
||||||
testes/coroutine.lua | 44 +++++++++++++++++++++++++++++++++++++++++++-
|
|
||||||
3 files changed, 47 insertions(+), 5 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/lcorolib.c b/lcorolib.c
|
|
||||||
index fedbebec3..785a1e81a 100644
|
|
||||||
--- a/src/lcorolib.c
|
|
||||||
+++ b/src/lcorolib.c
|
|
||||||
@@ -78,7 +78,7 @@ static int luaB_auxwrap (lua_State *L) {
|
|
||||||
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
|
|
||||||
stat = lua_resetthread(co); /* close its tbc variables */
|
|
||||||
lua_assert(stat != LUA_OK);
|
|
||||||
- lua_xmove(co, L, 1); /* copy error message */
|
|
||||||
+ lua_xmove(co, L, 1); /* move error message to the caller */
|
|
||||||
}
|
|
||||||
if (stat != LUA_ERRMEM && /* not a memory error and ... */
|
|
||||||
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
|
|
||||||
@@ -179,7 +179,7 @@ static int luaB_close (lua_State *L) {
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lua_pushboolean(L, 0);
|
|
||||||
- lua_xmove(co, L, 1); /* copy error message */
|
|
||||||
+ lua_xmove(co, L, 1); /* move error message */
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diff --git a/lstate.c b/lstate.c
|
|
||||||
index bfc590262..5cb0847c8 100644
|
|
||||||
--- a/src/lstate.c
|
|
||||||
+++ b/src/lstate.c
|
|
||||||
@@ -166,7 +166,7 @@ void luaE_checkcstack (lua_State *L) {
|
|
||||||
if (getCcalls(L) == LUAI_MAXCCALLS)
|
|
||||||
luaG_runerror(L, "C stack overflow");
|
|
||||||
else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
|
|
||||||
- luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
|
|
||||||
+ luaD_throw(L, LUA_ERRERR); /* error while handling stack error */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -330,13 +330,13 @@ int luaE_resetthread (lua_State *L, int status) {
|
|
||||||
ci->callstatus = CIST_C;
|
|
||||||
if (status == LUA_YIELD)
|
|
||||||
status = LUA_OK;
|
|
||||||
+ L->status = LUA_OK; /* so it can run __close metamethods */
|
|
||||||
status = luaD_closeprotected(L, 1, status);
|
|
||||||
if (status != LUA_OK) /* errors? */
|
|
||||||
luaD_seterrorobj(L, status, L->stack + 1);
|
|
||||||
else
|
|
||||||
L->top = L->stack + 1;
|
|
||||||
ci->top = L->top + LUA_MINSTACK;
|
|
||||||
- L->status = cast_byte(status);
|
|
||||||
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
From 1de95e97ef65632a88e08b6184bd9d1ceba7ec2f Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
|
|
||||||
Date: Fri, 10 Dec 2021 10:53:54 -0300
|
|
||||||
Subject: [PATCH] Bug: Lua stack still active when closing a state
|
|
||||||
|
|
||||||
---
|
|
||||||
lstate.c | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
diff --git a/lstate.c b/lstate.c
|
|
||||||
index 5cb0847c8..547a7a014 100644
|
|
||||||
--- a/src/lstate.c
|
|
||||||
+++ b/src/lstate.c
|
|
||||||
@@ -271,6 +271,7 @@ static void close_state (lua_State *L) {
|
|
||||||
if (!completestate(g)) /* closing a partially built state? */
|
|
||||||
luaC_freeallobjects(L); /* jucst collect its objects */
|
|
||||||
else { /* closing a fully built state */
|
|
||||||
+ L->ci = &L->base_ci; /* unwind CallInfo list */
|
|
||||||
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
|
|
||||||
luaC_freeallobjects(L); /* collect all objects */
|
|
||||||
luai_userstateclose(L);
|
|
||||||
From 0bfc572e51d9035a615ef6e9523f736c9ffa8e57 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
|
|
||||||
Date: Mon, 13 Dec 2021 10:41:17 -0300
|
|
||||||
Subject: [PATCH] Bug: GC is not reentrant
|
|
||||||
|
|
||||||
As the GC is not reentrant, finalizers should not be able to invoke it.
|
|
||||||
---
|
|
||||||
lapi.c | 17 +++++++++--------
|
|
||||||
lbaselib.c | 19 +++++++++++++++++--
|
|
||||||
lgc.c | 11 +++++++----
|
|
||||||
lgc.h | 9 +++++++++
|
|
||||||
lstate.c | 4 ++--
|
|
||||||
lstate.h | 2 +-
|
|
||||||
manual/manual.of | 11 ++++++-----
|
|
||||||
testes/api.lua | 5 ++---
|
|
||||||
testes/gc.lua | 6 ++++--
|
|
||||||
9 files changed, 57 insertions(+), 27 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/lapi.c b/lapi.c
|
|
||||||
index 071a06f3d..3585ac436 100644
|
|
||||||
--- a/src/lapi.c
|
|
||||||
+++ b/src/lapi.c
|
|
||||||
@@ -1136,18 +1136,19 @@ LUA_API int lua_status (lua_State *L) {
|
|
||||||
LUA_API int lua_gc (lua_State *L, int what, ...) {
|
|
||||||
va_list argp;
|
|
||||||
int res = 0;
|
|
||||||
- global_State *g;
|
|
||||||
+ global_State *g = G(L);
|
|
||||||
+ if (g->gcstp & GCSTPGC) /* internal stop? */
|
|
||||||
+ return -1; /* all options are invalid when stopped */
|
|
||||||
lua_lock(L);
|
|
||||||
- g = G(L);
|
|
||||||
va_start(argp, what);
|
|
||||||
switch (what) {
|
|
||||||
case LUA_GCSTOP: {
|
|
||||||
- g->gcrunning = 0;
|
|
||||||
+ g->gcstp = GCSTPUSR; /* stopeed by the user */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LUA_GCRESTART: {
|
|
||||||
luaE_setdebt(g, 0);
|
|
||||||
- g->gcrunning = 1;
|
|
||||||
+ g->gcstp = 0; /* (GCSTPGC must be already zero here) */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LUA_GCCOLLECT: {
|
|
||||||
@@ -1166,8 +1167,8 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
|
|
||||||
case LUA_GCSTEP: {
|
|
||||||
int data = va_arg(argp, int);
|
|
||||||
l_mem debt = 1; /* =1 to signal that it did an actual step */
|
|
||||||
- lu_byte oldrunning = g->gcrunning;
|
|
||||||
- g->gcrunning = 1; /* allow GC to run */
|
|
||||||
+ lu_byte oldstp = g->gcstp;
|
|
||||||
+ g->gcstp = 0; /* allow GC to run (GCSTPGC must be zero here) */
|
|
||||||
if (data == 0) {
|
|
||||||
luaE_setdebt(g, 0); /* do a basic step */
|
|
||||||
luaC_step(L);
|
|
||||||
@@ -1177,7 +1178,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
|
|
||||||
luaE_setdebt(g, debt);
|
|
||||||
luaC_checkGC(L);
|
|
||||||
}
|
|
||||||
- g->gcrunning = oldrunning; /* restore previous state */
|
|
||||||
+ g->gcstp = oldstp; /* restore previous state */
|
|
||||||
if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */
|
|
||||||
res = 1; /* signal it */
|
|
||||||
break;
|
|
||||||
@@ -1195,7 +1196,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LUA_GCISRUNNING: {
|
|
||||||
- res = g->gcrunning;
|
|
||||||
+ res = gcrunning(g);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LUA_GCGEN: {
|
|
||||||
diff --git a/lbaselib.c b/lbaselib.c
|
|
||||||
index 912c4cc63..1d60c9ded 100644
|
|
||||||
--- a/src/lbaselib.c
|
|
||||||
+++ b/src/lbaselib.c
|
|
||||||
@@ -182,12 +182,20 @@ static int luaB_rawset (lua_State *L) {
|
|
||||||
|
|
||||||
|
|
||||||
static int pushmode (lua_State *L, int oldmode) {
|
|
||||||
- lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
|
|
||||||
- : "generational");
|
|
||||||
+ if (oldmode == -1)
|
|
||||||
+ luaL_pushfail(L); /* invalid call to 'lua_gc' */
|
|
||||||
+ else
|
|
||||||
+ lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
|
|
||||||
+ : "generational");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+** check whether call to 'lua_gc' was valid (not inside a finalizer)
|
|
||||||
+*/
|
|
||||||
+#define checkvalres(res) { if (res == -1) break; }
|
|
||||||
+
|
|
||||||
static int luaB_collectgarbage (lua_State *L) {
|
|
||||||
static const char *const opts[] = {"stop", "restart", "collect",
|
|
||||||
"count", "step", "setpause", "setstepmul",
|
|
||||||
@@ -200,12 +208,14 @@ static int luaB_collectgarbage (lua_State *L) {
|
|
||||||
case LUA_GCCOUNT: {
|
|
||||||
int k = lua_gc(L, o);
|
|
||||||
int b = lua_gc(L, LUA_GCCOUNTB);
|
|
||||||
+ checkvalres(k);
|
|
||||||
lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
case LUA_GCSTEP: {
|
|
||||||
int step = (int)luaL_optinteger(L, 2, 0);
|
|
||||||
int res = lua_gc(L, o, step);
|
|
||||||
+ checkvalres(res);
|
|
||||||
lua_pushboolean(L, res);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@@ -213,11 +223,13 @@ static int luaB_collectgarbage (lua_State *L) {
|
|
||||||
case LUA_GCSETSTEPMUL: {
|
|
||||||
int p = (int)luaL_optinteger(L, 2, 0);
|
|
||||||
int previous = lua_gc(L, o, p);
|
|
||||||
+ checkvalres(previous);
|
|
||||||
lua_pushinteger(L, previous);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
case LUA_GCISRUNNING: {
|
|
||||||
int res = lua_gc(L, o);
|
|
||||||
+ checkvalres(res);
|
|
||||||
lua_pushboolean(L, res);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@@ -234,10 +246,13 @@ static int luaB_collectgarbage (lua_State *L) {
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
int res = lua_gc(L, o);
|
|
||||||
+ checkvalres(res);
|
|
||||||
lua_pushinteger(L, res);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ luaL_pushfail(L); /* invalid call (inside a finalizer) */
|
|
||||||
+ return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/lgc.c b/lgc.c
|
|
||||||
index b360eed00..7d0b5e4f7 100644
|
|
||||||
--- a/src/lgc.c
|
|
||||||
+++ b/src/lgc.c
|
|
||||||
@@ -906,16 +906,16 @@ static void GCTM (lua_State *L) {
|
|
||||||
if (!notm(tm)) { /* is there a finalizer? */
|
|
||||||
int status;
|
|
||||||
lu_byte oldah = L->allowhook;
|
|
||||||
- int running = g->gcrunning;
|
|
||||||
+ int oldgcstp = g->gcstp;
|
|
||||||
+ g->gcstp = GCSTPGC; /* avoid GC steps */
|
|
||||||
L->allowhook = 0; /* stop debug hooks during GC metamethod */
|
|
||||||
- g->gcrunning = 0; /* avoid GC steps */
|
|
||||||
setobj2s(L, L->top++, tm); /* push finalizer... */
|
|
||||||
setobj2s(L, L->top++, &v); /* ... and its argument */
|
|
||||||
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
|
|
||||||
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
|
|
||||||
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
|
|
||||||
L->allowhook = oldah; /* restore hooks */
|
|
||||||
- g->gcrunning = running; /* restore state */
|
|
||||||
+ g->gcstp = oldgcstp; /* restore state */
|
|
||||||
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
|
|
||||||
luaE_warnerror(L, "__gc metamethod");
|
|
||||||
L->top--; /* pops error object */
|
|
||||||
@@ -1502,9 +1502,11 @@ static void deletelist (lua_State *L, GCObject *p, GCObject *limit) {
|
|
||||||
*/
|
|
||||||
void luaC_freeallobjects (lua_State *L) {
|
|
||||||
global_State *g = G(L);
|
|
||||||
+ g->gcstp = GCSTPGC;
|
|
||||||
luaC_changemode(L, KGC_INC);
|
|
||||||
separatetobefnz(g, 1); /* separate all objects with finalizers */
|
|
||||||
lua_assert(g->finobj == NULL);
|
|
||||||
+ g->gcstp = 0;
|
|
||||||
callallpendingfinalizers(L);
|
|
||||||
deletelist(L, g->allgc, obj2gco(g->mainthread));
|
|
||||||
deletelist(L, g->finobj, NULL);
|
|
||||||
@@ -1647,6 +1649,7 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
** Performs a basic incremental step. The debt and step size are
|
|
||||||
** converted from bytes to "units of work"; then the function loops
|
|
||||||
@@ -1678,7 +1681,7 @@ static void incstep (lua_State *L, global_State *g) {
|
|
||||||
void luaC_step (lua_State *L) {
|
|
||||||
global_State *g = G(L);
|
|
||||||
lua_assert(!g->gcemergency);
|
|
||||||
- if (g->gcrunning) { /* running? */
|
|
||||||
+ if (gcrunning(g)) { /* running? */
|
|
||||||
if(isdecGCmodegen(g))
|
|
||||||
genstep(L, g);
|
|
||||||
else
|
|
||||||
diff --git a/lgc.h b/lgc.h
|
|
||||||
index 073e2a402..024a4328e 100644
|
|
||||||
--- a/src/lgc.h
|
|
||||||
+++ b/src/lgc.h
|
|
||||||
@@ -148,6 +148,15 @@
|
|
||||||
*/
|
|
||||||
#define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0)
|
|
||||||
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+** Control when GC is running:
|
|
||||||
+*/
|
|
||||||
+#define GCSTPUSR 1 /* bit true when GC stopped by user */
|
|
||||||
+#define GCSTPGC 2 /* bit true when GC stopped by itself */
|
|
||||||
+#define gcrunning(g) ((g)->gcstp == 0)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
** Does one step of collection when debt becomes positive. 'pre'/'pos'
|
|
||||||
** allows some adjustments to be done only when needed. macro
|
|
||||||
diff --git a/lstate.c b/lstate.c
|
|
||||||
index 547a7a014..1ffe1a0f7 100644
|
|
||||||
--- a/src/lstate.c
|
|
||||||
+++ b/src/lstate.c
|
|
||||||
@@ -236,7 +236,7 @@ static void f_luaopen (lua_State *L, void *ud) {
|
|
||||||
luaS_init(L);
|
|
||||||
luaT_init(L);
|
|
||||||
luaX_init(L);
|
|
||||||
- g->gcrunning = 1; /* allow gc */
|
|
||||||
+ g->gcstp = 0; /* allow gc */
|
|
||||||
setnilvalue(&g->nilvalue); /* now state is complete */
|
|
||||||
luai_userstateopen(L);
|
|
||||||
}
|
|
||||||
@@ -373,7 +373,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|
||||||
g->ud_warn = NULL;
|
|
||||||
g->mainthread = L;
|
|
||||||
g->seed = luai_makeseed(L);
|
|
||||||
- g->gcrunning = 0; /* no GC while building state */
|
|
||||||
+ g->gcstp = GCSTPGC; /* no GC while building state */
|
|
||||||
g->strt.size = g->strt.nuse = 0;
|
|
||||||
g->strt.hash = NULL;
|
|
||||||
setnilvalue(&g->l_registry);
|
|
||||||
diff --git a/lstate.h b/lstate.h
|
|
||||||
index 44cf939cb..7886d8914 100644
|
|
||||||
--- a/src/lstate.h
|
|
||||||
+++ b/src/lstate.h
|
|
||||||
@@ -263,7 +263,7 @@ typedef struct global_State {
|
|
||||||
lu_byte gcstopem; /* stops emergency collections */
|
|
||||||
lu_byte genminormul; /* control for minor generational collections */
|
|
||||||
lu_byte genmajormul; /* control for major generational collections */
|
|
||||||
- lu_byte gcrunning; /* true if GC is running */
|
|
||||||
+ lu_byte gcstp; /* control whether GC is running */
|
|
||||||
lu_byte gcemergency; /* true if this is an emergency collection */
|
|
||||||
lu_byte gcpause; /* size of pause between successive GCs */
|
|
||||||
lu_byte gcstepmul; /* GC "speed" */
|
|
||||||
From 597a53bbc681089d85b082b46c2e2428dec43b86 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
|
|
||||||
Date: Wed, 22 Dec 2021 09:00:52 -0300
|
|
||||||
Subject: [PATCH] Bug: finalizer calling exit can corrupt finalization order
|
|
||||||
|
|
||||||
'os.exit' can call lua_close again, separating new finalizers
|
|
||||||
created after all previous finalizers were already separated.
|
|
||||||
---
|
|
||||||
lgc.c | 10 +++++-----
|
|
||||||
lgc.h | 1 +
|
|
||||||
testes/main.lua | 28 ++++++++++++++++++++++++++++
|
|
||||||
3 files changed, 34 insertions(+), 5 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/lgc.c b/lgc.c
|
|
||||||
index d3f5b5b7b..42a73d813 100644
|
|
||||||
--- a/src/lgc.c
|
|
||||||
+++ b/src/lgc.c
|
|
||||||
@@ -907,7 +907,7 @@ static void GCTM (lua_State *L) {
|
|
||||||
int status;
|
|
||||||
lu_byte oldah = L->allowhook;
|
|
||||||
int oldgcstp = g->gcstp;
|
|
||||||
- g->gcstp = GCSTPGC; /* avoid GC steps */
|
|
||||||
+ g->gcstp |= GCSTPGC; /* avoid GC steps */
|
|
||||||
L->allowhook = 0; /* stop debug hooks during GC metamethod */
|
|
||||||
setobj2s(L, L->top++, tm); /* push finalizer... */
|
|
||||||
setobj2s(L, L->top++, &v); /* ... and its argument */
|
|
||||||
@@ -1011,7 +1011,8 @@ static void correctpointers (global_State *g, GCObject *o) {
|
|
||||||
void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
|
|
||||||
global_State *g = G(L);
|
|
||||||
if (tofinalize(o) || /* obj. is already marked... */
|
|
||||||
- gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */
|
|
||||||
+ gfasttm(g, mt, TM_GC) == NULL || /* or has no finalizer... */
|
|
||||||
+ (g->gcstp & GCSTPCLS)) /* or closing state? */
|
|
||||||
return; /* nothing to be done */
|
|
||||||
else { /* move 'o' to 'finobj' list */
|
|
||||||
GCObject **p;
|
|
||||||
@@ -1502,14 +1503,13 @@ static void deletelist (lua_State *L, GCObject *p, GCObject *limit) {
|
|
||||||
*/
|
|
||||||
void luaC_freeallobjects (lua_State *L) {
|
|
||||||
global_State *g = G(L);
|
|
||||||
- g->gcstp = GCSTPGC;
|
|
||||||
+ g->gcstp = GCSTPCLS; /* no extra finalizers after here */
|
|
||||||
luaC_changemode(L, KGC_INC);
|
|
||||||
separatetobefnz(g, 1); /* separate all objects with finalizers */
|
|
||||||
lua_assert(g->finobj == NULL);
|
|
||||||
- g->gcstp = 0;
|
|
||||||
callallpendingfinalizers(L);
|
|
||||||
deletelist(L, g->allgc, obj2gco(g->mainthread));
|
|
||||||
- deletelist(L, g->finobj, NULL);
|
|
||||||
+ lua_assert(g->finobj == NULL); /* no new finalizers */
|
|
||||||
deletelist(L, g->fixedgc, NULL); /* collect fixed objects */
|
|
||||||
lua_assert(g->strt.nuse == 0);
|
|
||||||
}
|
|
||||||
diff --git a/lgc.h b/lgc.h
|
|
||||||
index 024a4328e..4a125634b 100644
|
|
||||||
--- a/src/lgc.h
|
|
||||||
+++ b/src/lgc.h
|
|
||||||
@@ -154,6 +154,7 @@
|
|
||||||
*/
|
|
||||||
#define GCSTPUSR 1 /* bit true when GC stopped by user */
|
|
||||||
#define GCSTPGC 2 /* bit true when GC stopped by itself */
|
|
||||||
+#define GCSTPCLS 4 /* bit true when closing Lua state */
|
|
||||||
#define gcrunning(g) ((g)->gcstp == 0)
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user