mirror of
https://github.com/ruby/ruby.git
synced 2026-01-26 12:14:51 +00:00
Fix memory leak in String#encode when StringValue raises
The following script leaks memory:
10.times do
100_000.times do
"\ufffd".encode(Encoding::US_ASCII, fallback: proc { Object.new })
rescue
end
puts `ps -o rss= -p #{$$}`
end
Before:
450244
887748
1325124
1762756
2200260
2637508
3075012
3512516
3950020
4387524
After:
12236
12364
12748
13004
13388
13516
13772
13772
13772
13772
This commit is contained in:
parent
5384136eb5
commit
390d77ba00
Notes:
git
2025-11-01 14:48:06 +00:00
@ -3807,6 +3807,36 @@ CODE
|
||||
end
|
||||
end
|
||||
|
||||
def test_encode_fallback_not_string_memory_leak
|
||||
{
|
||||
"hash" => <<~RUBY,
|
||||
fallback = Hash.new { Object.new }
|
||||
RUBY
|
||||
"proc" => <<~RUBY,
|
||||
fallback = proc { Object.new }
|
||||
RUBY
|
||||
"method" => <<~RUBY,
|
||||
def my_method(_str) = Object.new
|
||||
fallback = method(:my_method)
|
||||
RUBY
|
||||
"aref" => <<~RUBY,
|
||||
fallback = Object.new
|
||||
def fallback.[](_str) = Object.new
|
||||
RUBY
|
||||
}.each do |type, code|
|
||||
assert_no_memory_leak([], '', <<~RUBY, "fallback type is #{type}", rss: true)
|
||||
class MyError < StandardError; end
|
||||
|
||||
#{code}
|
||||
|
||||
100_000.times do |i|
|
||||
"\\ufffd".encode(Encoding::US_ASCII, fallback:)
|
||||
rescue TypeError
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assert_bytesplice_result(expected, s, *args)
|
||||
|
||||
@ -2360,7 +2360,13 @@ transcode_loop_fallback_try(VALUE a)
|
||||
{
|
||||
struct transcode_loop_fallback_args *args = (struct transcode_loop_fallback_args *)a;
|
||||
|
||||
return args->fallback_func(args->fallback, args->rep);
|
||||
VALUE ret = args->fallback_func(args->fallback, args->rep);
|
||||
|
||||
if (!UNDEF_P(ret) && !NIL_P(ret)) {
|
||||
StringValue(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2428,7 +2434,6 @@ transcode_loop(const unsigned char **in_pos, unsigned char **out_pos,
|
||||
}
|
||||
|
||||
if (!UNDEF_P(rep) && !NIL_P(rep)) {
|
||||
StringValue(rep);
|
||||
ret = rb_econv_insert_output(ec, (const unsigned char *)RSTRING_PTR(rep),
|
||||
RSTRING_LEN(rep), rb_enc_name(rb_enc_get(rep)));
|
||||
if ((int)ret == -1) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user