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 634F713D8EA0; Tue, 10 Jun 2025 13:29:19 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 634F713D8EA0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1749551359; bh=6wfhK3MBFo/YGAhOEw1HnT/l/m99NCEjQaQ1kB3UM68=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=eTbsVt5CMJkBstv07iY6o+XDvzb1m/VH0BM/HN8VFzeUuFdAW1vds5CaxNX3qTlix tOEgNaEJdm6q+fLzHDXf+vf79tu8B5KVV7vgc1i5d3O2OpFx2m/aoywMCGqAsHc+6h h0Ep90puPYPhcMoSQdJlaOayLvV2aOyHr/Gciczo= Received: from send240.i.mail.ru (send240.i.mail.ru [95.163.59.79]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 0A47213D8E94 for ; Tue, 10 Jun 2025 13:28:49 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 0A47213D8E94 Received: by exim-smtp-85b97957d7-j7lvw with esmtpa (envelope-from ) id 1uOwDo-00000000RhL-0346; Tue, 10 Jun 2025 13:28:48 +0300 To: Sergey Bronnikov Date: Tue, 10 Jun 2025 13:28:51 +0300 Message-ID: <7644f7c143f38426718039d1fefb6626335bf10b.1749550966.git.skaplun@tarantool.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Mailru-Src: smtp X-4EC0790: 10 X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD909B82214CC98891720AEB103E7D02E8C3F1FE541820D088900894C459B0CD1B99DC77D1558A7CF1503AAE3001806DF1010CFFA24ED84304D23E79FF8DC8A0139F8D9167951636718 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE76D34FAA3D8B31588C2099A533E45F2D0395957E7521B51C2CFCAF695D4D8E9FCEA1F7E6F0F101C6759CC434672EE6371C2A783ECEC0211ADC4224003CC836476D5A39DEEDB180909611E41BBFE2FEB2B8F8357C91174DDD4D2D00DDEF66CDA8405FFBF556E75A21A118E2B3F3E7DB9259FA2833FD35BB23D9E625A9149C048EE26055571C92BF10F618001F51B5FD3F9D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8B1F8789D36234D406A471835C12D1D977C4224003CC8364762BB6847A3DEAEFB0F43C7A68FF6260569E8FC8737B5C2249EC8D19AE6D49635B68655334FD4449CB9ECD01F8117BC8BEAAAE862A0553A39223F8577A6DFFEA7C3B6C7E47A292E8D043847C11F186F3C59DAA53EE0834AAEE X-C1DE0DAB: 0D63561A33F958A587D37233988392645002B1117B3ED696E9FF822943F3DDB77E0012C66AE17B00823CB91A9FED034534781492E4B8EEAD3B90412627F530F9A71A35648BE338CE9510FB958DCE06DB58C12E6D310A6D535E2CDB7BC110771C X-C8649E89: 1C3962B70DF3F0ADBF74143AD284FC7177DD89D51EBB7742424CF958EAFF5D571004E42C50DC4CA955A7F0CF078B5EC49A30900B95165D34728AF701C68E45395C885D1A3AE8E92086817605A917193BD45142CFB1305EC8F93E584256E1E8341D7E09C32AA3244C795486250B1F9D3A77DD89D51EBB77422D128D992745FE52EA455F16B58544A2557BDE0DD54B3590A5AE236DF995FB59829709634694AABAED6A17656DB59BCAD427812AF56FC65B X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu53w8ahmwBjZKM/YPHZyZHvz5uv+WouB9+ObcCpyrx6l7KImUglyhkEat/+ysWwi0gdhEs0JGjl6ggRWTy1haxBpVdbIX1nthFXMZebaIdHP2ghjoIc/363UZI6Kf1ptIMVSykAyseJQ6/onSdtviYK6A= X-DA7885C5: 2B57C3563621C92AF255D290C0D534F9A75D337CA83CB6E29AB2DF6E6CB8943DF28F5C1C3018F06F5B1A4C17EAA7BC4BEF2421ABFA55128DAF83EF9164C44C7E X-Mailru-Sender: 689FA8AB762F7393FE9E42A757851DB6D6BCDF589319629ADD6B56B1E5A19E08FA96AF5166E4012CE49D44BB4BD9522A059A1ED8796F048DB274557F927329BE89D5A3BC2B10C37545BD1C3CC395C826B4A721A3011E896F X-Mras: Ok Subject: [Tarantool-patches] [PATCH luajit 1/2] Handle partial snapshot restore due to stack overflow. 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 pwnhacker0x18. Fixed by Peter Cawley. (cherry picked from commit 811c5322c8ab6bdbb6784cd43aa57041a1cc9360) `lj_snap_restore()` restores the PC for the inner cframe, but not the outer (before the protected call to the `trace_exit_cp()`). If the stack overflow is observed during the further snapshot restoration, it doesn't fix up the outer cframe's PC. After that, in the following error rethrowing from the right C frame, in case of error handler set, the stack overflow error may be raised again, and with an incorrect value of the PC for that frame, it leads to the crash in the `debug_framepc()`. This patch prevents it by inserting the special pseudo-valid value `L`. Unfortunately, this leads to the uninitialized reads by the `debug_framepc()` (by the address `L - 4`), if the error handler observes the resulted PC. This will be fixed in the next patch. Sergey Kaplun: * added the description and the test for the problem Part of tarantool/tarantool#11278 --- src/lj_trace.c | 4 +- .../lj-1196-partial-snap-restore.test.lua | 51 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 test/tarantool-tests/lj-1196-partial-snap-restore.test.lua diff --git a/src/lj_trace.c b/src/lj_trace.c index 0d1d233a..8a18d3cf 100644 --- a/src/lj_trace.c +++ b/src/lj_trace.c @@ -909,8 +909,10 @@ 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) + if (errcode) { + setcframe_pc(cframe_raw(L->cframe), L); /* Point to any valid memory. */ 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-partial-snap-restore.test.lua b/test/tarantool-tests/lj-1196-partial-snap-restore.test.lua new file mode 100644 index 00000000..8ee8f673 --- /dev/null +++ b/test/tarantool-tests/lj-1196-partial-snap-restore.test.lua @@ -0,0 +1,51 @@ +local tap = require('tap') + +-- Test file to demonstrate LuaJIT crash during snapshot restore +-- in case of the stack overflow. +-- See also: https://github.com/LuaJIT/LuaJIT/issues/1196. + +local test = tap.test('lj-1196-partial-snap-restore') + +test:plan(1) + +-- XXX: The reproducer below uses several stack slot offsets to +-- make sure that stack overflow happens during the snapshot +-- restoration and not the call to the stitched function and +-- return its result. The actual stack size should be less than +-- `LJ_STACK_MAXEX`, but with requested space it should be greater +-- than `LJ_STACK_MAX`, see for the details. +-- Before that, the `lj_snap_restore()` restores the `pc` for the +-- inner cframe, but not the outer (before the protected call to +-- the `trace_exit_cp()`). Thus, the further error rethrowing from +-- the right C frame leads to the crash before the patch. + +-- XXX: Simplify the `jit.dump()` output. +local tonumber = tonumber + +-- This function starts the first trace. +local function recursive_f() + -- Function with the single result to cause the trace stitching. + tonumber('') + -- Prereserved stack space before the call. + -- luacheck: no unused + local _, _, _, _, _, _, _, _, _, _, _ + -- Link from the stitched trace to the parent one. + recursive_f() + -- Additional stack required for the snapshot restoration. + -- luacheck: no unused + local _, _, _ +end + +-- Use coroutine wrap for the fixed stack size at the start. +coroutine.wrap(function() + -- XXX: Special stack slot offset. + -- luacheck: no unused + local _, _, _, _, _, _, _, _, _, _ + -- The error is observed only if we have the error handler set, + -- since we try to resize stack for its call. + xpcall(recursive_f, function() end) +end)() + +test:ok(true, 'no crash during snapshot restoring') + +test:done(true) -- 2.49.0