Skip to content

Problematic behaviour of #scan_integer(base: 16) when parses "0x" #140

Closed

Description

@andrykonchin

The method #scan_integer called with base: 16 is supposed to parse hexadecimal integer literals. There is an edge case when "0x" is not followed by any hex character (e.g. 0x.!@#). In this case #scan_integer doesn't match an integer literal and returns nil:

StringScanner.new("0x.!@#").scan_integer(base: 16)
# => nil

But there are might be pretty valid cases when 0 is expected to be returned instead:

StringScanner.new("0xyz").scan_integer(base: 16) # `"xyz"` is a plain text and `0` is expected

Wondering if it makes sense to match "0" and return 0 in the following cases:

  • "0x<non-hex-char>"
  • "+0x<non-hex-char>"
  • "-0x<non-hex-char>"
  • "0x<end-of-string>"
  • "+0x<end-of-string>"
  • "-0x<end-of-string>"

Activity

  1. eregon commented on Feb 19, 2025

    @eregon
    Member

    cc @byroot
    This was found when implementing scan_integer on TruffleRuby, where the natural way to do it would be using scan(/[+-]?(0x)?[0-9a-fA-F]+/).

  2. byroot commented on Feb 20, 2025

    @byroot
    Member

    Do you have a repro?

    I'm trying to fix this but if I add a test for it it passes:

    diff --git a/test/strscan/test_stringscanner.rb b/test/strscan/test_stringscanner.rb
    index eb35dfa..d939a2d 100644
    --- a/test/strscan/test_stringscanner.rb
    +++ b/test/strscan/test_stringscanner.rb
    @@ -1056,6 +1056,11 @@ module StringScannerTests
         assert_equal(0, s.pos)
         refute_predicate(s, :matched?)
     
    +    s = create_string_scanner('0xZZZZ')
    +    assert_nil(s.scan_integer(base: 16))
    +    assert_equal(0, s.pos)
    +    refute_predicate(s, :matched?)
    +
         s = create_string_scanner('-0x')
         assert_nil(s.scan_integer(base: 16))
         assert_equal(0, s.pos)
  3. byroot commented on Feb 20, 2025

    @byroot
    Member

    Nevermind, I kinda misread.

  4. byroot commented on Feb 20, 2025

    @byroot
    Member
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions