Skip to content

Commit 629d029

Browse files
Merge pull request #6736 from thomasspriggs/tas/smt_overflow
Add conversion of overflow expressions into terms for the new incremental SMT support
2 parents 2312d47 + efd4635 commit 629d029

16 files changed

+156
-14
lines changed

regression/cbmc-incr-smt2/bitvector-flag-tests/signed_overflow.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
signed_overflow.c
33
--incremental-smt2-solver 'z3 --smt2 -in' --signed-overflow-check --trace
44
^VERIFICATION FAILED$

regression/cbmc/overflow/leftshift_overflow-c89.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
leftshift_overflow.c
33
--signed-overflow-check --c89
44
^EXIT=10$

regression/cbmc/overflow/leftshift_overflow-c99.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
leftshift_overflow.c
33
--signed-overflow-check --c99
44
^EXIT=10$

regression/cbmc/overflow/mod_overflow.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
mod_overflow.c
33
--signed-overflow-check
44
^EXIT=10$

regression/cbmc/overflow/signed_addition_overflow1.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
signed_addition_overflow1.c
33
--signed-overflow-check
44
^EXIT=10$

regression/cbmc/overflow/signed_addition_overflow2.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
signed_addition_overflow2.c
33
--signed-overflow-check
44
^EXIT=10$

regression/cbmc/overflow/signed_addition_overflow3.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
signed_addition_overflow3.c
33
--signed-overflow-check --conversion-check
44
^EXIT=10$

regression/cbmc/overflow/signed_addition_overflow4.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
signed_addition_overflow4.c
33
--signed-overflow-check --conversion-check
44
^EXIT=10$

regression/cbmc/overflow/signed_multiplication1.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
signed_multiplication1.c
33
--signed-overflow-check
44
^EXIT=0$

regression/cbmc/overflow/signed_subtraction1.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
signed_subtraction1.c
33
--signed-overflow-check
44
^EXIT=0$

regression/cbmc/overflow/unary_minus_overflow.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
unary_minus_overflow.c
33
--signed-overflow-check --unsigned-overflow-check
44
^EXIT=10$

regression/cbmc/pragma_cprover2/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
main.c
33
--signed-overflow-check
44
^\[main.overflow\.1\] line 21 arithmetic overflow on signed \+ in n \+ n: FAILURE$

regression/cbmc/set-property-inline1/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
main.c
33
--property inc.overflow.1 --property inc.overflow.2 --slice-formula --signed-overflow-check --conversion-check
44
^EXIT=10$

regression/contracts/variant_init_inside_loop/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE new-smt-backend
22
main.c
33
--apply-loop-contracts _ --unsigned-overflow-check
44
^\[main\.\d+\] .* Check loop invariant before entry: SUCCESS$

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

+141
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,127 @@ static smt_termt convert_expr_to_smt(const isnormal_exprt &is_normal_expr)
833833
is_normal_expr.pretty());
834834
}
835835

836+
/// \brief
837+
/// Constructs a term which is true if the most significant bit of \p input
838+
/// is set.
839+
static smt_termt most_significant_bit_is_set(const smt_termt &input)
840+
{
841+
const auto bit_vector_sort = input.get_sort().cast<smt_bit_vector_sortt>();
842+
INVARIANT(
843+
bit_vector_sort,
844+
"Most significant bit can only be extracted from bit vector terms.");
845+
const size_t most_significant_bit_index = bit_vector_sort->bit_width() - 1;
846+
const auto extract_most_significant_bit = smt_bit_vector_theoryt::extract(
847+
most_significant_bit_index, most_significant_bit_index);
848+
return smt_core_theoryt::equal(
849+
extract_most_significant_bit(input), smt_bit_vector_constant_termt{1, 1});
850+
}
851+
852+
static smt_termt convert_expr_to_smt(const plus_overflow_exprt &plus_overflow)
853+
{
854+
const smt_termt left = convert_expr_to_smt(plus_overflow.lhs());
855+
const smt_termt right = convert_expr_to_smt(plus_overflow.rhs());
856+
if(operands_are_of_type<unsignedbv_typet>(plus_overflow))
857+
{
858+
const auto add_carry_bit = smt_bit_vector_theoryt::zero_extend(1);
859+
return most_significant_bit_is_set(
860+
smt_bit_vector_theoryt::add(add_carry_bit(left), add_carry_bit(right)));
861+
}
862+
if(operands_are_of_type<signedbv_typet>(plus_overflow))
863+
{
864+
// Overflow has occurred if the operands have the same sign and adding them
865+
// gives a result of the opposite sign.
866+
const smt_termt msb_left = most_significant_bit_is_set(left);
867+
const smt_termt msb_right = most_significant_bit_is_set(right);
868+
return smt_core_theoryt::make_and(
869+
smt_core_theoryt::equal(msb_left, msb_right),
870+
smt_core_theoryt::distinct(
871+
msb_left,
872+
most_significant_bit_is_set(smt_bit_vector_theoryt::add(left, right))));
873+
}
874+
UNIMPLEMENTED_FEATURE(
875+
"Generation of SMT formula for plus overflow expression: " +
876+
plus_overflow.pretty());
877+
}
878+
879+
static smt_termt convert_expr_to_smt(const minus_overflow_exprt &minus_overflow)
880+
{
881+
const smt_termt left = convert_expr_to_smt(minus_overflow.lhs());
882+
const smt_termt right = convert_expr_to_smt(minus_overflow.rhs());
883+
if(operands_are_of_type<unsignedbv_typet>(minus_overflow))
884+
{
885+
return smt_bit_vector_theoryt::unsigned_less_than(left, right);
886+
}
887+
if(operands_are_of_type<signedbv_typet>(minus_overflow))
888+
{
889+
// Overflow has occurred if the operands have the opposing signs and
890+
// subtracting them gives a result having the same signedness as the
891+
// right-hand operand. For example the following would be overflow for cases
892+
// for 8 bit wide bit vectors -
893+
// -128 - 1 == 127
894+
// 127 - (-1) == -128
895+
const smt_termt msb_left = most_significant_bit_is_set(left);
896+
const smt_termt msb_right = most_significant_bit_is_set(right);
897+
return smt_core_theoryt::make_and(
898+
smt_core_theoryt::distinct(msb_left, msb_right),
899+
smt_core_theoryt::equal(
900+
msb_right,
901+
most_significant_bit_is_set(
902+
smt_bit_vector_theoryt::subtract(left, right))));
903+
}
904+
UNIMPLEMENTED_FEATURE(
905+
"Generation of SMT formula for minus overflow expression: " +
906+
minus_overflow.pretty());
907+
}
908+
909+
static smt_termt convert_expr_to_smt(const mult_overflow_exprt &mult_overflow)
910+
{
911+
PRECONDITION(mult_overflow.lhs().type() == mult_overflow.rhs().type());
912+
const auto &operand_type = mult_overflow.lhs().type();
913+
const smt_termt left = convert_expr_to_smt(mult_overflow.lhs());
914+
const smt_termt right = convert_expr_to_smt(mult_overflow.rhs());
915+
if(
916+
const auto unsigned_type =
917+
type_try_dynamic_cast<unsignedbv_typet>(operand_type))
918+
{
919+
const std::size_t width = unsigned_type->get_width();
920+
const auto extend = smt_bit_vector_theoryt::zero_extend(width);
921+
return smt_bit_vector_theoryt::unsigned_greater_than_or_equal(
922+
smt_bit_vector_theoryt::multiply(extend(left), extend(right)),
923+
smt_bit_vector_constant_termt{power(2, width), width * 2});
924+
}
925+
if(
926+
const auto signed_type =
927+
type_try_dynamic_cast<signedbv_typet>(operand_type))
928+
{
929+
const smt_termt msb_left = most_significant_bit_is_set(left);
930+
const smt_termt msb_right = most_significant_bit_is_set(right);
931+
const std::size_t width = signed_type->get_width();
932+
const auto extend = smt_bit_vector_theoryt::sign_extend(width);
933+
const auto multiplication =
934+
smt_bit_vector_theoryt::multiply(extend(left), extend(right));
935+
const auto too_large = smt_bit_vector_theoryt::signed_greater_than_or_equal(
936+
multiplication,
937+
smt_bit_vector_constant_termt{power(2, width - 1), width * 2});
938+
const auto too_small = smt_bit_vector_theoryt::signed_less_than(
939+
multiplication,
940+
smt_bit_vector_theoryt::negate(
941+
smt_bit_vector_constant_termt{power(2, width - 1), width * 2}));
942+
return smt_core_theoryt::if_then_else(
943+
smt_core_theoryt::equal(msb_left, msb_right), too_large, too_small);
944+
}
945+
UNIMPLEMENTED_FEATURE(
946+
"Generation of SMT formula for multiply overflow expression: " +
947+
mult_overflow.pretty());
948+
}
949+
950+
static smt_termt convert_expr_to_smt(const shl_overflow_exprt &shl_overflow)
951+
{
952+
UNIMPLEMENTED_FEATURE(
953+
"Generation of SMT formula for shift left overflow expression: " +
954+
shl_overflow.pretty());
955+
}
956+
836957
static smt_termt convert_expr_to_smt(const array_exprt &array_construction)
837958
{
838959
UNIMPLEMENTED_FEATURE(
@@ -1144,6 +1265,26 @@ smt_termt convert_expr_to_smt(const exprt &expr)
11441265
{
11451266
return convert_expr_to_smt(*is_normal_expr);
11461267
}
1268+
if(
1269+
const auto plus_overflow = expr_try_dynamic_cast<plus_overflow_exprt>(expr))
1270+
{
1271+
return convert_expr_to_smt(*plus_overflow);
1272+
}
1273+
if(
1274+
const auto minus_overflow =
1275+
expr_try_dynamic_cast<minus_overflow_exprt>(expr))
1276+
{
1277+
return convert_expr_to_smt(*minus_overflow);
1278+
}
1279+
if(
1280+
const auto mult_overflow = expr_try_dynamic_cast<mult_overflow_exprt>(expr))
1281+
{
1282+
return convert_expr_to_smt(*mult_overflow);
1283+
}
1284+
if(const auto shl_overflow = expr_try_dynamic_cast<shl_overflow_exprt>(expr))
1285+
{
1286+
return convert_expr_to_smt(*shl_overflow);
1287+
}
11471288
if(const auto array_construction = expr_try_dynamic_cast<array_exprt>(expr))
11481289
{
11491290
return convert_expr_to_smt(*array_construction);

src/solvers/smt2_incremental/smt_bit_vector_theory.h

+1
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ class smt_bit_vector_theoryt
245245
static smt_sortt return_sort(const smt_termt &operand);
246246
static void validate(const smt_termt &operand);
247247
};
248+
/// \brief Arithmetic negation in two's complement.
248249
static const smt_function_application_termt::factoryt<negatet> negate;
249250

250251
// Shift operations

0 commit comments

Comments
 (0)