Skip to content

Commit 1b6d8d9

Browse files
authored
Merge pull request #5897 from tautschnig/overflow-exprt
Add {binary,unary_overflow_exprt}
2 parents e116df1 + 5f3a55d commit 1b6d8d9

File tree

8 files changed

+206
-54
lines changed

8 files changed

+206
-54
lines changed

scripts/expected_doxygen_warnings.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ warning: Included by graph for 'irep.h' not generated, too many nodes (62), thre
9393
warning: Included by graph for 'message.h' not generated, too many nodes (117), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
9494
warning: Included by graph for 'namespace.h' not generated, too many nodes (109), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
9595
warning: Included by graph for 'pointer_expr.h' not generated, too many nodes (117), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
96-
warning: Included by graph for 'prefix.h' not generated, too many nodes (86), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
96+
warning: Included by graph for 'prefix.h' not generated, too many nodes (85), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
9797
warning: Included by graph for 'simplify_expr.h' not generated, too many nodes (77), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
9898
warning: Included by graph for 'std_code.h' not generated, too many nodes (78), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
9999
warning: Included by graph for 'std_expr.h' not generated, too many nodes (243), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.

src/analyses/goto_check.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -872,29 +872,40 @@ void goto_checkt::integer_overflow_check(
872872
tmp.operands().resize(i);
873873
}
874874

875-
overflow.operands().resize(2);
876-
overflow.op0()=tmp;
877-
overflow.op1()=expr.operands()[i];
878-
879875
std::string kind=
880876
type.id()==ID_unsignedbv?"unsigned":"signed";
881877

882878
add_guarded_property(
883-
not_exprt(overflow),
879+
not_exprt{binary_overflow_exprt{tmp, expr.id(), expr.operands()[i]}},
884880
"arithmetic overflow on " + kind + " " + expr.id_string(),
885881
"overflow",
886882
expr.find_source_location(),
887883
expr,
888884
guard);
889885
}
890886
}
887+
else if(expr.operands().size() == 2)
888+
{
889+
std::string kind = type.id() == ID_unsignedbv ? "unsigned" : "signed";
890+
891+
const binary_exprt &bexpr = to_binary_expr(expr);
892+
add_guarded_property(
893+
not_exprt{binary_overflow_exprt{bexpr.lhs(), expr.id(), bexpr.rhs()}},
894+
"arithmetic overflow on " + kind + " " + expr.id_string(),
895+
"overflow",
896+
expr.find_source_location(),
897+
expr,
898+
guard);
899+
}
891900
else
892901
{
902+
PRECONDITION(expr.id() == ID_unary_minus);
903+
893904
std::string kind=
894905
type.id()==ID_unsignedbv?"unsigned":"signed";
895906

896907
add_guarded_property(
897-
not_exprt(overflow),
908+
not_exprt{unary_overflow_exprt{expr.id(), to_unary_expr(expr).op()}},
898909
"arithmetic overflow on " + kind + " " + expr.id_string(),
899910
"overflow",
900911
expr.find_source_location(),

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2925,8 +2925,7 @@ exprt c_typecheck_baset::do_special_functions(
29252925
identifier == CPROVER_PREFIX "overflow_minus" ||
29262926
identifier == CPROVER_PREFIX "overflow_mult" ||
29272927
identifier == CPROVER_PREFIX "overflow_plus" ||
2928-
identifier == CPROVER_PREFIX "overflow_shl" ||
2929-
identifier == CPROVER_PREFIX "overflow_unary_minus")
2928+
identifier == CPROVER_PREFIX "overflow_shl")
29302929
{
29312930
exprt overflow{identifier, typet{}, exprt::operandst{expr.arguments()}};
29322931
overflow.add_source_location() = f_op.source_location();
@@ -2951,15 +2950,22 @@ exprt c_typecheck_baset::do_special_functions(
29512950
overflow.id(ID_shl);
29522951
typecheck_expr_shifts(to_shift_expr(overflow));
29532952
}
2954-
else if(identifier == CPROVER_PREFIX "overflow_unary_minus")
2955-
{
2956-
overflow.id(ID_unary_minus);
2957-
typecheck_expr_unary_arithmetic(overflow);
2958-
}
29592953

2960-
overflow.id("overflow-" + overflow.id_string());
2961-
overflow.type() = bool_typet{};
2962-
return overflow;
2954+
binary_overflow_exprt of{
2955+
overflow.operands()[0], overflow.id(), overflow.operands()[1]};
2956+
of.add_source_location() = overflow.source_location();
2957+
return std::move(of);
2958+
}
2959+
else if(identifier == CPROVER_PREFIX "overflow_unary_minus")
2960+
{
2961+
exprt tmp{ID_unary_minus, typet{}, exprt::operandst{expr.arguments()}};
2962+
tmp.add_source_location() = f_op.source_location();
2963+
2964+
typecheck_expr_unary_arithmetic(tmp);
2965+
2966+
unary_overflow_exprt overflow{ID_unary_minus, tmp.operands().front()};
2967+
overflow.add_source_location() = tmp.source_location();
2968+
return std::move(overflow);
29632969
}
29642970
else if(identifier == CPROVER_PREFIX "enum_is_in_range")
29652971
{

src/goto-instrument/accelerate/overflow_instrumenter.cpp

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ Author: Matt Lewis
1313

1414
#include <iostream>
1515

16-
#include <util/std_expr.h>
17-
#include <util/std_code.h>
1816
#include <util/arith_tools.h>
17+
#include <util/bitvector_expr.h>
1918
#include <util/simplify_expr.h>
19+
#include <util/std_code.h>
20+
#include <util/std_expr.h>
2021

2122
#include <goto-programs/goto_program.h>
2223

@@ -211,38 +212,25 @@ void overflow_instrumentert::overflow_expr(
211212
expr.id()==ID_mult)
212213
{
213214
// A generic arithmetic operation.
214-
multi_ary_exprt overflow(
215-
"overflow-" + expr.id_string(), expr.operands(), bool_typet());
216-
217-
if(expr.operands().size()>=3)
215+
// The overflow checks are binary.
216+
for(std::size_t i = 1; i < expr.operands().size(); i++)
218217
{
219-
// The overflow checks are binary.
220-
for(std::size_t i=1; i<expr.operands().size(); i++)
221-
{
222-
exprt tmp;
218+
exprt tmp;
223219

224-
if(i==1)
225-
{
226-
tmp = to_multi_ary_expr(expr).op0();
227-
}
228-
else
229-
{
230-
tmp=expr;
231-
tmp.operands().resize(i);
232-
}
220+
if(i == 1)
221+
{
222+
tmp = to_multi_ary_expr(expr).op0();
223+
}
224+
else
225+
{
226+
tmp = expr;
227+
tmp.operands().resize(i);
228+
}
233229

234-
overflow.operands().resize(2);
235-
overflow.op0()=tmp;
236-
overflow.op1()=expr.operands()[i];
230+
binary_overflow_exprt overflow{tmp, expr.id(), expr.operands()[i]};
237231

238-
fix_types(to_binary_expr(overflow));
232+
fix_types(overflow);
239233

240-
cases.insert(overflow);
241-
}
242-
}
243-
else
244-
{
245-
fix_types(to_binary_expr(overflow));
246234
cases.insert(overflow);
247235
}
248236
}

src/solvers/flattening/boolbv.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ Author: Daniel Kroening, [email protected]
1717
#include <util/floatbv_expr.h>
1818
#include <util/magic.h>
1919
#include <util/mp_arith.h>
20-
#include <util/prefix.h>
2120
#include <util/replace_expr.h>
2221
#include <util/std_expr.h>
2322
#include <util/std_types.h>
@@ -413,8 +412,13 @@ literalt boolbvt::convert_rest(const exprt &expr)
413412
return convert_reduction(to_unary_expr(expr));
414413
else if(expr.id()==ID_onehot || expr.id()==ID_onehot0)
415414
return convert_onehot(to_unary_expr(expr));
416-
else if(has_prefix(expr.id_string(), "overflow-"))
415+
else if(
416+
expr.id() == ID_overflow_plus || expr.id() == ID_overflow_mult ||
417+
expr.id() == ID_overflow_minus || expr.id() == ID_overflow_shl ||
418+
expr.id() == ID_overflow_unary_minus)
419+
{
417420
return convert_overflow(expr);
421+
}
418422
else if(expr.id()==ID_isnan)
419423
{
420424
const auto &op = to_unary_expr(expr).op();

src/util/bitvector_expr.h

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,4 +677,145 @@ inline popcount_exprt &to_popcount_expr(exprt &expr)
677677
return ret;
678678
}
679679

680+
/// \brief A Boolean expression returning true, iff operation \c kind would
681+
/// result in an overflow when applied to operands \c lhs and \c rhs.
682+
class binary_overflow_exprt : public binary_predicate_exprt
683+
{
684+
public:
685+
binary_overflow_exprt(exprt _lhs, const irep_idt &kind, exprt _rhs)
686+
: binary_predicate_exprt(
687+
std::move(_lhs),
688+
"overflow-" + id2string(kind),
689+
std::move(_rhs))
690+
{
691+
}
692+
693+
static void check(
694+
const exprt &expr,
695+
const validation_modet vm = validation_modet::INVARIANT)
696+
{
697+
binary_exprt::check(expr, vm);
698+
699+
if(expr.id() != ID_overflow_shl)
700+
{
701+
const binary_exprt &binary_expr = to_binary_expr(expr);
702+
DATA_CHECK(
703+
vm,
704+
binary_expr.lhs().type() == binary_expr.rhs().type(),
705+
"operand types must match");
706+
}
707+
}
708+
709+
static void validate(
710+
const exprt &expr,
711+
const namespacet &,
712+
const validation_modet vm = validation_modet::INVARIANT)
713+
{
714+
check(expr, vm);
715+
}
716+
};
717+
718+
template <>
719+
inline bool can_cast_expr<binary_overflow_exprt>(const exprt &base)
720+
{
721+
return base.id() == ID_overflow_plus || base.id() == ID_overflow_mult ||
722+
base.id() == ID_overflow_minus || base.id() == ID_overflow_shl;
723+
}
724+
725+
inline void validate_expr(const binary_overflow_exprt &value)
726+
{
727+
validate_operands(
728+
value, 2, "binary overflow expression must have two operands");
729+
}
730+
731+
/// \brief Cast an exprt to a \ref binary_overflow_exprt
732+
///
733+
/// \a expr must be known to be \ref binary_overflow_exprt.
734+
///
735+
/// \param expr: Source expression
736+
/// \return Object of type \ref binary_overflow_exprt
737+
inline const binary_overflow_exprt &to_binary_overflow_expr(const exprt &expr)
738+
{
739+
PRECONDITION(
740+
expr.id() == ID_overflow_plus || expr.id() == ID_overflow_mult ||
741+
expr.id() == ID_overflow_minus || expr.id() == ID_overflow_shl);
742+
const binary_overflow_exprt &ret =
743+
static_cast<const binary_overflow_exprt &>(expr);
744+
validate_expr(ret);
745+
return ret;
746+
}
747+
748+
/// \copydoc to_binary_overflow_expr(const exprt &)
749+
inline binary_overflow_exprt &to_binary_overflow_expr(exprt &expr)
750+
{
751+
PRECONDITION(
752+
expr.id() == ID_overflow_plus || expr.id() == ID_overflow_mult ||
753+
expr.id() == ID_overflow_minus || expr.id() == ID_overflow_shl);
754+
binary_overflow_exprt &ret = static_cast<binary_overflow_exprt &>(expr);
755+
validate_expr(ret);
756+
return ret;
757+
}
758+
759+
/// \brief A Boolean expression returning true, iff operation \c kind would
760+
/// result in an overflow when applied to the (single) operand.
761+
class unary_overflow_exprt : public unary_predicate_exprt
762+
{
763+
public:
764+
unary_overflow_exprt(const irep_idt &kind, exprt _op)
765+
: unary_predicate_exprt("overflow-" + id2string(kind), std::move(_op))
766+
{
767+
}
768+
769+
static void check(
770+
const exprt &expr,
771+
const validation_modet vm = validation_modet::INVARIANT)
772+
{
773+
unary_exprt::check(expr, vm);
774+
}
775+
776+
static void validate(
777+
const exprt &expr,
778+
const namespacet &,
779+
const validation_modet vm = validation_modet::INVARIANT)
780+
{
781+
check(expr, vm);
782+
}
783+
};
784+
785+
template <>
786+
inline bool can_cast_expr<unary_overflow_exprt>(const exprt &base)
787+
{
788+
return base.id() == ID_overflow_unary_minus;
789+
}
790+
791+
inline void validate_expr(const unary_overflow_exprt &value)
792+
{
793+
validate_operands(
794+
value, 1, "unary overflow expression must have one operand");
795+
}
796+
797+
/// \brief Cast an exprt to a \ref unary_overflow_exprt
798+
///
799+
/// \a expr must be known to be \ref unary_overflow_exprt.
800+
///
801+
/// \param expr: Source expression
802+
/// \return Object of type \ref unary_overflow_exprt
803+
inline const unary_overflow_exprt &to_unary_overflow_expr(const exprt &expr)
804+
{
805+
PRECONDITION(expr.id() == ID_overflow_unary_minus);
806+
const unary_overflow_exprt &ret =
807+
static_cast<const unary_overflow_exprt &>(expr);
808+
validate_expr(ret);
809+
return ret;
810+
}
811+
812+
/// \copydoc to_unary_overflow_expr(const exprt &)
813+
inline unary_overflow_exprt &to_unary_overflow_expr(exprt &expr)
814+
{
815+
PRECONDITION(expr.id() == ID_overflow_unary_minus);
816+
unary_overflow_exprt &ret = static_cast<unary_overflow_exprt &>(expr);
817+
validate_expr(ret);
818+
return ret;
819+
}
820+
680821
#endif // CPROVER_UTIL_BITVECTOR_EXPR_H

src/util/simplify_expr.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2048,7 +2048,7 @@ simplify_exprt::simplify_complex(const unary_exprt &expr)
20482048
}
20492049

20502050
simplify_exprt::resultt<>
2051-
simplify_exprt::simplify_overflow_binary(const binary_exprt &expr)
2051+
simplify_exprt::simplify_overflow_binary(const binary_overflow_exprt &expr)
20522052
{
20532053
// zero is a neutral element for all operations supported here
20542054
if(
@@ -2111,7 +2111,7 @@ simplify_exprt::simplify_overflow_binary(const binary_exprt &expr)
21112111
}
21122112

21132113
simplify_exprt::resultt<>
2114-
simplify_exprt::simplify_overflow_unary(const unary_exprt &expr)
2114+
simplify_exprt::simplify_overflow_unary(const unary_overflow_exprt &expr)
21152115
{
21162116
// zero is a neutral element for all operations supported here
21172117
if(expr.op().is_zero())
@@ -2405,11 +2405,11 @@ simplify_exprt::resultt<> simplify_exprt::simplify_node(exprt node)
24052405
expr.id() == ID_overflow_plus || expr.id() == ID_overflow_minus ||
24062406
expr.id() == ID_overflow_mult || expr.id() == ID_overflow_shl)
24072407
{
2408-
r = simplify_overflow_binary(to_binary_expr(expr));
2408+
r = simplify_overflow_binary(to_binary_overflow_expr(expr));
24092409
}
24102410
else if(expr.id() == ID_overflow_unary_minus)
24112411
{
2412-
r = simplify_overflow_unary(to_unary_expr(expr));
2412+
r = simplify_overflow_unary(to_unary_overflow_expr(expr));
24132413
}
24142414

24152415
if(!no_change_join_operands)

src/util/simplify_expr_class.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class abs_exprt;
3030
class address_of_exprt;
3131
class array_exprt;
3232
class binary_exprt;
33+
class binary_overflow_exprt;
3334
class binary_relation_exprt;
3435
class bitnot_exprt;
3536
class bswap_exprt;
@@ -62,6 +63,7 @@ class sign_exprt;
6263
class typecast_exprt;
6364
class unary_exprt;
6465
class unary_minus_exprt;
66+
class unary_overflow_exprt;
6567
class unary_plus_exprt;
6668
class update_exprt;
6769
class with_exprt;
@@ -188,12 +190,12 @@ class simplify_exprt
188190
/// Try to simplify overflow-+, overflow-*, overflow--, overflow-shl.
189191
/// Simplification will be possible when the operands are constants or the
190192
/// types of the operands have infinite domains.
191-
NODISCARD resultt<> simplify_overflow_binary(const binary_exprt &);
193+
NODISCARD resultt<> simplify_overflow_binary(const binary_overflow_exprt &);
192194

193195
/// Try to simplify overflow-unary-.
194196
/// Simplification will be possible when the operand is constants or the
195197
/// type of the operand has an infinite domain.
196-
NODISCARD resultt<> simplify_overflow_unary(const unary_exprt &);
198+
NODISCARD resultt<> simplify_overflow_unary(const unary_overflow_exprt &);
197199

198200
/// Attempt to simplify mathematical function applications if we have
199201
/// enough information to do so. Currently focused on constant comparisons.

0 commit comments

Comments
 (0)