Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Justify signed integer literal overflow error when most significant bit occupies signed bit #23919

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion vlib/builtin/int_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
4 changes: 2 additions & 2 deletions vlib/builtin/string_int_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
4 changes: 2 additions & 2 deletions vlib/rand/mt19937/mt19937_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions vlib/rand/musl/musl_rng_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions vlib/rand/pcg32/pcg32_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions vlib/rand/random_numbers_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions vlib/rand/splitmix64/splitmix64_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions vlib/rand/sys/system_rng_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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{})
Expand All @@ -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{})
Expand Down
4 changes: 2 additions & 2 deletions vlib/rand/wyrand/wyrand_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions vlib/rand/xoroshiro128pp/xoros128pp_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion vlib/strconv/format.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
2 changes: 1 addition & 1 deletion vlib/strconv/format_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
44 changes: 42 additions & 2 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -3651,6 +3651,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..]
Expand All @@ -3659,16 +3660,55 @@ 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 {
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)
}

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 {
Expand Down
139 changes: 139 additions & 0 deletions vlib/v/checker/tests/overflow_int_signed_err.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
vlib/v/checker/tests/overflow_int_signed_err.vv:2:2: error: value `0xff` overflows `i8`
1 | 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: error: value `128` overflows `i8`
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
vlib/v/checker/tests/overflow_int_signed_err.vv:4:2: error: value `-129` overflows `i8`
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: error: value `-0xff` overflows `i8`
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: error: value `0xffff` overflows `i16`
7 |
8 | 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: error: value `32768` overflows `i16`
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
vlib/v/checker/tests/overflow_int_signed_err.vv:11:2: error: value `-32769` overflows `i16`
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: error: value `-0xffff` overflows `i16`
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: error: value `0xffffffff` overflows `int`
14 |
15 | 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: error: value `2147483648` overflows `int`
15 | 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: error: value `-2147483649` overflows `int`
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: error: value `-0xffffffff` overflows `int`
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: error: value `0xffffffff` overflows `i32`
21 |
22 | 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: error: value `2147483648` overflows `i32`
22 | 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: error: value `-2147483649` overflows `i32`
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: error: value `-0xffffffff` overflows `i32`
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: error: value `0xffffffffffffffff` overflows `i64`
28 |
29 | 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: error: value `9223372036854775808` overflows `i64`
29 | 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: error: value `-9223372036854775809` overflows `i64`
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: error: value `-0xffffffffffffffff` overflows `i64`
31 | i64(9223372036854775808), // converted to -9223372036854775808
32 | i64(-9223372036854775809), // converted to +9223372036854775807
33 | i64(-0xffffffffffffffff), // converted to +1
| ~~~~~~~~~~~~~~~~~~~~~~~~
34 | ]
35 |
Loading
Loading