Tarantool development patches archive
 help / color / mirror / Atom feed
From: Sergey Kaplun via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: Sergey Bronnikov <sergeyb@tarantool.org>
Cc: tarantool-patches@dev.tarantool.org
Subject: [Tarantool-patches] [PATCH luajit 2/2] Different fix for partial snapshot restore due to stack overflow.
Date: Tue, 10 Jun 2025 13:28:52 +0300	[thread overview]
Message-ID: <1152e27d618a4717c0f48cb77d085434eb183b18.1749550966.git.skaplun@tarantool.org> (raw)
In-Reply-To: <cover.1749550966.git.skaplun@tarantool.org>

From: Mike Pall <mike>

Reported by Junlong Li. Fixed by Peter Cawley.

(cherry picked from commit 86e7123bb1782a5f200ba5e83b8c4f3fbad4f7bc)

This patch is a follow-up to the previous commit, which leads to a dirty
read of the pseudo-valid PC set for the cframe on snapshot restoration.
To avoid these dirty reads, this patch sets the PC to the outer frame
as well before possible error throwing.

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

Part of tarantool/tarantool#11278
---
 src/lj_snap.c                                 |  3 +-
 src/lj_trace.c                                |  4 +-
 ...-1196-stack-overflow-snap-restore.test.lua | 65 +++++++++++++++++++
 3 files changed, 68 insertions(+), 4 deletions(-)
 create mode 100644 test/tarantool-tests/lj-1196-stack-overflow-snap-restore.test.lua

diff --git a/src/lj_snap.c b/src/lj_snap.c
index 8d7bd868..4cfae579 100644
--- a/src/lj_snap.c
+++ b/src/lj_snap.c
@@ -955,7 +955,8 @@ const BCIns *lj_snap_restore(jit_State *J, void *exptr)
   lua_State *L = J->L;
 
   /* Set interpreter PC to the next PC to get correct error messages. */
-  setcframe_pc(cframe_raw(L->cframe), pc+1);
+  setcframe_pc(L->cframe, pc+1);
+  setcframe_pc(cframe_raw(cframe_prev(L->cframe)), pc);
 
   /* Make sure the stack is big enough for the slots from the snapshot. */
   if (LJ_UNLIKELY(L->base + snap->topslot >= tvref(L->maxstack))) {
diff --git a/src/lj_trace.c b/src/lj_trace.c
index 8a18d3cf..0d1d233a 100644
--- a/src/lj_trace.c
+++ b/src/lj_trace.c
@@ -909,10 +909,8 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr)
   exd.J = J;
   exd.exptr = exptr;
   errcode = lj_vm_cpcall(L, NULL, &exd, trace_exit_cp);
-  if (errcode) {
-    setcframe_pc(cframe_raw(L->cframe), L);  /* Point to any valid memory. */
+  if (errcode)
     return -errcode;  /* Return negated error code. */
-  }
 
   if (exitcode) copyTV(L, L->top++, &exiterr);  /* Anchor the error object. */
 
diff --git a/test/tarantool-tests/lj-1196-stack-overflow-snap-restore.test.lua b/test/tarantool-tests/lj-1196-stack-overflow-snap-restore.test.lua
new file mode 100644
index 00000000..942d1f82
--- /dev/null
+++ b/test/tarantool-tests/lj-1196-stack-overflow-snap-restore.test.lua
@@ -0,0 +1,65 @@
+local tap = require('tap')
+
+-- Test file to demonstrate LuaJIT dirty reads after stack
+-- overflow during restoration from the snapshot.
+-- The test fails before the patch under Valgrind.
+--
+-- luacheck: push no max_comment_line_length
+--
+-- See also: https://github.com/LuaJIT/LuaJIT/issues/1196,
+-- https://www.freelists.org/post/luajit/Invalid-read-found-by-valgrind.
+--
+-- luacheck: pop
+
+local test = tap.test('lj-1196-stack-overflow-snap-restore')
+
+test:plan(4)
+
+-- XXX: This file has the same tests as the
+-- <test/LuaJIT-tests/lang/stackov.lua>, but without disabling the
+-- compilation for the given functions. Hence, the check here is
+-- less strict -- we just check that there are no dirty reads,
+-- uninitialized memory access, etc.
+
+local function recursive_f_noarg()
+  recursive_f_noarg()
+end
+
+local function recursive_one_arg(argument)
+  recursive_one_arg(argument)
+end
+
+local function recursive_f_vararg(...)
+  recursive_f_vararg(1, ...)
+end
+
+local function recursive_f_vararg_tail(...)
+  return recursive_f_vararg_tail(1, ...)
+end
+
+-- Use `coroutine.wrap()`, for independent stack sizes.
+-- The invalid read is done by the error handler
+-- `debug.traceback()`, since it observes the pseudo PC (`L`) and
+-- reads the memory by `L - 4` address before the patch.
+
+coroutine.wrap(function()
+  local status = xpcall(recursive_f_noarg, debug.traceback)
+  test:ok(not status, 'correct status, recursive no arguments')
+end)()
+
+coroutine.wrap(function()
+  local status = xpcall(recursive_one_arg, debug.traceback, 1)
+  test:ok(not status, 'correct status, recursive one argument')
+end)()
+
+coroutine.wrap(function()
+  local status = xpcall(recursive_f_vararg, debug.traceback, 1)
+  test:ok(not status, 'correct status, recursive vararg')
+end)()
+
+coroutine.wrap(function()
+  local status = xpcall(recursive_f_vararg_tail, debug.traceback, 1)
+  test:ok(not status, 'correct status, recursive vararg tail')
+end)()
+
+test:done(true)
-- 
2.49.0


  parent reply	other threads:[~2025-06-10 10:29 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-10 10:28 [Tarantool-patches] [PATCH luajit 0/2] Snapshot restore with " Sergey Kaplun via Tarantool-patches
2025-06-10 10:28 ` [Tarantool-patches] [PATCH luajit 1/2] Handle partial snapshot restore due to " Sergey Kaplun via Tarantool-patches
2025-06-10 15:29   ` Sergey Bronnikov via Tarantool-patches
2025-06-10 16:03     ` Sergey Kaplun via Tarantool-patches
2025-06-10 10:28 ` Sergey Kaplun via Tarantool-patches [this message]
2025-06-10 16:15   ` [Tarantool-patches] [PATCH luajit 2/2] Different fix for " Sergey Bronnikov via Tarantool-patches
2025-06-10 16:22     ` Sergey Kaplun via Tarantool-patches
2025-06-11  9:36       ` Sergey Bronnikov via Tarantool-patches

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1152e27d618a4717c0f48cb77d085434eb183b18.1749550966.git.skaplun@tarantool.org \
    --to=tarantool-patches@dev.tarantool.org \
    --cc=sergeyb@tarantool.org \
    --cc=skaplun@tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH luajit 2/2] Different fix for partial snapshot restore due to stack overflow.' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

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