From d3a82fa1a8df9d46078c6f8e440feb3674757089 Mon Sep 17 00:00:00 2001 From: Sutou Kouhei Date: Tue, 6 Oct 2026 13:46:14 +0900 Subject: [PATCH] Reset the number of registers after string pattern match `set_registers()` used `onig_region_set()` that doesn't change `num_regs` when the region is already allocated. So `StringScanner#size` and `#captures` after a string pattern match reported the number of registers of the previous `Regexp` match: ```ruby s = StringScanner.new("abc") s.scan(/(a)(b)/) s.scan("c") s.size # => 3 (should be 1) s.captures # => [nil, nil] (should be []) ``` Use `onig_region_resize()` like `adjust_registers_to_matched()` does. This is consistent with the JRuby and TruffleRuby implementations. Co-Authored-By: Claude Opus 5.5 --- ext/strscan/strscan.c | 2 +- test/strscan/test_stringscanner.rb | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c index 42a1f7f1ad..dd7caf91b0 100644 --- a/ext/strscan/strscan.c +++ b/ext/strscan/strscan.c @@ -634,7 +634,7 @@ set_registers(struct strscanner *p, size_t pos, size_t length) const int at = 0; OnigRegion *regs = &(p->regs); onig_region_clear(regs); - if (onig_region_set(regs, at, 0, 0)) return; + if (onig_region_resize(regs, at + 1) != 0) return; if (p->fixed_anchor_p) { regs->beg[at] = pos + p->curr; regs->end[at] = pos + p->curr + length; diff --git a/test/strscan/test_stringscanner.rb b/test/strscan/test_stringscanner.rb index 8530be3893..87b429b29b 100644 --- a/test/strscan/test_stringscanner.rb +++ b/test/strscan/test_stringscanner.rb @@ -1025,6 +1025,27 @@ def test_size assert_equal(4, s.size) end + def test_size_after_string_match + s = create_string_scanner("abc") + s.scan(/(a)(b)/) + s.scan("c") + assert_equal([1, []], [s.size, s.captures]) + end + + def test_size_after_getch + s = create_string_scanner("abc") + s.scan(/(a)(b)/) + s.getch + assert_equal([1, []], [s.size, s.captures]) + end + + def test_size_after_get_byte + s = create_string_scanner("abc") + s.scan(/(a)(b)/) + s.get_byte + assert_equal([1, []], [s.size, s.captures]) + end + def test_captures s = create_string_scanner("Timestamp: Fri Dec 12 1975 14:39") s.scan("Timestamp: ")