@@ -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