Skip to content

Commit 6e68a12

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 7831e81 commit 6e68a12

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

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: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,74 @@ 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+
// an undefined shift of a non-zero value always results in overflow
624+
const exprt undef = binary_predicate_exprt(
625+
distance, ID_gt, from_integer(op_width, distance_type));
626+
627+
const exprt op_zero = equal_exprt(op, from_integer(0, op_type));
628+
629+
auto new_type = to_bitvector_type(op_type);
630+
new_type.set_width(op_width * 2);
631+
632+
const exprt op_ext = typecast_exprt(op, new_type);
633+
634+
const exprt op_ext_shifted = shl_exprt(op_ext, distance);
635+
636+
// get top bits of the shifted operand
637+
const exprt top_bits = extractbits_exprt(
638+
op_ext_shifted,
639+
new_type.get_width() - 1,
640+
op_width - 1,
641+
unsignedbv_typet(op_width + 1));
642+
643+
const exprt top_bits_zero =
644+
equal_exprt(top_bits, from_integer(0, top_bits.type()));
645+
646+
// a negative distance shift isn't an overflow;
647+
// a shift of zero isn't overflow;
648+
// else check the top bits
649+
add_guarded_claim(
650+
or_exprt(neg_value_shift, neg_dist_shift, op_zero, top_bits_zero),
651+
"arithmetic overflow on signed shl",
652+
"overflow",
653+
expr.find_source_location(),
654+
expr,
655+
guard);
656+
}
657+
658+
return;
659+
}
592660

593661
exprt overflow("overflow-"+expr.id_string(), bool_typet());
594662
overflow.operands()=expr.operands();

0 commit comments

Comments
 (0)