checker: fix signed integer literal overflow error, when most significant bit occupies signed bit (fix #23782) (#23919)

This commit is contained in:
ChAoS_UnItY (Kyle Lin) 2025-03-13 23:29:44 +08:00 committed by GitHub
parent 734fde89e8
commit 9f3f1291e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 244 additions and 24 deletions

View File

@ -17,7 +17,7 @@ fn test_str_methods() {
assert int(1).str() == '1'
assert int(-1).str() == '-1'
assert int(2147483647).str() == '2147483647'
assert int(2147483648).str() == '-2147483648'
assert int(u32(2147483648)).str() == '-2147483648'
assert int(-2147483648).str() == '-2147483648'
assert i64(1).str() == '1'
assert i64(-1).str() == '-1'

View File

@ -330,8 +330,8 @@ fn test_parse() {
}
fn test_interpolate_binary_literals() {
assert ' 1 ${i64(0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000)}' == ' 1 -9223372036854775808'
assert ' 2 ${i64(0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111)}' == ' 2 -1'
assert ' 1 ${i64(u64(0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000))}' == ' 1 -9223372036854775808'
assert ' 2 ${i64(u64(0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111))}' == ' 2 -1'
assert ' 3 ${i64(0b0111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111)}' == ' 3 9223372036854775807'
assert ' 4 ${u64(0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000)}' == ' 4 9223372036854775808'
assert ' 5 ${u64(0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111)}' == ' 5 18446744073709551615'

View File

@ -166,7 +166,7 @@ fn test_mt19937_u64_in_range() {
fn test_mt19937_int31() {
max_u31 := int(0x7FFFFFFF)
sign_mask := int(0x80000000)
sign_mask := int(u32(0x80000000))
for seed in seeds {
mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
rng.seed(seed)
@ -182,7 +182,7 @@ fn test_mt19937_int31() {
fn test_mt19937_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000)
sign_mask := i64(u64(0x8000000000000000))
for seed in seeds {
mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
rng.seed(seed)

View File

@ -155,7 +155,7 @@ fn test_musl_u64_in_range() {
fn test_musl_int31() {
max_u31 := int(0x7FFFFFFF)
sign_mask := int(0x80000000)
sign_mask := int(u32(0x80000000))
for seed in seeds {
mut rng := &rand.PRNG(&musl.MuslRNG{})
rng.seed(seed)
@ -171,7 +171,7 @@ fn test_musl_int31() {
fn test_musl_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000)
sign_mask := i64(u64(0x8000000000000000))
for seed in seeds {
mut rng := &rand.PRNG(&musl.MuslRNG{})
rng.seed(seed)

View File

@ -158,7 +158,7 @@ fn test_pcg32_u64_in_range() {
fn test_pcg32_int31() {
max_u31 := int(0x7FFFFFFF)
sign_mask := int(0x80000000)
sign_mask := int(u32(0x80000000))
for seed in seeds {
mut rng := &rand.PRNG(&pcg32.PCG32RNG{})
rng.seed(seed)
@ -174,7 +174,7 @@ fn test_pcg32_int31() {
fn test_pcg32_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000)
sign_mask := i64(u64(0x8000000000000000))
for seed in seeds {
mut rng := &rand.PRNG(&pcg32.PCG32RNG{})
rng.seed(seed)

View File

@ -121,7 +121,7 @@ fn test_rand_i64_in_range() {
fn test_rand_int31() {
max_u31 := int(0x7FFFFFFF)
sign_mask := int(0x80000000)
sign_mask := int(u32(0x80000000))
for _ in 0 .. rnd_count {
value := rand.int31()
assert value >= 0
@ -133,7 +133,7 @@ fn test_rand_int31() {
fn test_rand_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000)
sign_mask := i64(u64(0x8000000000000000))
for _ in 0 .. rnd_count {
value := rand.int63()
assert value >= 0

View File

@ -155,7 +155,7 @@ fn test_splitmix64_u64_in_range() {
fn test_splitmix64_int31() {
max_u31 := int(0x7FFFFFFF)
sign_mask := int(0x80000000)
sign_mask := int(u32(0x80000000))
for seed in seeds {
mut rng := &rand.PRNG(&splitmix64.SplitMix64RNG{})
rng.seed(seed)
@ -171,7 +171,7 @@ fn test_splitmix64_int31() {
fn test_splitmix64_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000)
sign_mask := i64(u64(0x8000000000000000))
for seed in seeds {
mut rng := &rand.PRNG(&splitmix64.SplitMix64RNG{})
rng.seed(seed)

View File

@ -253,7 +253,7 @@ fn test_sys_rng_i64_in_range() {
fn test_sys_rng_int31() {
max_u31 := int(0x7FFFFFFF)
sign_mask := int(0x80000000)
sign_mask := int(u32(0x80000000))
for seed in seeds {
seed_data := [seed]
mut rng := &rand.PRNG(&sys.SysRNG{})
@ -270,7 +270,7 @@ fn test_sys_rng_int31() {
fn test_sys_rng_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000)
sign_mask := i64(u64(0x8000000000000000))
for seed in seeds {
seed_data := [seed]
mut rng := &rand.PRNG(&sys.SysRNG{})

View File

@ -155,7 +155,7 @@ fn test_wyrand_u64_in_range() {
fn test_wyrand_int31() {
max_u31 := int(0x7FFFFFFF)
sign_mask := int(0x80000000)
sign_mask := int(u32(0x80000000))
for seed in seeds {
mut rng := &rand.PRNG(&wyrand.WyRandRNG{})
rng.seed(seed)
@ -171,7 +171,7 @@ fn test_wyrand_int31() {
fn test_wyrand_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000)
sign_mask := i64(u64(0x8000000000000000))
for seed in seeds {
mut rng := &rand.PRNG(&wyrand.WyRandRNG{})
rng.seed(seed)

View File

@ -159,7 +159,7 @@ fn test_xoroshiro128pp_u64_in_range() {
fn test_xoroshiro128pp_int31() {
max_u31 := int(0x7FFFFFFF)
sign_mask := int(0x80000000)
sign_mask := int(u32(0x80000000))
for seed in seeds {
mut rng := &rand.PRNG(&XOROS128PPRNG{})
rng.seed(seed)
@ -175,7 +175,7 @@ fn test_xoroshiro128pp_int31() {
fn test_xoroshiro128pp_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000)
sign_mask := i64(u64(0x8000000000000000))
for seed in seeds {
mut rng := &rand.PRNG(&XOROS128PPRNG{})
rng.seed(seed)

View File

@ -155,7 +155,7 @@ hexadecimal
import strconv
a1 := u8(0xff)
b1 := i16(0xffff)
b1 := i16(u16(0xffff))
c1 := u32(0xffffffff)
d1 := u64(-1)
sc3 := '%hhx %hx %x %lx'

View File

@ -32,7 +32,7 @@ fn test_format() {
assert tmp_str == temp_s
a1 := u8(0xff)
b1 := i16(0xffff)
b1 := i16(u16(0xffff))
c1 := u32(0xffff_ffff)
d1 := u64(-1)
sc2 := '%hhu %hu %u %lu'

View File

@ -3672,6 +3672,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
tt := c.table.type_to_str(to_type)
tsize, _ := c.table.type_size(to_type.idx_type())
bit_size := tsize * 8
signed := node.expr.val[0] == `-`
value_string := match node.expr.val[0] {
`-`, `+` {
node.expr.val[1..]
@ -3680,16 +3681,63 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
node.expr.val
}
}
_, e := strconv.common_parse_uint2(value_string, 0, bit_size)
mut is_overflowed := false
v, e := strconv.common_parse_uint2(value_string, 0, bit_size)
match e {
0 {}
-3 {
// FIXME: Once integer literal is considered as hard error, remove this warn and migrate to later error
c.error('value `${node.expr.val}` overflows `${tt}`', node.pos)
is_overflowed = true
}
else {
c.error('cannot cast value `${node.expr.val}` to `${tt}`', node.pos)
}
}
// checks if integer literal's most significant bit
// alters sign bit when casting to signed integer
if !is_overflowed && to_type.is_signed() {
signed_one := match to_type.idx() {
ast.char_type_idx, ast.i8_type_idx {
u64(0xff)
}
ast.i16_type_idx {
u64(0xffff)
}
ast.int_type_idx, ast.i32_type_idx {
u64(0xffffffff)
}
ast.i64_type_idx {
u64(0xffffffffffffffff)
}
ast.isize_type_idx {
$if x64 {
u64(0xffffffffffffffff)
} $else {
u64(0xffffffff)
}
}
else {
c.error('ICE: Not a valid signed type', node.pos)
0
}
}
max_signed := (u64(1) << (bit_size - 1)) - 1
is_overflowed = v == signed_one || (signed && v - 2 == max_signed)
|| (!signed && v - 1 == max_signed)
// FIXME: Once integer literal is considered as hard error, remove this warn and migrate to later error
if is_overflowed {
c.warn('value `${node.expr.val}` overflows `${tt}`, this will be considered hard error soon',
node.pos)
}
}
// FIXME: Once integer literal is considered as hard error, uncomment this
// if is_overflowed {
// c.error('value `${node.expr.val}` overflows `${tt}`', node.pos)
// }
} else if to_type.is_float() && mut node.expr is ast.FloatLiteral {
tt := c.table.type_to_str(to_type)
strconv.atof64(node.expr.val) or {

View File

@ -0,0 +1,138 @@
vlib/v/checker/tests/overflow_int_signed_err.vv:2:2: warning: value `0xff` overflows `i8`, this will be considered hard error soon
1 | const _i8s = [
2 | i8(0xff), // converted to -1
| ~~~~~~~~
3 | i8(128), // converted to -128
4 | i8(-129), // converted to +127
vlib/v/checker/tests/overflow_int_signed_err.vv:3:2: warning: value `128` overflows `i8`, this will be considered hard error soon
1 | const _i8s = [
2 | i8(0xff), // converted to -1
3 | i8(128), // converted to -128
| ~~~~~~~
4 | i8(-129), // converted to +127
5 | i8(-0xff), // converted to +1
vlib/v/checker/tests/overflow_int_signed_err.vv:4:2: warning: value `-129` overflows `i8`, this will be considered hard error soon
2 | i8(0xff), // converted to -1
3 | i8(128), // converted to -128
4 | i8(-129), // converted to +127
| ~~~~~~~~
5 | i8(-0xff), // converted to +1
6 | ]
vlib/v/checker/tests/overflow_int_signed_err.vv:5:2: warning: value `-0xff` overflows `i8`, this will be considered hard error soon
3 | i8(128), // converted to -128
4 | i8(-129), // converted to +127
5 | i8(-0xff), // converted to +1
| ~~~~~~~~~
6 | ]
7 |
vlib/v/checker/tests/overflow_int_signed_err.vv:9:2: warning: value `0xffff` overflows `i16`, this will be considered hard error soon
7 |
8 | const _i16s = [
9 | i16(0xffff), // converted to -1
| ~~~~~~~~~~~
10 | i16(32768), // converted to -32768
11 | i16(-32769), // converted to +32767
vlib/v/checker/tests/overflow_int_signed_err.vv:10:2: warning: value `32768` overflows `i16`, this will be considered hard error soon
8 | const _i16s = [
9 | i16(0xffff), // converted to -1
10 | i16(32768), // converted to -32768
| ~~~~~~~~~~
11 | i16(-32769), // converted to +32767
12 | i16(-0xffff), // converted to +1
vlib/v/checker/tests/overflow_int_signed_err.vv:11:2: warning: value `-32769` overflows `i16`, this will be considered hard error soon
9 | i16(0xffff), // converted to -1
10 | i16(32768), // converted to -32768
11 | i16(-32769), // converted to +32767
| ~~~~~~~~~~~
12 | i16(-0xffff), // converted to +1
13 | ]
vlib/v/checker/tests/overflow_int_signed_err.vv:12:2: warning: value `-0xffff` overflows `i16`, this will be considered hard error soon
10 | i16(32768), // converted to -32768
11 | i16(-32769), // converted to +32767
12 | i16(-0xffff), // converted to +1
| ~~~~~~~~~~~~
13 | ]
14 |
vlib/v/checker/tests/overflow_int_signed_err.vv:16:2: warning: value `0xffffffff` overflows `int`, this will be considered hard error soon
14 |
15 | const _ints = [
16 | int(0xffffffff), // converted to -1
| ~~~~~~~~~~~~~~~
17 | int(2147483648), // converted to -2147483648 (overflow in 32-bit int)
18 | int(-2147483649), // converted to +2147483647 (overflow)
vlib/v/checker/tests/overflow_int_signed_err.vv:17:2: warning: value `2147483648` overflows `int`, this will be considered hard error soon
15 | const _ints = [
16 | int(0xffffffff), // converted to -1
17 | int(2147483648), // converted to -2147483648 (overflow in 32-bit int)
| ~~~~~~~~~~~~~~~
18 | int(-2147483649), // converted to +2147483647 (overflow)
19 | int(-0xffffffff), // converted to +1
vlib/v/checker/tests/overflow_int_signed_err.vv:18:2: warning: value `-2147483649` overflows `int`, this will be considered hard error soon
16 | int(0xffffffff), // converted to -1
17 | int(2147483648), // converted to -2147483648 (overflow in 32-bit int)
18 | int(-2147483649), // converted to +2147483647 (overflow)
| ~~~~~~~~~~~~~~~~
19 | int(-0xffffffff), // converted to +1
20 | ]
vlib/v/checker/tests/overflow_int_signed_err.vv:19:2: warning: value `-0xffffffff` overflows `int`, this will be considered hard error soon
17 | int(2147483648), // converted to -2147483648 (overflow in 32-bit int)
18 | int(-2147483649), // converted to +2147483647 (overflow)
19 | int(-0xffffffff), // converted to +1
| ~~~~~~~~~~~~~~~~
20 | ]
21 |
vlib/v/checker/tests/overflow_int_signed_err.vv:23:2: warning: value `0xffffffff` overflows `i32`, this will be considered hard error soon
21 |
22 | const _i32s = [
23 | i32(0xffffffff), // converted to -1
| ~~~~~~~~~~~~~~~
24 | i32(2147483648), // converted to -2147483648
25 | i32(-2147483649), // converted to +2147483647
vlib/v/checker/tests/overflow_int_signed_err.vv:24:2: warning: value `2147483648` overflows `i32`, this will be considered hard error soon
22 | const _i32s = [
23 | i32(0xffffffff), // converted to -1
24 | i32(2147483648), // converted to -2147483648
| ~~~~~~~~~~~~~~~
25 | i32(-2147483649), // converted to +2147483647
26 | i32(-0xffffffff), // converted to +1
vlib/v/checker/tests/overflow_int_signed_err.vv:25:2: warning: value `-2147483649` overflows `i32`, this will be considered hard error soon
23 | i32(0xffffffff), // converted to -1
24 | i32(2147483648), // converted to -2147483648
25 | i32(-2147483649), // converted to +2147483647
| ~~~~~~~~~~~~~~~~
26 | i32(-0xffffffff), // converted to +1
27 | ]
vlib/v/checker/tests/overflow_int_signed_err.vv:26:2: warning: value `-0xffffffff` overflows `i32`, this will be considered hard error soon
24 | i32(2147483648), // converted to -2147483648
25 | i32(-2147483649), // converted to +2147483647
26 | i32(-0xffffffff), // converted to +1
| ~~~~~~~~~~~~~~~~
27 | ]
28 |
vlib/v/checker/tests/overflow_int_signed_err.vv:30:2: warning: value `0xffffffffffffffff` overflows `i64`, this will be considered hard error soon
28 |
29 | const _i64s = [
30 | i64(0xffffffffffffffff), // converted to -1
| ~~~~~~~~~~~~~~~~~~~~~~~
31 | i64(9223372036854775808), // converted to -9223372036854775808
32 | i64(-9223372036854775809), // converted to +9223372036854775807
vlib/v/checker/tests/overflow_int_signed_err.vv:31:2: warning: value `9223372036854775808` overflows `i64`, this will be considered hard error soon
29 | const _i64s = [
30 | i64(0xffffffffffffffff), // converted to -1
31 | i64(9223372036854775808), // converted to -9223372036854775808
| ~~~~~~~~~~~~~~~~~~~~~~~~
32 | i64(-9223372036854775809), // converted to +9223372036854775807
33 | i64(-0xffffffffffffffff), // converted to +1
vlib/v/checker/tests/overflow_int_signed_err.vv:32:2: warning: value `-9223372036854775809` overflows `i64`, this will be considered hard error soon
30 | i64(0xffffffffffffffff), // converted to -1
31 | i64(9223372036854775808), // converted to -9223372036854775808
32 | i64(-9223372036854775809), // converted to +9223372036854775807
| ~~~~~~~~~~~~~~~~~~~~~~~~~
33 | i64(-0xffffffffffffffff), // converted to +1
34 | ]
vlib/v/checker/tests/overflow_int_signed_err.vv:33:2: warning: value `-0xffffffffffffffff` overflows `i64`, this will be considered hard error soon
31 | i64(9223372036854775808), // converted to -9223372036854775808
32 | i64(-9223372036854775809), // converted to +9223372036854775807
33 | i64(-0xffffffffffffffff), // converted to +1
| ~~~~~~~~~~~~~~~~~~~~~~~~
34 | ]

View File

@ -0,0 +1,34 @@
const _i8s = [
i8(0xff), // converted to -1
i8(128), // converted to -128
i8(-129), // converted to +127
i8(-0xff), // converted to +1
]
const _i16s = [
i16(0xffff), // converted to -1
i16(32768), // converted to -32768
i16(-32769), // converted to +32767
i16(-0xffff), // converted to +1
]
const _ints = [
int(0xffffffff), // converted to -1
int(2147483648), // converted to -2147483648 (overflow in 32-bit int)
int(-2147483649), // converted to +2147483647 (overflow)
int(-0xffffffff), // converted to +1
]
const _i32s = [
i32(0xffffffff), // converted to -1
i32(2147483648), // converted to -2147483648
i32(-2147483649), // converted to +2147483647
i32(-0xffffffff), // converted to +1
]
const _i64s = [
i64(0xffffffffffffffff), // converted to -1
i64(9223372036854775808), // converted to -9223372036854775808
i64(-9223372036854775809), // converted to +9223372036854775807
i64(-0xffffffffffffffff), // converted to +1
]

View File

@ -569,8 +569,8 @@ fn pe_idt_offsetof(field PeImportDirectoryTableField) i64 {
fn default_pe_idt() PeImportDirectoryTable {
return PeImportDirectoryTable{
forwarder_chain: i32(0xffffffff)
time_date_stamp: i32(0xffffffff)
forwarder_chain: i32(u32(0xffffffff))
time_date_stamp: i32(u32(0xffffffff))
}
}