Skip to content

Commit 9a1df4b

Browse files
committed
SMT2 back-end: flatten with_exprt operands
Solvers without datatypes support require flattening towards bitvectors. This is also true for array-typed expressions when the array is not at the top level (despite possible array-theory support). This changes makes sure we will flatten such array-typed expressions.
1 parent 9611331 commit 9a1df4b

File tree

4 files changed

+86
-39
lines changed

4 files changed

+86
-39
lines changed

regression/contracts-dfcc/CMakeLists.txt

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,15 @@ add_test_pl_profile(
4141
#)
4242

4343
# solver appears on the PATH in Windows already
44-
#if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
45-
# set_property(
46-
# TEST "cbmc-cprover-smt2-CORE"
47-
# PROPERTY ENVIRONMENT
48-
# "PATH=$ENV{PATH}:$<TARGET_FILE_DIR:smt2_solver>"
49-
# )
50-
#endif()
44+
if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
45+
set_property(
46+
TEST "contracts-dfcc-CORE"
47+
PROPERTY ENVIRONMENT
48+
"PATH=$ENV{PATH}:$<TARGET_FILE_DIR:smt2_solver>"
49+
)
50+
set_property(
51+
TEST "contracts-non-dfcc-CORE"
52+
PROPERTY ENVIRONMENT
53+
"PATH=$ENV{PATH}:$<TARGET_FILE_DIR:smt2_solver>"
54+
)
55+
endif()
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
typedef struct
2+
{
3+
int coeffs[2];
4+
} mlk_poly;
5+
6+
// clang-format off
7+
void mlk_poly_add(mlk_poly *r, const mlk_poly *b)
8+
__CPROVER_ensures(r->coeffs[0] == __CPROVER_old(*r).coeffs[0] + b->coeffs[0])
9+
__CPROVER_assigns(__CPROVER_object_upto(r, sizeof(mlk_poly)));
10+
// clang-format on
11+
12+
int main()
13+
{
14+
mlk_poly r[1];
15+
mlk_poly b[1];
16+
mlk_poly_add(&r[0], &b[0]);
17+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--dfcc main --replace-call-with-contract mlk_poly_add _ --no-array-field-sensitivity --cprover-smt2
4+
^\[mlk_poly_add.overflow.1\] line 8 arithmetic overflow on signed \+
5+
^\*\* 1 of \d+ failed
6+
^VERIFICATION FAILED$
7+
^EXIT=10$
8+
^SIGNAL=0$
9+
--
10+
--
11+
Make sure the SMT back-end produces valid SMT2 when structs and arrays are
12+
nested in each other.

src/solvers/smt2/smt2_conv.cpp

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4400,50 +4400,63 @@ void smt2_convt::convert_with(const with_exprt &expr)
44004400
}
44014401
else
44024402
{
4403+
auto convert_operand = [this](const exprt &op)
4404+
{
4405+
// may need to flatten array-theory arrays in there
4406+
if(op.type().id() == ID_array && use_array_theory(op))
4407+
flatten_array(op);
4408+
else if(op.type().id() == ID_bool)
4409+
flatten2bv(op);
4410+
else
4411+
convert_expr(op);
4412+
};
4413+
44034414
std::size_t struct_width=boolbv_width(struct_type);
44044415

44054416
// figure out the offset and width of the member
44064417
const boolbv_widtht::membert &m =
44074418
boolbv_width.get_member(struct_type, component_name);
44084419

4409-
out << "(let ((?withop ";
4410-
convert_expr(expr.old());
4411-
out << ")) ";
4412-
44134420
if(m.width==struct_width)
44144421
{
4415-
// the struct is the same as the member, no concat needed,
4416-
// ?withop won't be used
4417-
convert_expr(value);
4418-
}
4419-
else if(m.offset==0)
4420-
{
4421-
// the member is at the beginning
4422-
out << "(concat "
4423-
<< "((_ extract " << (struct_width-1) << " "
4424-
<< m.width << ") ?withop) ";
4425-
convert_expr(value);
4426-
out << ")"; // concat
4427-
}
4428-
else if(m.offset+m.width==struct_width)
4429-
{
4430-
// the member is at the end
4431-
out << "(concat ";
4432-
convert_expr(value);
4433-
out << " ((_ extract " << (m.offset - 1) << " 0) ?withop))";
4422+
// the struct is the same as the member, no concat needed
4423+
convert_operand(value);
44344424
}
44354425
else
44364426
{
4437-
// most general case, need two concat-s
4438-
out << "(concat (concat "
4439-
<< "((_ extract " << (struct_width-1) << " "
4440-
<< (m.offset+m.width) << ") ?withop) ";
4441-
convert_expr(value);
4442-
out << ") ((_ extract " << (m.offset-1) << " 0) ?withop)";
4443-
out << ")"; // concat
4444-
}
4427+
out << "(let ((?withop ";
4428+
convert_operand(expr.old());
4429+
out << ")) ";
4430+
4431+
if(m.offset == 0)
4432+
{
4433+
// the member is at the beginning
4434+
out << "(concat "
4435+
<< "((_ extract " << (struct_width - 1) << " " << m.width
4436+
<< ") ?withop) ";
4437+
convert_operand(value);
4438+
out << ")"; // concat
4439+
}
4440+
else if(m.offset + m.width == struct_width)
4441+
{
4442+
// the member is at the end
4443+
out << "(concat ";
4444+
convert_operand(value);
4445+
out << " ((_ extract " << (m.offset - 1) << " 0) ?withop))";
4446+
}
4447+
else
4448+
{
4449+
// most general case, need two concat-s
4450+
out << "(concat (concat "
4451+
<< "((_ extract " << (struct_width - 1) << " "
4452+
<< (m.offset + m.width) << ") ?withop) ";
4453+
convert_operand(value);
4454+
out << ") ((_ extract " << (m.offset - 1) << " 0) ?withop)";
4455+
out << ")"; // concat
4456+
}
44454457

4446-
out << ")"; // let ?withop
4458+
out << ")"; // let ?withop
4459+
}
44474460
}
44484461
}
44494462
else if(expr_type.id() == ID_union || expr_type.id() == ID_union_tag)

0 commit comments

Comments
 (0)