Skip to content

Fix tonumber to handle bad input without throwing exceptions#346

Open
kellybirr wants to merge 2 commits into
moonsharp-devs:masterfrom
kellybirr:tonumber-fix
Open

Fix tonumber to handle bad input without throwing exceptions#346
kellybirr wants to merge 2 commits into
moonsharp-devs:masterfrom
kellybirr:tonumber-fix

Conversation

@kellybirr

Copy link
Copy Markdown

fix: tonumber(e, base) no longer throws raw CLR exceptions on bad input

tonumber with an explicit base delegated to Convert.ToUInt32 (for bases
2/8/10/16), so script-influenceable input like tonumber('zz', 16) escaped
the interpreter as a raw FormatException — and input above uint.MaxValue
as an OverflowException — instead of returning nil per Lua semantics.
These exceptions cannot be caught by pcall and propagate into the
embedding host.

Replace the conversion with a small Lua-5.2-style numeral parser:

  • bases 2..36 supported (previously only 2..10 and 16), with digits
    0-9 and a-z/A-Z case-insensitively, per standard Lua
  • optional surrounding whitespace and a leading '-' accepted; any other
    input (empty, '0x' prefix, '+' sign, out-of-base digit, embedded
    space) yields nil instead of raising or throwing
  • large numerals accumulate into a double instead of overflowing uint
  • a string DynValue wrapping a null (DynValue.NewString(null)) yields
    nil instead of a NullReferenceException
  • only 'base out of range' still raises, matching reference Lua

Note two deliberate behavior changes, both aligning with reference Lua:
out-of-base digits in bases 3-9 previously raised "invalid character"
and now return nil (TestMore/301-basic.t updated accordingly), and
values above uint.MaxValue previously threw where they now parse.

Adds a TonumberTests fixture covering valid numerals across bases,
sign/whitespace handling, nil-on-unparseable-input regressions, large
values, and the out-of-range-base errors.

tonumber with an explicit base delegated to Convert.ToUInt32 (for bases
2/8/10/16), so script-influenceable input like tonumber('zz', 16) escaped
the interpreter as a raw FormatException — and input above uint.MaxValue
as an OverflowException — instead of returning nil per Lua semantics.
These exceptions cannot be caught by pcall and propagate into the
embedding host.

Replace the conversion with a small Lua-5.2-style numeral parser:

- bases 2..36 supported (previously only 2..10 and 16), with digits
  0-9 and a-z/A-Z case-insensitively, per standard Lua
- optional surrounding whitespace and a leading '-' accepted; any other
  input (empty, '0x' prefix, '+' sign, out-of-base digit, embedded
  space) yields nil instead of raising or throwing
- large numerals accumulate into a double instead of overflowing uint
- a string DynValue wrapping a null (DynValue.NewString(null)) yields
  nil instead of a NullReferenceException
- only 'base out of range' still raises, matching reference Lua

Note two deliberate behavior changes, both aligning with reference Lua:
out-of-base digits in bases 3-9 previously raised "invalid character"
and now return nil (TestMore/301-basic.t updated accordingly), and
values above uint.MaxValue previously threw where they now parse.

Adds a TonumberTests fixture covering valid numerals across bases,
sign/whitespace handling, nil-on-unparseable-input regressions, large
values, and the out-of-range-base errors.
fix: tonumber(e, base) no longer throws raw CLR exceptions on bad input
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant