From d533fa752772be6df9ae3c145d409e5190c8ffcd Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 30 Jan 2026 23:15:22 +0900 Subject: [PATCH] Fix for string reference corruption issue If GC.compact occurs after parsing, strings referenced from the parse result are corrupted. Below is a reproduction script. In this case, it is intentionally reproducing a scenario where `GC.compact` occurs during parsing. ```rb require 'rbs' module Patch def to_i(...) super(...) end end String.prepend(Patch) TracePoint.new(:call) do |tp| GC.start GC.start GC.compact end.enable(target: String.instance_method(:to_i)) errors = 0 n = 100 n.times do |i| 1000.times { |i| "\x00" * (1000); "X#{i}" * 100 } len = 500 var = ("A" * len + "_V#{i}").to_sym type = "(42 | #{var}) -> Array[#{var}]" result = RBS::Parser.parse_method_type(type, variables: [var]) if var == result.type.return_type.args.first.name print "." else errors += 1 print "X" end end puts "\n#{errors}/n errors (#{(errors * 100.0 / n).round(1)}%)" exit(errors > 0 ? 1 : 0) ``` To fix this issue, similar to https://github.com/ruby/rbs/pull/2822 , strings of symbols given as arguments are copied and retained. If it is an **owned** type, `free()` will also be performed when the constant pool is freed. --- ext/rbs_extension/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ext/rbs_extension/main.c b/ext/rbs_extension/main.c index 4c3b934e5..edb4bf304 100644 --- a/ext/rbs_extension/main.c +++ b/ext/rbs_extension/main.c @@ -67,10 +67,12 @@ static void declare_type_variables(rbs_parser_t *parser, VALUE variables, VALUE } VALUE name_str = rb_sym2str(symbol); + uint8_t *copied_name = (uint8_t *) malloc((size_t) RSTRING_LEN(name_str)); + memcpy((void *) copied_name, RSTRING_PTR(name_str), RSTRING_LEN(name_str)); - rbs_constant_id_t id = rbs_constant_pool_insert_shared( + rbs_constant_id_t id = rbs_constant_pool_insert_owned( &parser->constant_pool, - (const uint8_t *) RSTRING_PTR(name_str), + copied_name, RSTRING_LEN(name_str) );