Skip to content

Commit 61d086d

Browse files
authored
fix: fix range check for uint32 in jit (#833)
1 parent b8300f0 commit 61d086d

File tree

2 files changed

+116
-1
lines changed

2 files changed

+116
-1
lines changed

internal/decoder/jitdec/assembler_regabi_amd64.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,17 @@ func (self *_Assembler) range_unsigned_CX(i *rt.GoItab, t *rt.GoType, v uint64)
887887
self.Sjmp("JA" , _LB_range_error) // JA _range_error
888888
}
889889

890+
func (self *_Assembler) range_uint32_CX(i *rt.GoItab, t *rt.GoType) {
891+
self.Emit("MOVQ" , _VAR_st_Iv, _CX) // MOVQ st.Iv, CX
892+
self.Emit("MOVQ" , jit.Gitab(i), _ET) // MOVQ ${i}, ET
893+
self.Emit("MOVQ" , jit.Gtype(t), _EP) // MOVQ ${t}, EP
894+
self.Emit("TESTQ", _CX, _CX) // TESTQ CX, CX
895+
self.Sjmp("JS" , _LB_range_error) // JS _range_error
896+
self.Emit("MOVL" , _CX, _DX) // MOVL CX, DX
897+
self.Emit("CMPQ" , _CX, _DX) // CMPQ CX, DX
898+
self.Sjmp("JNE" , _LB_range_error) // JNZ _range_error
899+
}
900+
890901
/** String Manipulating Routines **/
891902

892903
var (
@@ -1453,7 +1464,7 @@ func (self *_Assembler) _asm_OP_u16(_ *_Instr) {
14531464
func (self *_Assembler) _asm_OP_u32(_ *_Instr) {
14541465
var pin = "_u32_end_{n}"
14551466
self.parse_unsigned(uint32Type, pin, -1) // PARSE uint32
1456-
self.range_unsigned_CX(_I_uint32, _T_uint32, math.MaxUint32) // RANGE uint32
1467+
self.range_uint32_CX(_I_uint32, _T_uint32) // RANGE uint32
14571468
self.Emit("MOVL", _CX, jit.Ptr(_VP, 0)) // MOVL CX, (VP)
14581469
self.Link(pin)
14591470
}

issue_test/issue825_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* Copyright 2025 ByteDance Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package issue_test
18+
19+
import (
20+
"encoding/json"
21+
"fmt"
22+
"testing"
23+
24+
"github.com/bytedance/sonic"
25+
"github.com/stretchr/testify/require"
26+
)
27+
28+
func TestIssue825_IntegerTypeBoundaries(t *testing.T) {
29+
// Test different integer types with boundary values
30+
type testCase struct {
31+
name string
32+
input string
33+
value interface{}
34+
expected interface{}
35+
shouldError bool
36+
}
37+
38+
testCases := []testCase{
39+
// uint8 tests
40+
{"uint8_valid", "255", new(uint8), uint8(255), false},
41+
{"uint8_overflow", "256", new(uint8), uint8(0), true},
42+
{"uint8_large", "9223372036854775807", new(uint8), uint8(0), true},
43+
44+
// uint16 tests
45+
{"uint16_valid", "65535", new(uint16), uint16(65535), false},
46+
{"uint16_overflow", "65536", new(uint16), uint16(0), true},
47+
{"uint16_large", "9223372036854775807", new(uint16), uint16(0), true},
48+
49+
// uint32 tests (the main issue)
50+
{"uint32_valid", "4294967295", new(uint32), uint32(4294967295), false},
51+
{"uint32_overflow", "4294967296", new(uint32), uint32(0), true},
52+
{"uint32_large", "9223372036854775807", new(uint32), uint32(0), true},
53+
54+
// uint64 tests
55+
{"uint64_valid", "9223372036854775807", new(uint64), uint64(9223372036854775807), false},
56+
{"uint64_max", "18446744073709551615", new(uint64), uint64(18446744073709551615), false},
57+
58+
// int8 tests
59+
{"int8_valid", "127", new(int8), int8(127), false},
60+
{"int8_overflow", "128", new(int8), int8(0), true},
61+
{"int8_negative", "-128", new(int8), int8(-128), false},
62+
{"int8_negative_overflow", "-129", new(int8), int8(0), true},
63+
64+
// int16 tests
65+
{"int16_valid", "32767", new(int16), int16(32767), false},
66+
{"int16_overflow", "32768", new(int16), int16(0), true},
67+
{"int16_negative", "-32768", new(int16), int16(-32768), false},
68+
{"int16_negative_overflow", "-32769", new(int16), int16(0), true},
69+
70+
// int32 tests
71+
{"int32_valid", "2147483647", new(int32), int32(2147483647), false},
72+
{"int32_overflow", "2147483648", new(int32), int32(0), true},
73+
{"int32_negative", "-2147483648", new(int32), int32(-2147483648), false},
74+
{"int32_negative_overflow", "-2147483649", new(int32), int32(0), true},
75+
76+
// int64 tests
77+
{"int64_valid", "9223372036854775807", new(int64), int64(9223372036854775807), false},
78+
{"int64_negative", "-9223372036854775808", new(int64), int64(-9223372036854775808), false},
79+
}
80+
81+
for _, tc := range testCases {
82+
t.Run(tc.name, func(t *testing.T) {
83+
// Test Sonic
84+
err := sonic.Unmarshal([]byte(tc.input), tc.value)
85+
sonicHasError := err != nil
86+
87+
// Test standard library
88+
errStd := json.Unmarshal([]byte(tc.input), tc.value)
89+
stdHasError := errStd != nil
90+
91+
fmt.Printf("Test: %s\n", tc.name)
92+
fmt.Printf(" Input: %s\n", tc.input)
93+
fmt.Printf(" Sonic error: %v\n", err)
94+
fmt.Printf(" Std error: %v\n", errStd)
95+
fmt.Printf(" Error match: %v == %v\n", sonicHasError, stdHasError)
96+
fmt.Println()
97+
98+
// Check error behavior consistency
99+
require.Equal(t, stdHasError, sonicHasError,
100+
"Error behavior mismatch for %s: Sonic error=%v, Std error=%v",
101+
tc.input, sonicHasError, stdHasError)
102+
})
103+
}
104+
}

0 commit comments

Comments
 (0)