Skip to content

Commit 689b2da

Browse files
author
Daniel Kroening
committed
signed left-shift overflow depends on standard version
The semantics of signed left shifts are contentious for the case that a '1' is shifted into the signed bit. Assuming 32-bit integers, 1<<31 is implementation-defined in ANSI C and C++98, but is explicitly undefined by C99, C11 and C++11.
1 parent 568845b commit 689b2da

File tree

3 files changed

+39
-6
lines changed

3 files changed

+39
-6
lines changed

regression/cbmc/Overflow_Leftshift1/main.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ int main()
33
unsigned char x;
44

55
// signed, owing to promotion, and may overflow
6-
unsigned r=x << ((sizeof(unsigned)-1)*8);
6+
unsigned r = x << ((sizeof(unsigned) - 1) * 8 + 1);
77

88
// signed, owing to promotion, and cannot overflow
99
r=x << ((sizeof(unsigned)-1)*8-1);
@@ -20,5 +20,8 @@ int main()
2020
// distance too far, not an overflow
2121
s = s << 100;
2222

23+
// not an overflow in ANSI-C, but undefined in C99
24+
s = 1 << (sizeof(int) * 8 - 1);
25+
2326
return 0;
2427
}

regression/cbmc/Overflow_Leftshift1/test.desc renamed to regression/cbmc/Overflow_Leftshift1/test-c89.desc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CORE
22
main.c
3-
--signed-overflow-check
3+
--signed-overflow-check --c89
44
^EXIT=10$
55
^SIGNAL=0$
66
^\[.*\] line 6 arithmetic overflow on signed shl in .*: FAILURE$
@@ -13,3 +13,4 @@ main.c
1313
^warning: ignoring
1414
^\[.*\] line 12 arithmetic overflow on signed shl in .*: .*
1515
^\[.*\] line 21 arithmetic overflow on signed shl in .*: .*
16+
^\[.*\] line 24 arithmetic overflow on signed shl in .*: .*

src/analyses/goto_check.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ Author: Daniel Kroening, [email protected]
1616
#include <util/arith_tools.h>
1717
#include <util/array_name.h>
1818
#include <util/base_type.h>
19-
#include <util/cprover_prefix.h>
2019
#include <util/c_types.h>
20+
#include <util/config.h>
21+
#include <util/cprover_prefix.h>
2122
#include <util/expr_util.h>
2223
#include <util/find_symbols.h>
2324
#include <util/guard.h>
@@ -634,12 +635,40 @@ void goto_checkt::integer_overflow_check(
634635

635636
const exprt op_ext_shifted = shl_exprt(op_ext, distance);
636637

637-
// get top bits of the shifted operand
638+
// The semantics of signed left shifts are contentious for the case
639+
// that a '1' is shifted into the signed bit.
640+
// Assuming 32-bit integers, 1<<31 is implementation-defined
641+
// in ANSI C and C++98, but is explicitly undefined by C99,
642+
// C11 and C++11.
643+
bool allow_shift_into_sign_bit = true;
644+
645+
if(mode == ID_C)
646+
{
647+
if(
648+
config.ansi_c.c_standard == configt::ansi_ct::c_standardt::C99 ||
649+
config.ansi_c.c_standard == configt::ansi_ct::c_standardt::C11)
650+
{
651+
allow_shift_into_sign_bit = false;
652+
}
653+
}
654+
else if(mode == ID_cpp)
655+
{
656+
if(
657+
config.cpp.cpp_standard == configt::cppt::cpp_standardt::CPP11 ||
658+
config.cpp.cpp_standard == configt::cppt::cpp_standardt::CPP14)
659+
{
660+
allow_shift_into_sign_bit = false;
661+
}
662+
}
663+
664+
const unsigned number_of_top_bits =
665+
allow_shift_into_sign_bit ? op_width : op_width + 1;
666+
638667
const exprt top_bits = extractbits_exprt(
639668
op_ext_shifted,
640669
new_type.get_width() - 1,
641-
op_width - 1,
642-
unsignedbv_typet(op_width + 1));
670+
new_type.get_width() - number_of_top_bits,
671+
unsignedbv_typet(number_of_top_bits));
643672

644673
const exprt top_bits_zero =
645674
equal_exprt(top_bits, from_integer(0, top_bits.type()));

0 commit comments

Comments
 (0)