From: Evgeniy Temirgaleev via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: Sergey Kaplun <skaplun@tarantool.org>
Cc: tarantool-patches@dev.tarantool.org
Subject: Re: [Tarantool-patches] [PATCH luajit] Clarify that lj_buf_shrink() does not keep any buffer data.
Date: Thu, 12 Nov 2026 02:40:06 +0300 [thread overview]
Message-ID: <16fad0d6-b11c-49a9-8ca2-557b466f532d@tarantool.org> (raw)
In-Reply-To: <20261111133805.1497870-1-skaplun@tarantool.org>
Hi, Sergey! Thanks for the patch! LGTM
On 11/11/26 4:38 PM, Sergey Kaplun wrote:
> From: Mike Pall <mike>
>
> https://www.freelists.org/post/luajit/lj-buf-shrink-may-truncate-the-data-and-sbw-point-over-the-end-of-the-buffer,1
> Thanks to Junlong li.
>
> (cherry picked from commit 444c8ff19a39248307a7037354d6d259cc0e5efc)
>
> When `lj_cf_string_format()` formats any object to the string via `%s`
> it casts this object to a string implicitly on the first pass of parsing
> the regexp. If the `__tostring` metamethod of the object invokes the
> atomic step of the GC, GC shrinks the `tmpbuf` is used for string
> formatting. In case when the result string occupies more than half of
> the buffer, the writes in the second pass miss the buffer and may lead
> to the heap-buffer-overflow, an invalid result string, or the core dump.
>
> This patch resets the current pointer position in the buffer in the
> `lj_buf_shrink()` to avoid incorrect buffer writes.
>
> Sergey Kaplun:
> * added the description and the test for the problem
>
> Resolves tarantool/tarantool#4171
> Part of tarantool/tarantool#13442
> ---
>
> Branch: https://github.com/tarantool/luajit/tree/skaplun/gh-4171-lj-cf-string-format-atomic
> Related issues:
> * https://github.com/tarantool/tarantool/issues/4171
> * https://github.com/tarantool/tarantool/issues/13442
>
> src/lj_buf.c | 3 +-
> ...h-4171-lj-cf-string-format-atomic.test.lua | 30 +++++++++++++++++++
> 2 files changed, 31 insertions(+), 2 deletions(-)
> create mode 100644 test/tarantool-tests/gh-4171-lj-cf-string-format-atomic.test.lua
>
> diff --git a/src/lj_buf.c b/src/lj_buf.c
> index 923f4276..bcfc4c93 100644
> --- a/src/lj_buf.c
> +++ b/src/lj_buf.c
> @@ -52,10 +52,9 @@ void LJ_FASTCALL lj_buf_shrink(lua_State *L, SBuf *sb)
> char *b = sbufB(sb);
> MSize osz = (MSize)(sbufE(sb) - b);
> if (osz > 2*LJ_MIN_SBUF) {
> - MSize n = (MSize)(sbufP(sb) - b);
> b = lj_mem_realloc(L, b, osz, (osz >> 1));
> setmref(sb->b, b);
> - setmref(sb->p, b + n);
> + setmref(sb->p, b); /* Not supposed to keep data across shrinks. */
> setmref(sb->e, b + (osz >> 1));
> }
> }
> diff --git a/test/tarantool-tests/gh-4171-lj-cf-string-format-atomic.test.lua b/test/tarantool-tests/gh-4171-lj-cf-string-format-atomic.test.lua
> new file mode 100644
> index 00000000..c601ce08
> --- /dev/null
> +++ b/test/tarantool-tests/gh-4171-lj-cf-string-format-atomic.test.lua
> @@ -0,0 +1,30 @@
> +local tap = require('tap')
> +
> +-- The test file demonstrates `string.format()`
> +-- heap-buffer-overflow under ASAN if the atomic phase of the GC
> +-- is entered during the first pass of formatting with implicit
> +-- conversion of the argument to a string via %s.
> +-- See also: https://github.com/tarantool/tarantool/issues/4171.
> +local test = tap.test('gh-4171-lj-cf-string-format-atomic')
> +
> +test:plan(1)
> +
> +local obj = setmetatable({}, {
> + __tostring = function()
> + -- Shrinks `tmpbuf`: 256 -> 128 (but length of string is 200).
> + collectgarbage()
> + return 'x'
> + end
> +})
> +
> +local prefix = string.rep('a', 200)
> +
> +-- %s triggers a full GC cycle, including `tmpbuf` shrinking in
> +-- the atomic phase. '_suffix' was written outside the buffer
> +-- before the patch.
> +local res = string.format(prefix .. '%s_suffix', obj)
> +
> +-- Under ASAN this leads to heap-buffer-overflow.
> +test:is(res, prefix .. 'x_suffix', 'correct string format result')
> +
> +test:done(true)
--
--
Best regards,
Evgeniy Temirgaleev
prev parent reply other threads:[~2026-11-11 23:40 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-11 13:38 Sergey Kaplun via Tarantool-patches
2026-11-11 23:40 ` Evgeniy Temirgaleev via Tarantool-patches [this message]
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=16fad0d6-b11c-49a9-8ca2-557b466f532d@tarantool.org \
--to=tarantool-patches@dev.tarantool.org \
--cc=e.temirgaleev@tarantool.org \
--cc=skaplun@tarantool.org \
--subject='Re: [Tarantool-patches] [PATCH luajit] Clarify that lj_buf_shrink() does not keep any buffer data.' \
/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