6804addeec (master): Keep the fallback string alive across rb_econv_insert_output

0 views
Skip to first unread message

Koichi Sasada

unread,
1:22 PM (11 hours ago) 1:22 PM
to ruby...@g.ruby-lang.org
Koichi Sasada 2026-08-30 14:59:15 +0000 (Sun, 30 Aug 2026)

New Revision: 6804addeec

https://github.com/ruby/ruby/commit/6804addeec

Log:
Keep the fallback string alive across rb_econv_insert_output

transcode_loop() passed the fallback result to rb_econv_insert_output()
as a bare pointer and length. Nothing roots the string during that call:
args.rep still holds the pre-fallback error-bytes string, and with
clang -O3 the VALUE itself lives in no stack slot the conservative scan
can see -- only the raw data pointer survives in a register, and for an
embedded string that is an interior pointer the scanner rejects.

rb_econv_insert_output() can run a GC: when the fallback string's
encoding differs from the converter's insert encoding it calls
allocate_converted_string(), which opens a fresh econv and allocates the
destination buffer. The fallback string is then swept mid-call and the
sub-conversion reads its freed bytes.

On an ASAN build this reports use-after-poison at the 1-byte input read
in transcode_restartable0(); CI hit it about once in two hundred runs of
test_fallback_proc, and GC.stress reproduces it in a few hundred
iterations on a clang -O3 ASAN build. With RB_GC_GUARD the same loop is
clean.

Co-Authored-By: Claude Opus 5 <nor...@anthropic.com>

Modified files:
transcode.c
Reply all
Reply to author
Forward
0 new messages