Skip to content

Commit f873334

Browse files
authored
Merge pull request #3690 from diffblue/shl-overflow2
signed left-shift overflow depends on standard version
2 parents b697346 + ae78609 commit f873334

File tree

4 files changed

+39
-6
lines changed

4 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: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Author: Daniel Kroening, [email protected]
1717
#include <util/array_name.h>
1818
#include <util/base_type.h>
1919
#include <util/c_types.h>
20+
#include <util/config.h>
2021
#include <util/cprover_prefix.h>
2122
#include <util/expr_util.h>
2223
#include <util/find_symbols.h>
@@ -662,12 +663,40 @@ void goto_checkt::integer_overflow_check(
662663

663664
const exprt op_ext_shifted = shl_exprt(op_ext, distance);
664665

665-
// get top bits of the shifted operand
666+
// The semantics of signed left shifts are contentious for the case
667+
// that a '1' is shifted into the signed bit.
668+
// Assuming 32-bit integers, 1<<31 is implementation-defined
669+
// in ANSI C and C++98, but is explicitly undefined by C99,
670+
// C11 and C++11.
671+
bool allow_shift_into_sign_bit = true;
672+
673+
if(mode == ID_C)
674+
{
675+
if(
676+
config.ansi_c.c_standard == configt::ansi_ct::c_standardt::C99 ||
677+
config.ansi_c.c_standard == configt::ansi_ct::c_standardt::C11)
678+
{
679+
allow_shift_into_sign_bit = false;
680+
}
681+
}
682+
else if(mode == ID_cpp)
683+
{
684+
if(
685+
config.cpp.cpp_standard == configt::cppt::cpp_standardt::CPP11 ||
686+
config.cpp.cpp_standard == configt::cppt::cpp_standardt::CPP14)
687+
{
688+
allow_shift_into_sign_bit = false;
689+
}
690+
}
691+
692+
const unsigned number_of_top_bits =
693+
allow_shift_into_sign_bit ? op_width : op_width + 1;
694+
666695
const exprt top_bits = extractbits_exprt(
667696
op_ext_shifted,
668697
new_type.get_width() - 1,
669-
op_width - 1,
670-
unsignedbv_typet(op_width + 1));
698+
new_type.get_width() - number_of_top_bits,
699+
unsignedbv_typet(number_of_top_bits));
671700

672701
const exprt top_bits_zero =
673702
equal_exprt(top_bits, from_integer(0, top_bits.type()));

src/ansi-c/c_preprocess.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ bool c_preprocess_gcc_clang(
610610
switch(config.ansi_c.c_standard)
611611
{
612612
case configt::ansi_ct::c_standardt::C89:
613-
argv.push_back("-std=gnu++89");
613+
argv.push_back("-std=gnu89");
614614
break;
615615

616616
case configt::ansi_ct::c_standardt::C99:

0 commit comments

Comments
 (0)