From 166cacc505e5a0d807712e9cb5b6919a7d190a6e Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Wed, 12 Aug 2020 04:54:09 -0400 Subject: [PATCH] Fix corruption in ARGF.inplace Extension string stored in `ARGF.inplace` is created using an api designed for C string constants to create a Ruby string that points at another Ruby string. When the original string is swept, the extension string gets corrupted. Reproduction script (on MacOS): ```ruby #!/usr/bin/ruby -pi.bak BEGIN { GC.start(full_mark: true) arr = [] 1000000.times do |x| arr << "fooo#{x}" end } puts "hello" ``` Co-Authored-By: Matt Valentine-House <31869+eightbitraptor@users.noreply.github.com> --- io.c | 2 +- test/ruby/test_argf.rb | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/io.c b/io.c index 2760e6c530..5e4fdd5d95 100644 --- a/io.c +++ b/io.c @@ -12988,7 +12988,7 @@ opt_i_set(VALUE val, ID id, VALUE *var) void ruby_set_inplace_mode(const char *suffix) { - ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_fstring_cstr(suffix); + ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)); } /* diff --git a/test/ruby/test_argf.rb b/test/ruby/test_argf.rb index 277fa368f5..4734d5b3ae 100644 --- a/test/ruby/test_argf.rb +++ b/test/ruby/test_argf.rb @@ -387,6 +387,21 @@ class TestArgf < Test::Unit::TestCase assert_equal("foo", File.read(name+suffix)) end + def test_inplace_bug_17117 + assert_in_out_err(["-", @t1.path], "#{<<~"{#"}#{<<~'};'}") + {# + #!/usr/bin/ruby -pi.bak + BEGIN { + GC.start + arr = [] + 1000000.times { |x| arr << "fooo#{x}" } + } + puts "hello" + }; + assert_equal("hello\n1\nhello\n2\n", File.read(@t1.path)) + assert_equal("1\n2\n", File.read("#{@t1.path}.bak")) + end + def test_encoding ruby('-e', "#{<<~"{#"}\n#{<<~'};'}", @t1.path, @t2.path, @t3.path) do |f| {#