Skip to content

Commit fec7fb8

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 b326498 commit fec7fb8

File tree

3 files changed

+34
-4
lines changed

3 files changed

+34
-4
lines changed

regression/cbmc/Overflow_Leftshift1/main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 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$

src/analyses/goto_check.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Author: Daniel Kroening, [email protected]
1818
#include <util/base_type.h>
1919
#include <util/cprover_prefix.h>
2020
#include <util/c_types.h>
21+
#include <util/config.h>
2122
#include <util/expr_util.h>
2223
#include <util/find_symbols.h>
2324
#include <util/guard.h>
@@ -634,12 +635,38 @@ 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(config.ansi_c.c_standard == configt::ansi_ct::c_standardt::C99 ||
648+
config.ansi_c.c_standard == configt::ansi_ct::c_standardt::C11)
649+
{
650+
allow_shift_into_sign_bit = false;
651+
}
652+
}
653+
else if(mode == ID_cpp)
654+
{
655+
if(config.cpp.cpp_standard == configt::cppt::cpp_standardt::CPP11 ||
656+
config.cpp.cpp_standard == configt::cppt::cpp_standardt::CPP14)
657+
{
658+
allow_shift_into_sign_bit = false;
659+
}
660+
}
661+
662+
const unsigned number_of_top_bits =
663+
allow_shift_into_sign_bit ? op_width : op_width + 1;
664+
638665
const exprt top_bits = extractbits_exprt(
639666
op_ext_shifted,
640667
new_type.get_width() - 1,
641-
op_width - 1,
642-
unsignedbv_typet(op_width + 1));
668+
new_type.get_width() - number_of_top_bits,
669+
unsignedbv_typet(number_of_top_bits));
643670

644671
const exprt top_bits_zero =
645672
equal_exprt(top_bits, from_integer(0, top_bits.type()));

0 commit comments

Comments
 (0)