Skip to content

Commit 3be9b5e

Browse files
author
Daniel Kroening
committed
implement criteria for shl overflow in goto_check
The current implementation generates an overflow-shl predicate, which is then interpreted by the solver APIs. This has the disadvantage that the predicate has semantics that are both complicated and highly language-dependent, which is not a good fit for a solver. The new implementation defines the meaning of signed left shift overflows in goto-check, similar as it is already done for division and unary minus. This is covered by an existing test: regression/cbmc/Overflow_Leftshift1/test.desc
1 parent 052a8d3 commit 3be9b5e

File tree

3 files changed

+78
-2
lines changed

3 files changed

+78
-2
lines changed

regression/cbmc/Overflow_Leftshift1/main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,8 @@ int main()
1717
// overflow
1818
s = 1 << x;
1919

20+
// distance too far, not an overflow
21+
s = s << 100;
22+
2023
return 0;
2124
}

scripts/delete_failing_smt2_solver_tests

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ rm Linking7/test.desc
3737
rm Linking7/member-name-mismatch.desc
3838
rm Malloc23/test.desc
3939
rm Multi_Dimensional_Array2/test.desc
40-
rm Overflow_Leftshift1/test.desc
41-
rm Overflow_Subtraction1/test.desc
4240
rm Pointer_Arithmetic11/test.desc
4341
rm Pointer_byte_extract2/test.desc
4442
rm Pointer_byte_extract5/no-simplify.desc

src/analyses/goto_check.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,81 @@ void goto_checkt::integer_overflow_check(
589589

590590
return;
591591
}
592+
else if(expr.id() == ID_shl)
593+
{
594+
if(type.id() == ID_signedbv)
595+
{
596+
const auto &shl_expr = to_shl_expr(expr);
597+
const auto &op = shl_expr.op();
598+
const auto &op_type = to_signedbv_type(type);
599+
const auto op_width = op_type.get_width();
600+
const auto &distance = shl_expr.distance();
601+
const auto &distance_type = distance.type();
602+
603+
// a left shift of a negative value is undefined;
604+
// yet this isn't an overflow
605+
exprt neg_value_shift;
606+
607+
if(op_type.id() == ID_unsignedbv)
608+
neg_value_shift = false_exprt();
609+
else
610+
neg_value_shift =
611+
binary_relation_exprt(op, ID_lt, from_integer(0, op_type));
612+
613+
// a shift with negative distance is undefined;
614+
// yet this isn't an overflow
615+
exprt neg_dist_shift;
616+
617+
if(distance_type.id() == ID_unsignedbv)
618+
neg_dist_shift = false_exprt();
619+
else
620+
neg_dist_shift =
621+
binary_relation_exprt(op, ID_lt, from_integer(0, distance_type));
622+
623+
// shifting a non-zero value by more than its width is undefined;
624+
// yet this isn't an overflow
625+
const exprt dist_too_large = binary_predicate_exprt(
626+
distance, ID_gt, from_integer(op_width, distance_type));
627+
628+
const exprt op_zero = equal_exprt(op, from_integer(0, op_type));
629+
630+
auto new_type = to_bitvector_type(op_type);
631+
new_type.set_width(op_width * 2);
632+
633+
const exprt op_ext = typecast_exprt(op, new_type);
634+
635+
const exprt op_ext_shifted = shl_exprt(op_ext, distance);
636+
637+
// get top bits of the shifted operand
638+
const exprt top_bits = extractbits_exprt(
639+
op_ext_shifted,
640+
new_type.get_width() - 1,
641+
op_width - 1,
642+
unsignedbv_typet(op_width + 1));
643+
644+
const exprt top_bits_zero =
645+
equal_exprt(top_bits, from_integer(0, top_bits.type()));
646+
647+
// a negative distance shift isn't an overflow;
648+
// a negative value shift isn't an overflow;
649+
// a shift that's too far isn't an overflow;
650+
// a shift of zero isn't overflow;
651+
// else check the top bits
652+
add_guarded_claim(
653+
disjunction({neg_value_shift,
654+
neg_dist_shift,
655+
dist_too_large,
656+
op_zero,
657+
top_bits_zero}),
658+
"arithmetic overflow on signed shl",
659+
"overflow",
660+
expr.find_source_location(),
661+
expr,
662+
guard);
663+
}
664+
665+
return;
666+
}
592667

593668
exprt overflow("overflow-"+expr.id_string(), bool_typet());
594669
overflow.operands()=expr.operands();

0 commit comments

Comments
 (0)