From d70d0c562c9cca5f392aa9ff6a79f6145edcef78 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Thu, 20 Feb 2025 09:28:04 +0100 Subject: [PATCH] `scan_integer(base: 16)` ignore x suffix if not followed by hexadecimal Fix: https://github.com/ruby/strscan/issues/140 `0x`, `0xZZZ` should be parsed as `0` instead of not matching at all. --- .../jruby/ext/strscan/RubyStringScanner.java | 5 +++- ext/strscan/strscan.c | 2 +- test/strscan/test_stringscanner.rb | 23 +++++++++++-------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java index dc85048fe9..b7925b8fd2 100644 --- a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java +++ b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java @@ -616,7 +616,10 @@ public IRubyObject scan_base16_integer(ThreadContext context) { len++; } - if ((remaining_len >= (len + 2)) && bytes.get(ptr + len) == '0' && bytes.get(ptr + len + 1) == 'x') { + if ((remaining_len >= (len + 3)) && + bytes.get(ptr + len) == '0' && + bytes.get(ptr + len + 1) == 'x' && + isHexChar(bytes.get(ptr + len + 2))) { len += 2; } diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c index 012d3a4c42..e5a0ad66a3 100644 --- a/ext/strscan/strscan.c +++ b/ext/strscan/strscan.c @@ -1379,7 +1379,7 @@ strscan_scan_base16_integer(VALUE self) len++; } - if ((remaining_len >= (len + 2)) && ptr[len] == '0' && ptr[len + 1] == 'x') { + if ((remaining_len >= (len + 3)) && ptr[len] == '0' && ptr[len + 1] == 'x' && rb_isxdigit(ptr[len + 2])) { len += 2; } diff --git a/test/strscan/test_stringscanner.rb b/test/strscan/test_stringscanner.rb index eb35dfa119..2f68331da5 100644 --- a/test/strscan/test_stringscanner.rb +++ b/test/strscan/test_stringscanner.rb @@ -1052,19 +1052,24 @@ def test_scan_integer_base_16 assert_predicate(s, :matched?) s = create_string_scanner('0x') - assert_nil(s.scan_integer(base: 16)) - assert_equal(0, s.pos) - refute_predicate(s, :matched?) + assert_equal(0, s.scan_integer(base: 16)) + assert_equal(1, s.pos) + assert_predicate(s, :matched?) + + s = create_string_scanner('0xyz') + assert_equal(0, s.scan_integer(base: 16)) + assert_equal(1, s.pos) + assert_predicate(s, :matched?) s = create_string_scanner('-0x') - assert_nil(s.scan_integer(base: 16)) - assert_equal(0, s.pos) - refute_predicate(s, :matched?) + assert_equal(0, s.scan_integer(base: 16)) + assert_equal(2, s.pos) + assert_predicate(s, :matched?) s = create_string_scanner('+0x') - assert_nil(s.scan_integer(base: 16)) - assert_equal(0, s.pos) - refute_predicate(s, :matched?) + assert_equal(0, s.scan_integer(base: 16)) + assert_equal(2, s.pos) + assert_predicate(s, :matched?) s = create_string_scanner('-123abc') assert_equal(-0x123abc, s.scan_integer(base: 16))