Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH luajit v2] Fix frame traversal for __gc handler frames.
@ 2021-11-19 16:41 Sergey Kaplun via Tarantool-patches
  2021-11-23 12:57 ` Igor Munkin via Tarantool-patches
  2021-11-23 22:00 ` Igor Munkin via Tarantool-patches
  0 siblings, 2 replies; 3+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-11-19 16:41 UTC (permalink / raw)
  To: Sergey Ostanevich, Igor Munkin; +Cc: tarantool-patches

From: Mike Pall <mike>

Reported by Changochen.

(cherry picked from 53f82e6e2e858a0a62fd1a2ff47e9866693382e6)

A cframe unwinding is missed for a C protected frame during a search for
an error function to handle a runtime error. It leads to undefined
behaviour or crash, when raising a runtime error on stack with the CP
frame before an error function handler (for example, an error in __gc
handler).

This patch adds missing unwinding for CP frame.

Sergey Kaplun:
* added the description and the test for the problem
---

LuaJIT issue: https://github.com/LuaJIT/LuaJIT/issues/601
Branch: https://github.com/tarantool/luajit/tree/skaplun/gh-noticket-fix-gc-finderrfunc
Tarantool branch: https://github.com/tarantool/tarantool/tree/skaplun/gh-noticket-fix-gc-finderrfunc

Changes in v2:
* Create CP and C stack manually in LuaC

 src/lj_err.c                                  |  1 +
 test/tarantool-tests/CMakeLists.txt           |  1 +
 .../lj-601-fix-gc-finderrfunc.test.lua        | 35 ++++++++++++
 .../lj-601-fix-gc-finderrfunc/CMakeLists.txt  |  1 +
 .../lj-601-fix-gc-finderrfunc/mixcframe.c     | 55 +++++++++++++++++++
 5 files changed, 93 insertions(+)
 create mode 100644 test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua
 create mode 100644 test/tarantool-tests/lj-601-fix-gc-finderrfunc/CMakeLists.txt
 create mode 100644 test/tarantool-tests/lj-601-fix-gc-finderrfunc/mixcframe.c

diff --git a/src/lj_err.c b/src/lj_err.c
index b6be357e..b520b3d3 100644
--- a/src/lj_err.c
+++ b/src/lj_err.c
@@ -585,6 +585,7 @@ static ptrdiff_t finderrfunc(lua_State *L)
       if (cframe_canyield(cf)) return 0;
       if (cframe_errfunc(cf) >= 0)
 	return cframe_errfunc(cf);
+      cf = cframe_prev(cf);
       frame = frame_prevd(frame);
       break;
     case FRAME_PCALL:
diff --git a/test/tarantool-tests/CMakeLists.txt b/test/tarantool-tests/CMakeLists.txt
index a872fa5e..b21500a0 100644
--- a/test/tarantool-tests/CMakeLists.txt
+++ b/test/tarantool-tests/CMakeLists.txt
@@ -60,6 +60,7 @@ add_subdirectory(gh-4427-ffi-sandwich)
 add_subdirectory(gh-6098-fix-side-exit-patching-on-arm64)
 add_subdirectory(gh-6189-cur_L)
 add_subdirectory(lj-49-bad-lightuserdata)
+add_subdirectory(lj-601-fix-gc-finderrfunc)
 add_subdirectory(lj-flush-on-trace)
 add_subdirectory(misclib-getmetrics-capi)
 
diff --git a/test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua b/test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua
new file mode 100644
index 00000000..d4c44489
--- /dev/null
+++ b/test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua
@@ -0,0 +1,35 @@
+local tap = require('tap')
+
+local mixcframe = require('libmixcframe')
+local test = tap.test('lj-601-fix-gc-finderrfunc')
+test:plan(1)
+
+-- Test file to demonstrate LuaJIT incorrect behaviour, when
+-- throwing error in __gc finalizer.
+-- See also, https://github.com/LuaJIT/LuaJIT/issues/601.
+
+-- Stop GC for now.
+collectgarbage('stop')
+
+local a = newproxy(true)
+getmetatable(a).__gc = function()
+  -- Function to raise error via `lj_err_run()` inside __gc.
+  error('raise error in __gc')
+end
+-- luacheck: no unused
+a = nil
+
+-- We need to get the following Lua stack format when raise an
+-- error:
+-- + L->stack
+-- | ...
+-- | CP -- any C protected frame.
+-- | ...[L/LP/V]...
+-- | C -- any C frame.
+-- | ...[L/LP/V]...
+-- | CP (with inherited errfunc) -- __gc frame.
+-- V
+-- Enter in the C to call CP func. Call `lua_gc()` inside.
+test:ok(mixcframe.test_handle_err(), 'error in __gc is successfully handled')
+
+os.exit(test:check() and 0 or 1)
diff --git a/test/tarantool-tests/lj-601-fix-gc-finderrfunc/CMakeLists.txt b/test/tarantool-tests/lj-601-fix-gc-finderrfunc/CMakeLists.txt
new file mode 100644
index 00000000..3fed6105
--- /dev/null
+++ b/test/tarantool-tests/lj-601-fix-gc-finderrfunc/CMakeLists.txt
@@ -0,0 +1 @@
+BuildTestCLib(libmixcframe mixcframe.c)
diff --git a/test/tarantool-tests/lj-601-fix-gc-finderrfunc/mixcframe.c b/test/tarantool-tests/lj-601-fix-gc-finderrfunc/mixcframe.c
new file mode 100644
index 00000000..730e30ae
--- /dev/null
+++ b/test/tarantool-tests/lj-601-fix-gc-finderrfunc/mixcframe.c
@@ -0,0 +1,55 @@
+#include <lua.h>
+#include <lauxlib.h>
+#include <string.h>
+
+static void spoil_cframe(void)
+{
+	/*
+	 * We need to map CFRAME_SIZE + lua_call frame size.
+	 * 1 Kb is totally enough with overhead.
+	 */
+	char a[1024];
+	/*
+	 * XXX: Need a value >= 0 on C stack to be interpreted as
+	 * its own errfunc, not inherited. Just put the big
+	 * address (0x7f7f7f7f).
+	 */
+	memset(a, 0x7f, sizeof(a));
+}
+
+static int cframe_func(lua_State *L)
+{
+	lua_gc(L, LUA_GCCOLLECT, 0);
+	return 0;
+}
+
+static int call_cframe_func(lua_State *L)
+{
+	lua_pushcfunction(L, cframe_func);
+	spoil_cframe();
+	lua_call(L, 0, 0);
+	return 0;
+}
+
+static int test_handle_err(lua_State *L)
+{
+	/*
+	 * Not interested in the result, just want to be sure that
+	 * unwinding in `finderrfunc()` works correctly.
+	 */
+	lua_cpcall(L, call_cframe_func, NULL);
+	lua_pushboolean(L, 1);
+	return 1;
+}
+
+static const struct luaL_Reg mixcframe[] = {
+	{"test_handle_err", test_handle_err},
+	{NULL, NULL}
+};
+
+LUA_API int luaopen_libmixcframe(lua_State *L)
+{
+	luaL_register(L, "mixcframe", mixcframe);
+	return 1;
+}
+
-- 
2.31.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Tarantool-patches] [PATCH luajit v2] Fix frame traversal for __gc handler frames.
  2021-11-19 16:41 [Tarantool-patches] [PATCH luajit v2] Fix frame traversal for __gc handler frames Sergey Kaplun via Tarantool-patches
@ 2021-11-23 12:57 ` Igor Munkin via Tarantool-patches
  2021-11-23 22:00 ` Igor Munkin via Tarantool-patches
  1 sibling, 0 replies; 3+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-11-23 12:57 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

Thanks for the fixes! LGTM, with a tiny nit.

On 19.11.21, Sergey Kaplun wrote:
> From: Mike Pall <mike>
> 
> Reported by Changochen.
> 
> (cherry picked from 53f82e6e2e858a0a62fd1a2ff47e9866693382e6)
> 
> A cframe unwinding is missed for a C protected frame during a search for
> an error function to handle a runtime error. It leads to undefined
> behaviour or crash, when raising a runtime error on stack with the CP
> frame before an error function handler (for example, an error in __gc
> handler).
> 
> This patch adds missing unwinding for CP frame.
> 
> Sergey Kaplun:
> * added the description and the test for the problem
> ---
> 
> LuaJIT issue: https://github.com/LuaJIT/LuaJIT/issues/601
> Branch: https://github.com/tarantool/luajit/tree/skaplun/gh-noticket-fix-gc-finderrfunc
> Tarantool branch: https://github.com/tarantool/tarantool/tree/skaplun/gh-noticket-fix-gc-finderrfunc
> 
> Changes in v2:
> * Create CP and C stack manually in LuaC
> 
>  src/lj_err.c                                  |  1 +
>  test/tarantool-tests/CMakeLists.txt           |  1 +
>  .../lj-601-fix-gc-finderrfunc.test.lua        | 35 ++++++++++++
>  .../lj-601-fix-gc-finderrfunc/CMakeLists.txt  |  1 +
>  .../lj-601-fix-gc-finderrfunc/mixcframe.c     | 55 +++++++++++++++++++
>  5 files changed, 93 insertions(+)
>  create mode 100644 test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua
>  create mode 100644 test/tarantool-tests/lj-601-fix-gc-finderrfunc/CMakeLists.txt
>  create mode 100644 test/tarantool-tests/lj-601-fix-gc-finderrfunc/mixcframe.c
> 

<snipped>

> diff --git a/test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua b/test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua
> new file mode 100644
> index 00000000..d4c44489
> --- /dev/null
> +++ b/test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua
> @@ -0,0 +1,35 @@

<snipped>

> +local a = newproxy(true)
> +getmetatable(a).__gc = function()
> +  -- Function to raise error via `lj_err_run()` inside __gc.
> +  error('raise error in __gc')
> +end
> +-- luacheck: no unused
> +a = nil
> +
> +-- We need to get the following Lua stack format when raise an
> +-- error:
> +-- + L->stack
> +-- | ...
> +-- | CP -- any C protected frame.
> +-- | ...[L/LP/V]...
> +-- | C -- any C frame.
> +-- | ...[L/LP/V]...
> +-- | CP (with inherited errfunc) -- __gc frame.
> +-- V
> +-- Enter in the C to call CP func. Call `lua_gc()` inside.

Minor: I'd adjust this comment the following way:
| -- Enter in the C land to call a function in a protected C frame
| -- (CP). Spoil host stack (and ergo cframe area) and later call
| -- Lua C function, triggering full GC cycle in a non-protected
| -- frame. As a result, error is raised in __gc metamethod above.

Fixed, squashed, force-pushed to the branch. Diff is below:

================================================================================

diff --git a/test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua b/test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua
index d4c44489..2122c7a0 100644
--- a/test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua
+++ b/test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua
@@ -29,7 +29,10 @@ a = nil
 -- | ...[L/LP/V]...
 -- | CP (with inherited errfunc) -- __gc frame.
 -- V
--- Enter in the C to call CP func. Call `lua_gc()` inside.
+-- Enter in the C land to call a function in a protected C frame
+-- (CP). Spoil host stack (and ergo cframe area) and later call
+-- Lua C function, triggering full GC cycle in a non-protected
+-- frame. As a result, error is raised in __gc metamethod above.
 test:ok(mixcframe.test_handle_err(), 'error in __gc is successfully handled')
 
 os.exit(test:check() and 0 or 1)

================================================================================

> +test:ok(mixcframe.test_handle_err(), 'error in __gc is successfully handled')
> +
> +os.exit(test:check() and 0 or 1)

<snipped>

> -- 
> 2.31.0
> 

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Tarantool-patches] [PATCH luajit v2] Fix frame traversal for __gc handler frames.
  2021-11-19 16:41 [Tarantool-patches] [PATCH luajit v2] Fix frame traversal for __gc handler frames Sergey Kaplun via Tarantool-patches
  2021-11-23 12:57 ` Igor Munkin via Tarantool-patches
@ 2021-11-23 22:00 ` Igor Munkin via Tarantool-patches
  1 sibling, 0 replies; 3+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-11-23 22:00 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

I've checked the patch into all long-term branches in tarantool/luajit
and bumped a new version in 1.10, 2.8 and master.

On 19.11.21, Sergey Kaplun wrote:
> From: Mike Pall <mike>
> 
> Reported by Changochen.
> 
> (cherry picked from 53f82e6e2e858a0a62fd1a2ff47e9866693382e6)
> 
> A cframe unwinding is missed for a C protected frame during a search for
> an error function to handle a runtime error. It leads to undefined
> behaviour or crash, when raising a runtime error on stack with the CP
> frame before an error function handler (for example, an error in __gc
> handler).
> 
> This patch adds missing unwinding for CP frame.
> 
> Sergey Kaplun:
> * added the description and the test for the problem
> ---
> 
> LuaJIT issue: https://github.com/LuaJIT/LuaJIT/issues/601
> Branch: https://github.com/tarantool/luajit/tree/skaplun/gh-noticket-fix-gc-finderrfunc
> Tarantool branch: https://github.com/tarantool/tarantool/tree/skaplun/gh-noticket-fix-gc-finderrfunc
> 
> Changes in v2:
> * Create CP and C stack manually in LuaC
> 
>  src/lj_err.c                                  |  1 +
>  test/tarantool-tests/CMakeLists.txt           |  1 +
>  .../lj-601-fix-gc-finderrfunc.test.lua        | 35 ++++++++++++
>  .../lj-601-fix-gc-finderrfunc/CMakeLists.txt  |  1 +
>  .../lj-601-fix-gc-finderrfunc/mixcframe.c     | 55 +++++++++++++++++++
>  5 files changed, 93 insertions(+)
>  create mode 100644 test/tarantool-tests/lj-601-fix-gc-finderrfunc.test.lua
>  create mode 100644 test/tarantool-tests/lj-601-fix-gc-finderrfunc/CMakeLists.txt
>  create mode 100644 test/tarantool-tests/lj-601-fix-gc-finderrfunc/mixcframe.c
> 

<snipped>

> -- 
> 2.31.0
> 

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-11-23 22:01 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-19 16:41 [Tarantool-patches] [PATCH luajit v2] Fix frame traversal for __gc handler frames Sergey Kaplun via Tarantool-patches
2021-11-23 12:57 ` Igor Munkin via Tarantool-patches
2021-11-23 22:00 ` Igor Munkin via Tarantool-patches

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox