From a30fe56a1c67f516e7d96932faf7ab8b496d16ea Mon Sep 17 00:00:00 2001 From: Jiale Lin <63439129+ljluestc@users.noreply.github.com> Date: Sun, 3 May 2026 20:10:15 -0700 Subject: [PATCH] fix: correct numeric string coercion with leading zeros Use decimal-first parsing for numeric string coercion to avoid unintended octal interpretation for values like "00011", while preserving hex support (for example "0x7d6"). Add regression coverage for issue #478 in both DoString-focused tests and glua issue script tests. Fixes #478 Co-Authored-By: Oz --- _glua-tests/issues.lua | 7 +++++++ state_test.go | 22 ++++++++++++++++++++++ utils.go | 24 ++++++++++++++++++------ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/_glua-tests/issues.lua b/_glua-tests/issues.lua index 6d6343ab..94cbfc2b 100644 --- a/_glua-tests/issues.lua +++ b/_glua-tests/issues.lua @@ -490,3 +490,10 @@ function test() assert(b == nil) end test() + +-- issue #478 +function test() + local a = "00001" + "00011" + assert(a == 12) +end +test() diff --git a/state_test.go b/state_test.go index 7b7aa53d..18f59fae 100644 --- a/state_test.go +++ b/state_test.go @@ -276,6 +276,28 @@ func TestConcat(t *testing.T) { errorIfNotEqual(t, "a1c", L.Concat(LString("a"), LNumber(1), LString("c"))) } +func TestDoStringNumericStringCoercion(t *testing.T) { + L := NewState() + defer L.Close() + + err := L.DoString(`a = "00001" + "00011"`) + errorIfNotNil(t, err) + + v := L.GetGlobal("a") + errorIfNotEqual(t, LNumber(12), v) +} + +func TestDoStringNumericStringHexCoercion(t *testing.T) { + L := NewState() + defer L.Close() + + err := L.DoString(`a = "0x7d6" + "1"`) + errorIfNotNil(t, err) + + v := L.GetGlobal("a") + errorIfNotEqual(t, LNumber(2007), v) +} + func TestPCall(t *testing.T) { L := NewState() defer L.Close() diff --git a/utils.go b/utils.go index 2df68dc7..bd83b413 100644 --- a/utils.go +++ b/utils.go @@ -143,14 +143,26 @@ func isArrayKey(v LNumber) bool { func parseNumber(number string) (LNumber, error) { var value LNumber number = strings.Trim(number, " \t\n") - if v, err := strconv.ParseInt(number, 0, LNumberBit); err != nil { - if v2, err2 := strconv.ParseFloat(number, LNumberBit); err2 != nil { - return LNumber(0), err2 - } else { - value = LNumber(v2) + if v, err := strconv.ParseInt(number, 10, LNumberBit); err == nil { + value = LNumber(v) + return value, nil + } + if len(number) > 2 { + prefix := number + if number[0] == '+' || number[0] == '-' { + prefix = number[1:] + } + if strings.HasPrefix(prefix, "0x") || strings.HasPrefix(prefix, "0X") { + if v, err := strconv.ParseInt(number, 0, LNumberBit); err == nil { + value = LNumber(v) + return value, nil + } } + } + if v2, err := strconv.ParseFloat(number, LNumberBit); err != nil { + return LNumber(0), err } else { - value = LNumber(v) + value = LNumber(v2) } return value, nil }