Skip to content

Commit 652c959

Browse files
committed
Fix signed integer literal overflow
1 parent 4cc6f25 commit 652c959

File tree

3 files changed

+103
-1
lines changed

3 files changed

+103
-1
lines changed

vlib/v/checker/checker.v

+16-1
Original file line numberDiff line numberDiff line change
@@ -3651,6 +3651,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
36513651
tt := c.table.type_to_str(to_type)
36523652
tsize, _ := c.table.type_size(to_type.idx_type())
36533653
bit_size := tsize * 8
3654+
signed := node.expr.val[0] == `-`
36543655
value_string := match node.expr.val[0] {
36553656
`-`, `+` {
36563657
node.expr.val[1..]
@@ -3659,7 +3660,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
36593660
node.expr.val
36603661
}
36613662
}
3662-
_, e := strconv.common_parse_uint2(value_string, 0, bit_size)
3663+
value, e := strconv.common_parse_uint2(value_string, 0, bit_size)
36633664
match e {
36643665
0 {}
36653666
-3 {
@@ -3669,6 +3670,20 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
36693670
c.error('cannot cast value `${node.expr.val}` to `${tt}`', node.pos)
36703671
}
36713672
}
3673+
3674+
// checks if integer literal's most significant bit occupies sign bit when casting to
3675+
// signed integer, we determine the condition by checking most significant bit's index
3676+
if !signed && to_type.is_signed() {
3677+
mut v := value
3678+
mut ms_bit_index := 0
3679+
for v != 0 {
3680+
v >>= 1
3681+
ms_bit_index += 1
3682+
}
3683+
if ms_bit_index == bit_size {
3684+
c.error('value `${node.expr.val} overflows `${tt}`', node.pos)
3685+
}
3686+
}
36723687
} else if to_type.is_float() && mut node.expr is ast.FloatLiteral {
36733688
tt := c.table.type_to_str(to_type)
36743689
strconv.atof64(node.expr.val) or {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
vlib/v/checker/tests/overflow_int_signed_err.vv:2:2: error: value `0xff overflows `i8`
2+
1 | i8s := [
3+
2 | i8(0xff) // converted to -1
4+
| ~~~~~~~~
5+
3 | i8(128) // converted to -128
6+
4 | i8(-129) // converted to +127
7+
vlib/v/checker/tests/overflow_int_signed_err.vv:3:2: error: value `128 overflows `i8`
8+
1 | i8s := [
9+
2 | i8(0xff) // converted to -1
10+
3 | i8(128) // converted to -128
11+
| ~~~~~~~
12+
4 | i8(-129) // converted to +127
13+
5 | i8(-0xff) // converted to +1
14+
vlib/v/checker/tests/overflow_int_signed_err.vv:9:2: error: value `0xffff overflows `i16`
15+
7 |
16+
8 | i16s := [
17+
9 | i16(0xffff) // converted to -1
18+
| ~~~~~~~~~~~
19+
10 | i16(32768) // converted to -32768
20+
11 | i16(-32769) // converted to +32767
21+
vlib/v/checker/tests/overflow_int_signed_err.vv:10:2: error: value `32768 overflows `i16`
22+
8 | i16s := [
23+
9 | i16(0xffff) // converted to -1
24+
10 | i16(32768) // converted to -32768
25+
| ~~~~~~~~~~
26+
11 | i16(-32769) // converted to +32767
27+
12 | i16(-0xffff) // converted to +1
28+
vlib/v/checker/tests/overflow_int_signed_err.vv:16:2: error: value `0xffffffff overflows `int`
29+
14 |
30+
15 | ints := [
31+
16 | int(0xffffffff) // converted to -1
32+
| ~~~~~~~~~~~~~~~
33+
17 | int(2147483648) // converted to -2147483648
34+
18 | int(-2147483649) // converted to +2147483647
35+
vlib/v/checker/tests/overflow_int_signed_err.vv:17:2: error: value `2147483648 overflows `int`
36+
15 | ints := [
37+
16 | int(0xffffffff) // converted to -1
38+
17 | int(2147483648) // converted to -2147483648
39+
| ~~~~~~~~~~~~~~~
40+
18 | int(-2147483649) // converted to +2147483647
41+
19 | int(-0xffffffff) // converted to +1
42+
vlib/v/checker/tests/overflow_int_signed_err.vv:23:2: error: value `0xffffffffffffffff overflows `i64`
43+
21 |
44+
22 | i64s := [
45+
23 | i64(0xffffffffffffffff) // converted to -1
46+
| ~~~~~~~~~~~~~~~~~~~~~~~
47+
24 | i64(9223372036854775808) // converted to -9223372036854775808
48+
25 | i64(-9223372036854775809) // converted to +9223372036854775807
49+
vlib/v/checker/tests/overflow_int_signed_err.vv:24:2: error: value `9223372036854775808 overflows `i64`
50+
22 | i64s := [
51+
23 | i64(0xffffffffffffffff) // converted to -1
52+
24 | i64(9223372036854775808) // converted to -9223372036854775808
53+
| ~~~~~~~~~~~~~~~~~~~~~~~~
54+
25 | i64(-9223372036854775809) // converted to +9223372036854775807
55+
26 | i64(-0xffffffffffffffff) // converted to +1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
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
6+
]
7+
8+
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
13+
]
14+
15+
ints := [
16+
int(0xffffffff), // converted to -1
17+
int(2147483648), // converted to -2147483648
18+
int(-2147483649), // converted to +2147483647
19+
int(-0xffffffff), // converted to +1
20+
]
21+
22+
i64s := [
23+
i64(0xffffffffffffffff), // converted to -1
24+
i64(9223372036854775808), // converted to -9223372036854775808
25+
i64(-9223372036854775809), // converted to +9223372036854775807
26+
i64(-0xffffffffffffffff), // converted to +1
27+
]
28+
29+
println('i8s: ${i8s}')
30+
println('i16s: ${i16s}')
31+
println('ints: ${ints}')
32+
println('i64s: ${i64s}')

0 commit comments

Comments
 (0)