From 3d4cd0bbc0db7eee82d8acbad85757082b7941c7 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 10 Jul 2019 16:05:39 +0200 Subject: [PATCH] check integer const overflow at compilation --- compiler/parser.v | 8 ++++++-- compiler/table.v | 20 ++++++++++++++++++++ vlib/builtin/string.v | 4 ++++ vlib/math/math.v | 15 +++++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/compiler/parser.v b/compiler/parser.v index 66ab24ac45..ee6c870d30 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -1994,6 +1994,9 @@ fn (p mut Parser) factor() string { typ = 'f32' // typ = 'f64' // TODO } + if p.expected_type != '' && !is_valid_int_const(p.lit, p.expected_type) { + p.error('constant `$p.lit` overflows `$p.expected_type`') + } p.gen(p.lit) p.fgen(p.lit) case Token.minus: @@ -2252,7 +2255,7 @@ fn (p mut Parser) string_expr() { // '$age'! means the user wants this to be a tmp string (uses global buffer, no allocation, // won't be used again) if p.tok == .not { - p.next() + p.check(.not) p.gen('_STR_TMP($format$args)') } else { @@ -2550,7 +2553,9 @@ fn (p mut Parser) cast(typ string) string { p.next() } p.check(.lpar) + p.expected_type = typ expr_typ := p.bool_expression() + p.expected_type = '' p.check(.rpar) // `string(buffer)` => `tos2(buffer)` if typ == 'string' && (expr_typ == 'byte*' || expr_typ == 'byteptr') { @@ -2562,7 +2567,6 @@ fn (p mut Parser) cast(typ string) string { } else { p.cgen.set_placeholder(pos, '($typ)(') - // p.fgen(typ) } p.gen(')') return typ diff --git a/compiler/table.v b/compiler/table.v index dbca9145e4..82a49b1a06 100644 --- a/compiler/table.v +++ b/compiler/table.v @@ -4,6 +4,8 @@ module main +import math + struct Table { mut: types []Type @@ -637,3 +639,21 @@ fn (table &Table) cgen_name_type_pair(name, typ string) string { return '$typ $name' } +fn is_valid_int_const(val, typ string) bool { + x := val.int() + switch typ { + case 'byte', 'u8': return 0 <= x && x <= math.MaxU8 + case 'u16': return 0 <= x && x <= math.MaxU16 + case 'u32': return 0 <= x && x <= math.MaxU32 + //case 'u64': return 0 <= x && x <= math.MaxU64 + ////////////// + case 'i8': return math.MinI8 <= x && x <= math.MaxI8 + case 'i16': return math.MinI16 <= x && x <= math.MaxI16 + case 'int', 'i32': return math.MinI32 <= x && x <= math.MaxI32 + //case 'i64': + //x64 := val.i64() + //return i64(-(1<<63)) <= x64 && x64 <= i64((1<<63)-1) + } + return true +} + diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index f16b32f399..e38447b8f8 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -133,6 +133,10 @@ pub fn (s string) int() int { return C.atoi(s.str) } +pub fn (s string) i64() i64 { + return C.atoll(s.str) +} + pub fn (s string) f32() f32 { return C.atof(s.str) } diff --git a/vlib/math/math.v b/vlib/math/math.v index 543109c57a..42063d4301 100644 --- a/vlib/math/math.v +++ b/vlib/math/math.v @@ -22,6 +22,21 @@ const ( Log10E = 1.0 / Ln10 ) +const ( + MaxI8 = (1<<7) - 1 + MinI8 = -1 << 7 + MaxI16 = (1<<15) - 1 + MinI16 = -1 << 15 + MaxI32 = (1<<31) - 1 + MinI32 = -1 << 31 +// MaxI64 = ((1<<63) - 1) +// MinI64 = (-(1 << 63) ) + MaxU8 = (1<<8) - 1 + MaxU16 = (1<<16) - 1 + MaxU32 = (1<<32) - 1 + MaxU64 = (1<<64) - 1 +) + // Returns the absolute value. pub fn abs(a f64) f64 { if a < 0 {