From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 0D8F46E459; Fri, 19 Nov 2021 19:43:52 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 0D8F46E459 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1637340232; bh=tuFOGLt3Cz16a/fHKYUn5mpwjo+d+15G6eTVVS+DEB4=; h=To:Date:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=H4IXmP/kpAaIhrYQR/306sjWqqeAT/FsZGEM7tMu/3orQhRGCWBpZKxZ060D+b/Wj yh383TJysshw/NUapJarPubxSTphcYRNTX3E9sXu64lGkzZQyEbtfaKxCDzOuj6C5Q eIFQiJYEYZ9iGDEYiQadCCIF2SuOGBy22x/HrVgc= Received: from smtp3.mail.ru (smtp3.mail.ru [94.100.179.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id DA0FC6E459 for ; Fri, 19 Nov 2021 19:43:49 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org DA0FC6E459 Received: by smtp3.mail.ru with esmtpa (envelope-from ) id 1mo6zM-0004EO-Rt; Fri, 19 Nov 2021 19:43:49 +0300 To: Sergey Ostanevich , Igor Munkin Date: Fri, 19 Nov 2021 19:41:57 +0300 Message-Id: <20211119164157.18344-1-skaplun@tarantool.org> X-Mailer: git-send-email 2.31.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-7564579A: EEAE043A70213CC8 X-77F55803: 4F1203BC0FB41BD9731B3922EC0639796B771AC0C92A63AE326C66FF2261167500894C459B0CD1B9DE99FFBDBC3A7C40E8F4CA60C705BC9119BB2CB5BD254DA66F8F9941A8C2109B X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7EED5D2FAB4CEB1EDEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F79006373682D752F1DB00E08638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D83B5ECB59CA1107C1B9D7E579F8FE0725117882F4460429724CE54428C33FAD305F5C1EE8F4F765FCAA867293B0326636D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8BAA867293B0326636D2E47CDBA5A96583BA9C0B312567BB231DD303D21008E29813377AFFFEAFD269A417C69337E82CC2E827F84554CEF50127C277FBC8AE2E8BA83251EDC214901ED5E8D9A59859A8B66F6A3E018CF4DC80089D37D7C0E48F6C5571747095F342E88FB05168BE4CE3AF X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975C68CB598F2FAAB17E3D4C6DF9BA4032C296A35728860D7FC89C2B6934AE262D3EE7EAB7254005DCED579D4A3F7131653F9510FB958DCE06DB6ED91DBE5ABE359ADBCB5631A0A9D21F2272C4C079A4C8AD93EDB24507CE13387DFF0A840B692CF8 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D34DA1FE609583D493C70F547400C2B64B8F818B6AB06F3EAA0640E8947E6F7678A19F071C72C91554A1D7E09C32AA3244CFAE6E01BFD570EB278DA423039217333BBA718C7E6A9E042927AC6DF5659F194 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojbL9S8ysBdXjnnSaqFPpXC1qyk/VVEfZB X-Mailru-Sender: 3B9A0136629DC91206CBC582EFEF4CB468276C5659805895C6D90D497A3689ACD47AA7F46CD25F9CF2400F607609286E924004A7DEC283833C7120B22964430C52B393F8C72A41A89437F6177E88F7363CDA0F3B3F5B9367 X-Mras: Ok Subject: [Tarantool-patches] [PATCH luajit v2] Fix frame traversal for __gc handler frames. X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Sergey Kaplun via Tarantool-patches Reply-To: Sergey Kaplun Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" From: Mike Pall 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 +#include +#include + +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