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 3C74A1550A43; Thu, 11 Sep 2025 10:35:11 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 3C74A1550A43 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1757576111; bh=EKB3NdqFn1y3S0BrmmhJpLVqvMQlWBcg6GGW/bE09ek=; h=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=JlM1QEVXgKz4iyo2qPBvbSaV35yoeIRxfZhsdQZ5JBElvg6izCUVuHCg8b48/zdki k57BbpAMglFCd45BnNj2dvGkwEriTeJ5CTGmjEOds2jRu/HshdthfijOi+PhwJuhVz duek0V4QVUgvCUjOemrr+sPDfCWXlhnm6DCQdFuY= Received: from send58.i.mail.ru (send58.i.mail.ru [89.221.237.153]) (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 5DDB840E76C for ; Thu, 11 Sep 2025 10:35:09 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 5DDB840E76C Received: by exim-smtp-6658775494-j45qb with esmtpa (envelope-from ) id 1uwbpk-000000004SB-0e1m; Thu, 11 Sep 2025 10:35:08 +0300 Content-Type: multipart/alternative; boundary="------------SS4XU356LkX0N2Ai5dN2IN1W" Message-ID: <2add5454-ffe6-415c-a247-c48bf9349f9a@tarantool.org> Date: Thu, 11 Sep 2025 10:35:07 +0300 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird To: Sergey Kaplun , tarantool-patches References: Content-Language: en-US In-Reply-To: X-Mailru-Src: smtp X-4EC0790: 10 X-7564579A: 78E4E2B564C1792B X-77F55803: 4F1203BC0FB41BD996BA4BB8E0D3695B29F161A018EC2674B8237E3AAB4F1994182A05F5380850401C26F18B2EFDAB453DE06ABAFEAF67052E3EC63D4CECCBE5E9C3D291D2A32EF14787F701E017BF3D X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7492D3E4238663367EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637AC83A81C8FD4AD23D82A6BABE6F325AC2E85FA5F3EDFCBAA7353EFBB55337566A5F354E88FC47EC0FD8BB269841BB1DFC638A2C8D659EEA2EA6887943120E014389733CBF5DBD5E913377AFFFEAFD269176DF2183F8FC7C078FCF50C7EAF9C588941B15DA834481FCF19DD082D7633A0EF3E4896CB9E6436389733CBF5DBD5E9D5E8D9A59859A8B6F459A8243F1D1D44CC7F00164DA146DA6F5DAA56C3B73B237318B6A418E8EAB8D32BA5DBAC0009BE9E8FC8737B5C22490F250D17497FEF6176E601842F6C81A12EF20D2F80756B5FB606B96278B59C4276E601842F6C81A127C277FBC8AE2E8B8DBB596EC94336063AA81AA40904B5D99C9F4D5AE37F343AD1F44FA8B9022EA23BBE47FD9DD3FB595F5C1EE8F4F765FC72CEEB2601E22B093A03B725D353964B0B7D0EA88DDEDAC722CA9DD8327EE4930A3850AC1BE2E7352686C055BC15B7FBC4224003CC83647689D4C264860C145E X-C1DE0DAB: 0D63561A33F958A56B513ADD8DEC66CC5002B1117B3ED6966652A44A38D0C40A33EE06AFCD964888823CB91A9FED034534781492E4B8EEAD14747542773C033FBDAD6C7F3747799A X-C8649E89: 1C3962B70DF3F0ADBF74143AD284FC7177DD89D51EBB7742424CF958EAFF5D571004E42C50DC4CA955A7F0CF078B5EC49A30900B95165D341ADA1A41A420E9B29AD9C2853761C536E1CD6142D772ECA0204F90AD95B67E4DBB341F129B7FE6321D7E09C32AA3244C62C0ECD3CFD7576A77DD89D51EBB774277B8C26058517D44EA455F16B58544A2E30DDF7C44BCB90DA5AE236DF995FB59978A700BF655EAEEED6A17656DB59BCAD427812AF56FC65B X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu53w8ahmwBjZKM/YPHZyZHvz5uv+WouB9+ObcCpyrx6l7KImUglyhkEat/+ysWwi0gdhEs0JGjl6ggRWTy1haxBpVdbIX1nthFXMZebaIdHP2ghjoIc/363UZI6Kf1ptIMVdVMtzNxwZu59+DMpnJITZI= X-Mailru-Sender: 811C44EDE0507D1FE3AB2BB2D6096E35F15E2356C9B320ABCC811723C208B417EFA438B3766CE55AAA34DFAC7EFFC4FC645D15D82EE4B272BD6E4642A116CA93524AA66B5ACBE6721EF430B9A63E2A504198E0F3ECE9B5443453F38A29522196 X-Mras: Ok Subject: Re: [Tarantool-patches] Fwd: [PATCH luajit] Invalidate SCEV entry when returning to lower frame. 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 Bronnikov via Tarantool-patches Reply-To: Sergey Bronnikov Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" This is a multi-part message in MIME format. --------------SS4XU356LkX0N2Ai5dN2IN1W Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Hi, Sergey, thanks for the patch! LGTM Sergey On 9/11/25 09:59, Sergey Kaplun wrote: >> >> From: Mike Pall >> >> Thanks to Zhongwei Yao. >> >> (cherry picked from commit 65c849390702b1150d52e64db86cbc6b3c98413e) >> >> When returning to the lower frame, LuaJIT does not clear the Scalar >> Evolution analysis entry. Hence, this may lead to its invalid usage in >> the next function called if the IR references match. The further >> analysis is invalid and may lead to the assertion failure. >> >> This patch invalidates the ScEv entry IR reference index when returning >> to the lower frame. >> >> Sergey Kaplun: >> * added the description and the test for the problem >> >> Part of tarantool/tarantool#11691 >> --- >> >> Branch:https://github.com/tarantool/luajit/tree/skaplun/lj-1115-invalid-scev-entry-lower-frame >> Related issues: >> *https://github.com/LuaJIT/LuaJIT/pull/1115 >> *https://github.com/tarantool/tarantool/issues/11691 >> >> src/lj_record.c | 1 + >> ...15-invalid-scev-entry-lower-frame.test.lua | 69 +++++++++++++++++++ >> 2 files changed, 70 insertions(+) >> create mode 100644 test/tarantool-tests/lj-1115-invalid-scev-entry-lower-frame.test.lua >> >> diff --git a/src/lj_record.c b/src/lj_record.c >> index 1dd22dac..ba409a61 100644 >> --- a/src/lj_record.c >> +++ b/src/lj_record.c >> @@ -898,6 +898,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) >> emitir(IRTG(IR_RETF, IRT_PGC), trpt, trpc); >> J->retdepth++; >> J->needsnap = 1; >> + J->scev.idx = REF_NIL; >> lj_assertJ(J->baseslot == 1+LJ_FR2, "bad baseslot for return"); >> /* Shift result slots up and clear the slots of the new frame below. */ >> memmove(J->base + cbase, J->base-1-LJ_FR2, sizeof(TRef)*nresults); >> diff --git a/test/tarantool-tests/lj-1115-invalid-scev-entry-lower-frame.test.lua b/test/tarantool-tests/lj-1115-invalid-scev-entry-lower-frame.test.lua >> new file mode 100644 >> index 00000000..47bc87ae >> --- /dev/null >> +++ b/test/tarantool-tests/lj-1115-invalid-scev-entry-lower-frame.test.lua >> @@ -0,0 +1,69 @@ >> +local tap = require('tap') >> + >> +-- Test file to demonstrate LuaJIT's incorrect Scalar Evolution >> +-- analysis for recording of return to a lower frame. >> +-- See also:https://github.com/LuaJIT/LuaJIT/pull/1115. >> +local test = tap.test('lj-1115-invalid-scev-entry-lower-frame'):skipcond({ >> + ['Test requires JIT enabled'] = not jit.status(), >> +}) >> + >> +test:plan(1) >> + >> +local HOTLOOP = 1 >> +local HOTEXIT = 1 >> +local RECORD_IDX = HOTLOOP + 1 >> +-- Number of iterations to start recording side trace with two >> +-- iterations in the cycle. >> +local NITER = RECORD_IDX + HOTEXIT + 2 >> + >> +local function test_function(tab) >> + -- XXX: For reproducing the issue, it is necessary to avoid >> + -- UGET. Local functions use MOV and take the same IR slots. >> + local function trace_root(data) >> + -- Start of the trace, setup ScEv entry. >> + for i = 1, #data - 1 do >> + -- Start of the side trace by the hmask check. >> + if data[i].t == 'a' then >> + return i + 1 >> + end >> + end >> + -- Unreachable in this test. >> + return nil >> + end >> + >> + local function other_scev(data, start) >> + for i = start, #data - 1 do >> + -- The ScEv entry matches the recorded IR from the parent >> + -- trace before the patch. It leads to the assertion >> + -- failure. >> + if data[i].t == 'a' then >> + return >> + end >> + end >> + end >> + >> + -- Record the root trace first. Then record the side trace >> + -- returning to the lower frame (this function). >> + local start = trace_root(tab) >> + -- The ScEv entry is invalid after the return to the lower >> + -- frame. Record the trace with another range in the ScEv entry >> + -- to obtain the error. >> + return start, other_scev(tab, start) >> +end >> + >> +local data = {} >> +for i = 1, NITER do >> + data[#data + 1] = {t = 'a' .. i} >> +end >> + >> +-- Change the hmask value to start the side trace recording. >> +data[RECORD_IDX] = {} >> +-- Setup for the trace's return to the lower frame. >> +data[NITER - 2] = {t = 'a'} >> + >> +jit.opt.start('hotloop=' .. HOTLOOP, 'hotexit=' .. HOTEXIT) >> + >> +test_function(data) >> + >> +test:ok(true, 'correct ScEv entry invalidation for return to a lower frame') >> +test:done(true) >> -- >> 2.51.0 >> > ----- End forwarded message ----- > --------------SS4XU356LkX0N2Ai5dN2IN1W Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 7bit

Hi, Sergey,

thanks for the patch! LGTM

Sergey

On 9/11/25 09:59, Sergey Kaplun wrote:

From: Mike Pall <mike>

Thanks to Zhongwei Yao.

(cherry picked from commit 65c849390702b1150d52e64db86cbc6b3c98413e)

When returning to the lower frame, LuaJIT does not clear the Scalar
Evolution analysis entry. Hence, this may lead to its invalid usage in
the next function called if the IR references match. The further
analysis is invalid and may lead to the assertion failure.

This patch invalidates the ScEv entry IR reference index when returning
to the lower frame.

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

Part of tarantool/tarantool#11691
---

Branch: https://github.com/tarantool/luajit/tree/skaplun/lj-1115-invalid-scev-entry-lower-frame
Related issues:
* https://github.com/LuaJIT/LuaJIT/pull/1115
* https://github.com/tarantool/tarantool/issues/11691

 src/lj_record.c                               |  1 +
 ...15-invalid-scev-entry-lower-frame.test.lua | 69 +++++++++++++++++++
 2 files changed, 70 insertions(+)
 create mode 100644 test/tarantool-tests/lj-1115-invalid-scev-entry-lower-frame.test.lua

diff --git a/src/lj_record.c b/src/lj_record.c
index 1dd22dac..ba409a61 100644
--- a/src/lj_record.c
+++ b/src/lj_record.c
@@ -898,6 +898,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
       emitir(IRTG(IR_RETF, IRT_PGC), trpt, trpc);
       J->retdepth++;
       J->needsnap = 1;
+      J->scev.idx = REF_NIL;
       lj_assertJ(J->baseslot == 1+LJ_FR2, "bad baseslot for return");
       /* Shift result slots up and clear the slots of the new frame below. */
       memmove(J->base + cbase, J->base-1-LJ_FR2, sizeof(TRef)*nresults);
diff --git a/test/tarantool-tests/lj-1115-invalid-scev-entry-lower-frame.test.lua b/test/tarantool-tests/lj-1115-invalid-scev-entry-lower-frame.test.lua
new file mode 100644
index 00000000..47bc87ae
--- /dev/null
+++ b/test/tarantool-tests/lj-1115-invalid-scev-entry-lower-frame.test.lua
@@ -0,0 +1,69 @@
+local tap = require('tap')
+
+-- Test file to demonstrate LuaJIT's incorrect Scalar Evolution
+-- analysis for recording of return to a lower frame.
+-- See also: https://github.com/LuaJIT/LuaJIT/pull/1115.
+local test = tap.test('lj-1115-invalid-scev-entry-lower-frame'):skipcond({
+  ['Test requires JIT enabled'] = not jit.status(),
+})
+
+test:plan(1)
+
+local HOTLOOP = 1
+local HOTEXIT = 1
+local RECORD_IDX = HOTLOOP + 1
+-- Number of iterations to start recording side trace with two
+-- iterations in the cycle.
+local NITER = RECORD_IDX + HOTEXIT + 2
+
+local function test_function(tab)
+  -- XXX: For reproducing the issue, it is necessary to avoid
+  -- UGET. Local functions use MOV and take the same IR slots.
+  local function trace_root(data)
+    -- Start of the trace, setup ScEv entry.
+    for i = 1, #data - 1 do
+      -- Start of the side trace by the hmask check.
+      if data[i].t == 'a' then
+        return i + 1
+      end
+    end
+    -- Unreachable in this test.
+    return nil
+  end
+
+  local function other_scev(data, start)
+    for i = start, #data - 1 do
+      -- The ScEv entry matches the recorded IR from the parent
+      -- trace before the patch. It leads to the assertion
+      -- failure.
+      if data[i].t == 'a' then
+        return
+      end
+    end
+  end
+
+  -- Record the root trace first. Then record the side trace
+  -- returning to the lower frame (this function).
+  local start = trace_root(tab)
+  -- The ScEv entry is invalid after the return to the lower
+  -- frame. Record the trace with another range in the ScEv entry
+  -- to obtain the error.
+  return start, other_scev(tab, start)
+end
+
+local data = {}
+for i = 1, NITER do
+  data[#data + 1] = {t = 'a' .. i}
+end
+
+-- Change the hmask value to start the side trace recording.
+data[RECORD_IDX] = {}
+-- Setup for the trace's return to the lower frame.
+data[NITER - 2] = {t = 'a'}
+
+jit.opt.start('hotloop=' .. HOTLOOP, 'hotexit=' .. HOTEXIT)
+
+test_function(data)
+
+test:ok(true, 'correct ScEv entry invalidation for return to a lower frame')
+test:done(true)
-- 
2.51.0

----- End forwarded message -----

--------------SS4XU356LkX0N2Ai5dN2IN1W--