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 143711B71201; Fri, 6 Mar 2026 16:42:39 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 143711B71201 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1772804559; bh=+N3/ympTzd322vKiM6/WkAyHeyQzX1/CzpULfLekRGE=; 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=X0fSi5mQ0Uo46fejmd32hRnLz1DOu411OZmKv/Nuwy4nw5vWdYA/gYTSsUn/VPEZy jRVsRw2qfwAGi4K77l6p0C0KJ7ocIVAIzW/aAz1ykCvfZnNAjt8kyRsCZSucApEwS4 tWO4pmf+ahsBxbnP3Un8SHv/NXO/swXTeTgn5ulE= Received: from send241.i.mail.ru (send241.i.mail.ru [95.163.59.80]) (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 3A9671B7A57B for ; Fri, 6 Mar 2026 16:42:08 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 3A9671B7A57B Received: by exim-smtp-695fc89d9f-w2j46 with esmtpa (envelope-from ) id 1vyVRP-00000000I8k-0kBG; Fri, 06 Mar 2026 16:42:07 +0300 To: Sergey Bronnikov Date: Fri, 6 Mar 2026 16:42:54 +0300 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Mailru-Src: smtp X-4EC0790: 10 X-7564579A: 78E4E2B564C1792B X-77F55803: 4F1203BC0FB41BD91ABAE9865AC7DC88E3B882EBCA423B4D6BA2A0DD5046E6A3182A05F5380850405F5DCD448E9599F93DE06ABAFEAF67052DAE8250B62273C1DCE0344743397B7022AF0AD8BA8DF889 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7D9C4478D0B876341EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637AC83A81C8FD4AD23D82A6BABE6F325AC2E85FA5F3EDFCBAA7353EFBB553375666F44369204E714C71A41C76590B8617C34C2904774DD75337DC13077BA4BFAF2389733CBF5DBD5E913377AFFFEAFD269176DF2183F8FC7C0CB629EEF1311BF91D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8B8883BAB8B32E402CA471835C12D1D977C4224003CC836476EB9C4185024447017B076A6E789B0E975F5C1EE8F4F765FC0AB88CB275472D7A3AA81AA40904B5D9CF19DD082D7633A0C84D3B47A649675F3AA81AA40904B5D98AA50765F790063792ACDD2839142C15D81D268191BDAD3D3666184CF4C3C14F3FC91FA280E0CE3D1A620F70A64A45A98AA50765F79006372E808ACE2090B5E1725E5C173C3A84C3C5EA940A35A165FF2DBA43225CD8A89FB26E97DCB74E6252C6EABA9B74D0DA47B5C8C57E37DE458BEDA766A37F9254B7 X-C1DE0DAB: 0D63561A33F958A5D7244C9C563402105002B1117B3ED6962FE76DDC983746A1219207EC0A953D2C823CB91A9FED034534781492E4B8EEADF12279BA039A6965C79554A2A72441328621D336A7BC284946AD531847A6065A535571D14F44ED41 X-C8649E89: 1C3962B70DF3F0AD73CAD6646DEDE191716CD42B3DD1D34CAB70F9BE574AE9C625B6776AC983F447FC0B9F89525902EE6F57B2FD27647F25E66C117BDB76D659A38E99E0C6F2779ECB76CADD11711518875A6D1FD9EB74607C356CF6BEEF3D1EB459FF948EF20132B8341EE9D5BE9A0A2472A4F3EFB6B45BEF77CD829DB9C1E0503B686577E23CE46536EB022892E5344C41F94D744909CECFA6C6B0C050A61A8CAF69B82BA93681CD72808BE417F3B9E0E7457915DAA85F X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu53w8ahmwBjZKM/YPHZyZHvz5uv+WouB9+ObcCpyrx6l7KImUglyhkEat/+ysWwi0gdhEs0JGjl6ggRWTy1haxBpVdbIX1nthFXMZebaIdHP2ghjoIc/363UZI6Kf1ptIMVbwN8XFWZxQUyEVP2Efn6QY= X-Mailru-Sender: 583F1D7ACE8F49BDD951BA70C165859EFF7D02DFA92120F9E9E07FF329DA7D4715F4C2E6EF6D7A8D917C509E768BB0B6F2400F607609286E924004A7DEC283833C7120B22964430C52B393F8C72A41A84198E0F3ECE9B5443453F38A29522196 X-Mras: Ok Subject: [Tarantool-patches] [PATCH luajit 1/2] Fix edge cases when generating IR for string.byte/sub/find. 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 Contributed by XmiliaH. (cherry picked from commit af9763a50da87ff8ba16e828cbd5664135e05a88) The generated ADD/SUB IRs for the calculation of indexes in the string for the aforementioned build-ins don't check the overflow. This may lead to the incorrect results, incorrect trace semantics, or invalid memory access. Also, the negative values may pass the UGT guard check emitted for the positive `end` position and lead to the incorrect results on the trace. This patch fixes this by using guarded ADDOV/SUBOV instead. The UGT IR is replaced with GT. Sergey Kaplun: * added the description and the test for the problem Part of tarantool/tarantool#12134 --- src/lj_ffrecord.c | 8 +-- .../lj-1407-ir-string-builtin.test.lua | 70 +++++++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 test/tarantool-tests/lj-1407-ir-string-builtin.test.lua diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c index 3b82d044..d888e83e 100644 --- a/src/lj_ffrecord.c +++ b/src/lj_ffrecord.c @@ -752,7 +752,7 @@ static TRef recff_string_start(jit_State *J, GCstr *s, int32_t *st, TRef tr, emitir(IRTGI(IR_EQ), tr, tr0); tr = tr0; } else { - tr = emitir(IRTI(IR_ADD), tr, lj_ir_kint(J, -1)); + tr = emitir(IRTGI(IR_ADDOV), tr, lj_ir_kint(J, -1)); emitir(IRTGI(IR_GE), tr, tr0); start--; } @@ -804,7 +804,7 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd) } else if ((MSize)end <= str->len) { emitir(IRTGI(IR_ULE), trend, trlen); } else { - emitir(IRTGI(IR_UGT), trend, trlen); + emitir(IRTGI(IR_GT), trend, trlen); end = (int32_t)str->len; trend = trlen; } @@ -812,7 +812,7 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd) if (rd->data) { /* Return string.sub result. */ if (end - start >= 0) { /* Also handle empty range here, to avoid extra traces. */ - TRef trptr, trslen = emitir(IRTI(IR_SUB), trend, trstart); + TRef trptr, trslen = emitir(IRTGI(IR_SUBOV), trend, trstart); emitir(IRTGI(IR_GE), trslen, tr0); trptr = emitir(IRT(IR_STRREF, IRT_PGC), trstr, trstart); J->base[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen); @@ -823,7 +823,7 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd) } else { /* Return string.byte result(s). */ ptrdiff_t i, len = end - start; if (len > 0) { - TRef trslen = emitir(IRTI(IR_SUB), trend, trstart); + TRef trslen = emitir(IRTGI(IR_SUBOV), trend, trstart); emitir(IRTGI(IR_EQ), trslen, lj_ir_kint(J, (int32_t)len)); if (J->baseslot + len > LJ_MAX_JSLOTS) lj_trace_err_info(J, LJ_TRERR_STACKOV); diff --git a/test/tarantool-tests/lj-1407-ir-string-builtin.test.lua b/test/tarantool-tests/lj-1407-ir-string-builtin.test.lua new file mode 100644 index 00000000..f168469a --- /dev/null +++ b/test/tarantool-tests/lj-1407-ir-string-builtin.test.lua @@ -0,0 +1,70 @@ +local tap = require('tap') + +-- Test file to demonstrate incorrect LuaJIT recording for the +-- corner cases of the `string` built-ins. All cases below don't +-- check the integer overflow/underflow correctly. +-- See also https://github.com/LuaJIT/LuaJIT/issues/1407. + +local test = tap.test('lj-1407-ir-string-builtin'):skipcond({ + ['Test requires JIT enabled'] = not jit.status(), +}) + +test:plan(4) + +local function trace_sub(s, i, e) + local r = s:sub(i, e) + return r +end + +local function trace_sub_neg(s, i) + local r = s:sub(1, i) + return r +end + +local function trace_byte(s, i, e) + local r = s:byte(i, e) + return r +end + +local function trace_find(s, i) + local r = s:find('2', i) + return r +end + +jit.opt.start('hotloop=1') + +-- Compile the trace. +trace_sub('123', 1, -2) +trace_sub('123', 1, -2) +-- Execute the trace with the invalid memory access. +test:is(trace_sub('123', 0x7FFFFFFF, -0x7FFFFFFF), '', + 'string.sub is correct at the trace') + +-- The arithmetic for the number of results on the trace is the +-- following for the negative last argument (`end`): +-- | str->len + 1 + end - (start - 1) +-- Trace has the guard to the number of results. We should record +-- an original trace with the guard passed for the underflowed +-- case as well: +-- 0 + 1 + 0x80000001 - 0x7ffffffe = 4. +-- Compile the trace that fits the needed properties: +trace_byte('1234', 1, -1) +trace_byte('1234', 1, -1) +-- Execute the trace with the invalid memory access. +test:is(trace_byte('', 0x7FFFFFFF, -0x7FFFFFFF), nil, + 'string.byte is correct at the trace') + +-- Compile the trace. +trace_sub_neg('123', 5) +trace_sub_neg('123', 5) +-- Execute the trace with negative value. +test:is(trace_sub_neg('123', -2), '12', + 'string.sub negative end is correct at the trace') + +-- Compile the trace. +trace_find('123', 5) +trace_find('123', 5) +-- Execute the trace with value to overflow. +test:is(trace_find('123', -0x80000000), 2, 'string.find with overflow') + +test:done(true) -- 2.53.0