Skip to content

Commit 8694d4e

Browse files
Merge pull request #6357 from thomasspriggs/tas/incremtal_backed_to_solver
Implement sending commands to solver in incremental SMT2 backend
2 parents bd59ad3 + 71d746a commit 8694d4e

19 files changed

+621
-29
lines changed
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11

2+
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
3+
set(exclude_win_broken_tests -X winbug)
4+
else()
5+
set(exclude_win_broken_tests "")
6+
endif()
7+
28
add_test_pl_tests(
3-
"$<TARGET_FILE:cbmc> --validate-goto-model --validate-ssa-equation --slice-formula"
9+
"$<TARGET_FILE:cbmc> --validate-goto-model --validate-ssa-equation --slice-formula" ${exclude_win_broken_tests}
410
)

regression/cbmc-incr-smt2/Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@ default: test
33
include ../../src/config.inc
44
include ../../src/common
55

6+
ifeq ($(BUILD_ENV_),MSVC)
7+
exclude_broken_windows_tests=-X winbug
8+
else
9+
exclude_broken_windows_tests=
10+
endif
11+
612
test:
7-
@../test.pl -e -p -c "../../../src/cbmc/cbmc --validate-goto-model --validate-ssa-equation --slice-formula"
13+
@../test.pl -e -p -c "../../../src/cbmc/cbmc --validate-goto-model --validate-ssa-equation --slice-formula" $(exclude_broken_windows_tests)
814

915
tests.log: ../test.pl test
1016

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
int main()
3+
{
4+
int x, y;
5+
if(x != 0)
6+
{
7+
y = 9;
8+
}
9+
else
10+
{
11+
y = 4;
12+
}
13+
int z = y;
14+
__CPROVER_assert(x != z, "Assert of integer equality.");
15+
return 0;
16+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
CORE winbug
2+
control_flow.c
3+
--incremental-smt2-solver "z3 --smt2 -in" --verbosity 10
4+
Passing problem to incremental SMT2 solving via "z3 --smt2 -in"
5+
Sending command to SMT2 solver - \(set-option :produce-models true\)
6+
Sending command to SMT2 solver - \(set-logic QF_UFBV\)
7+
Sending command to SMT2 solver - \(declare-fun |goto_symex::&92;guard#1| \(\) Bool\)
8+
Sending command to SMT2 solver - \(define-fun |B1| \(\) Bool |goto_symex::&92;guard#1|\)
9+
Sending command to SMT2 solver - \(declare-fun |main::1::x!0@1#1| \(\) \(_ BitVec 32\)\)
10+
Sending command to SMT2 solver - \(assert \(|=| |goto_symex::&92;guard#1| \(|not| \(|=| |main::1::x!0@1#1| \(_ bv0 32\)\)\)\)\)
11+
Sending command to SMT2 solver - \(declare-fun |main::1::y!0@1#4| \(\) \(_ BitVec 32\)\)
12+
Sending command to SMT2 solver - \(assert \(|=| |main::1::y!0@1#4| \(|ite| |goto_symex::&92;guard#1| \(_ bv9 32\) \(_ bv4 32\)\)\)\)
13+
Sending command to SMT2 solver - \(declare-fun |main::1::x!0@1#3| \(\) \(_ BitVec 32\)\)
14+
Sending command to SMT2 solver - \(assert \(|=| |main::1::x!0@1#3| \(|ite| |goto_symex::&92;guard#1| |main::1::x!0@1#1| \(_ bv0 32\)\)\)\)
15+
Sending command to SMT2 solver - \(declare-fun |main::1::z!0@1#2| \(\) \(_ BitVec 32\)\)
16+
Sending command to SMT2 solver - \(assert \(|=| |main::1::z!0@1#2| |main::1::y!0@1#4|\)\)
17+
Sending command to SMT2 solver - \(define-fun |B3| \(\) Bool \(|=| |main::1::x!0@1#1| \(_ bv0 32\)\)\)
18+
Sending command to SMT2 solver - \(assert \(|not| \(|not| \(|=| |main::1::x!0@1#3| |main::1::z!0@1#2|\)\)\)\)
19+
Sending command to SMT2 solver - \(define-fun |B4| \(\) Bool \(|not| false\)\)
20+
Sending command to SMT2 solver - \(assert |B4|\)
21+
Sending command to SMT2 solver - \(check-sat\)
22+
Solver response - sat
23+
^EXIT=(0|127|134|137)$
24+
^SIGNAL=0$
25+
--
26+
type: pointer
27+
--
28+
Test that running cbmc with the `--incremental-smt2-solver` argument can be used
29+
to send a valid SMT2 formula to a sub-process solver for an example input file
30+
which include control flow constructs. Note that at the time of adding this
31+
test, an invariant violation is expected due to the unimplemented response
32+
parsing.
Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
1-
CORE
1+
CORE winbug
22
test.c
3-
--incremental-smt2-solver z3
4-
Passing problem to incremental SMT2 solving via "z3"
3+
--incremental-smt2-solver "z3 --smt2 -in" --verbosity 10
4+
Passing problem to incremental SMT2 solving via "z3 --smt2 -in"
5+
Sending command to SMT2 solver - \(set-option :produce-models true\)
6+
Sending command to SMT2 solver - \(set-logic QF_UFBV\)
7+
Sending command to SMT2 solver - \(define-fun |B0| \(\) Bool true\)
8+
Sending command to SMT2 solver - \(declare-fun |main::1::x!0@1#1| \(\) \(_ BitVec 32\)\)
9+
Sending command to SMT2 solver - \(define-fun |B1| \(\) Bool \(|=| |main::1::x!0@1#1| |main::1::x!0@1#1|\)\)
10+
Sending command to SMT2 solver - \(assert \(|not| \(|not| \(|=| |main::1::x!0@1#1| \(_ bv0 32\)\)\)\)\)
11+
Sending command to SMT2 solver - \(define-fun |B2| \(\) Bool \(|not| false\)\)
12+
Sending command to SMT2 solver - \(assert |B2|\)
13+
Sending command to SMT2 solver - \(check-sat\)
14+
Solver response - sat
515
^EXIT=(0|127|134|137)$
616
^SIGNAL=0$
7-
identifier: main::1::x
817
--
918
type: pointer
1019
--
1120
Test that running cbmc with the `--incremental-smt2-solver` argument causes the
1221
incremental smt2 solving to be used. Note that at the time of adding this test,
13-
an invariant violation is expected due to the unimplemented solving.
14-
Regexes matching the printing in the expected failed invariant are included in
15-
order to test that `--slice-formula` is causing the first unimplemented
16-
expression passed to `smt2_incremental_decision_proceduret` to relate to the
17-
variable `x` in function `main` and not to `cprover_initialise`.
22+
an invariant violation is expected due to the unimplemented response parsing.
23+
24+
The sliced formula is expected to use only the implemented subset of exprts.
25+
This is implementation is sufficient to send this example to the solver and
26+
receive a "sat" response.

src/goto-checker/solver_factory.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Author: Daniel Kroening, Peter Schrammel
3333
#include <solvers/sat/external_sat.h>
3434
#include <solvers/sat/satcheck.h>
3535
#include <solvers/smt2_incremental/smt2_incremental_decision_procedure.h>
36+
#include <solvers/smt2_incremental/smt_solver_process.h>
3637
#include <solvers/strings/string_refinement.h>
3738

3839
solver_factoryt::solver_factoryt(
@@ -330,10 +331,12 @@ std::unique_ptr<solver_factoryt::solvert>
330331
solver_factoryt::get_incremental_smt2(std::string solver_command)
331332
{
332333
no_beautification();
334+
auto solver_process = util_make_unique<smt_piped_solver_processt>(
335+
std::move(solver_command), message_handler);
333336

334337
return util_make_unique<solvert>(
335338
util_make_unique<smt2_incremental_decision_proceduret>(
336-
std::move(solver_command)));
339+
ns, std::move(solver_process), message_handler));
337340
}
338341

339342
std::unique_ptr<solver_factoryt::solvert>

src/solvers/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ SRC = $(BOOLEFORCE_SRC) \
199199
smt2_incremental/smt_core_theory.cpp \
200200
smt2_incremental/smt_logics.cpp \
201201
smt2_incremental/smt_options.cpp \
202+
smt2_incremental/smt_solver_process.cpp \
202203
smt2_incremental/smt_sorts.cpp \
203204
smt2_incremental/smt_terms.cpp \
204205
smt2_incremental/smt_to_smt2_string.cpp \

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ smt_sortt convert_type_to_smt_sort(const typet &type)
4646

4747
static smt_termt convert_expr_to_smt(const symbol_exprt &symbol_expr)
4848
{
49-
UNIMPLEMENTED_FEATURE(
50-
"Generation of SMT formula for symbol expression: " + symbol_expr.pretty());
49+
return smt_identifier_termt{symbol_expr.get_identifier(),
50+
convert_type_to_smt_sort(symbol_expr.type())};
5151
}
5252

5353
static smt_termt convert_expr_to_smt(const nondet_symbol_exprt &nondet_symbol)

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 139 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,133 @@
22

33
#include "smt2_incremental_decision_procedure.h"
44

5+
#include <solvers/smt2_incremental/convert_expr_to_smt.h>
6+
#include <solvers/smt2_incremental/smt_commands.h>
7+
#include <solvers/smt2_incremental/smt_core_theory.h>
8+
#include <solvers/smt2_incremental/smt_solver_process.h>
9+
#include <solvers/smt2_incremental/smt_terms.h>
510
#include <util/expr.h>
11+
#include <util/namespace.h>
12+
#include <util/range.h>
13+
#include <util/std_expr.h>
14+
#include <util/string_utils.h>
15+
#include <util/symbol.h>
16+
17+
#include <stack>
18+
19+
/// \brief Find all sub expressions of the given \p expr which need to be
20+
/// expressed as separate smt commands.
21+
/// \return A collection of sub expressions, which need to be expressed as
22+
/// separate smt commands. This collection is in traversal order. It will
23+
/// include duplicate subexpressions, which need to be removed by the caller
24+
/// in order to avoid duplicate definitions.
25+
/// \note This pass over \p expr is tightly coupled to the implementation of
26+
/// `convert_expr_to_smt`. This is because any sub expressions which
27+
/// `convert_expr_to_smt` translates into function applications, must also be
28+
/// returned by this`gather_dependent_expressions` function.
29+
static std::vector<exprt> gather_dependent_expressions(const exprt &expr)
30+
{
31+
std::vector<exprt> dependent_expressions;
32+
expr.visit_pre([&](const exprt &expr_node) {
33+
if(can_cast_expr<symbol_exprt>(expr_node))
34+
{
35+
dependent_expressions.push_back(expr_node);
36+
}
37+
});
38+
return dependent_expressions;
39+
}
40+
41+
/// \brief Defines any functions which \p expr depends on, which have not yet
42+
/// been defined, along with their dependencies in turn.
43+
void smt2_incremental_decision_proceduret::define_dependent_functions(
44+
const exprt &expr)
45+
{
46+
std::unordered_set<exprt, irep_hash> seen_expressions =
47+
make_range(expression_identifiers)
48+
.map([](const std::pair<exprt, smt_identifier_termt> &expr_identifier) {
49+
return expr_identifier.first;
50+
});
51+
std::stack<exprt> to_be_defined;
52+
const auto dependencies_needed = [&](const exprt &expr) {
53+
bool result = false;
54+
for(const auto &dependency : gather_dependent_expressions(expr))
55+
{
56+
if(!seen_expressions.insert(dependency).second)
57+
continue;
58+
result = true;
59+
to_be_defined.push(dependency);
60+
}
61+
return result;
62+
};
63+
dependencies_needed(expr);
64+
while(!to_be_defined.empty())
65+
{
66+
const exprt current = to_be_defined.top();
67+
if(dependencies_needed(current))
68+
continue;
69+
if(const auto symbol_expr = expr_try_dynamic_cast<symbol_exprt>(current))
70+
{
71+
const irep_idt &identifier = symbol_expr->get_identifier();
72+
const symbolt *symbol = nullptr;
73+
if(ns.lookup(identifier, symbol) || symbol->value.is_nil())
74+
{
75+
const smt_declare_function_commandt function{
76+
smt_identifier_termt(
77+
identifier, convert_type_to_smt_sort(symbol_expr->type())),
78+
{}};
79+
expression_identifiers.emplace(*symbol_expr, function.identifier());
80+
solver_process->send(function);
81+
}
82+
else
83+
{
84+
if(dependencies_needed(symbol->value))
85+
continue;
86+
const smt_define_function_commandt function{
87+
symbol->name, {}, convert_expr_to_smt(symbol->value)};
88+
expression_identifiers.emplace(*symbol_expr, function.identifier());
89+
solver_process->send(function);
90+
}
91+
}
92+
to_be_defined.pop();
93+
}
94+
}
695

796
smt2_incremental_decision_proceduret::smt2_incremental_decision_proceduret(
8-
std::string solver_command)
9-
: solver_command{std::move(solver_command)}, number_of_solver_calls{0}
97+
const namespacet &_ns,
98+
std::unique_ptr<smt_base_solver_processt> _solver_process,
99+
message_handlert &message_handler)
100+
: ns{_ns},
101+
number_of_solver_calls{0},
102+
solver_process(std::move(_solver_process)),
103+
log{message_handler}
104+
{
105+
solver_process->send(
106+
smt_set_option_commandt{smt_option_produce_modelst{true}});
107+
solver_process->send(smt_set_logic_commandt{
108+
smt_logic_quantifier_free_uninterpreted_functions_bit_vectorst{}});
109+
}
110+
111+
void smt2_incremental_decision_proceduret::ensure_handle_for_expr_defined(
112+
const exprt &expr)
10113
{
114+
if(
115+
expression_handle_identifiers.find(expr) !=
116+
expression_handle_identifiers.cend())
117+
{
118+
return;
119+
}
120+
121+
define_dependent_functions(expr);
122+
smt_define_function_commandt function{
123+
"B" + std::to_string(handle_sequence()), {}, convert_expr_to_smt(expr)};
124+
expression_handle_identifiers.emplace(expr, function.identifier());
125+
solver_process->send(function);
11126
}
12127

13128
exprt smt2_incremental_decision_proceduret::handle(const exprt &expr)
14129
{
130+
log.debug() << "`handle` -\n " << expr.pretty(2, 0) << messaget::eom;
131+
ensure_handle_for_expr_defined(expr);
15132
return expr;
16133
}
17134

@@ -29,7 +146,7 @@ void smt2_incremental_decision_proceduret::print_assignment(
29146
std::string
30147
smt2_incremental_decision_proceduret::decision_procedure_text() const
31148
{
32-
return "incremental SMT2 solving via \"" + solver_command + "\"";
149+
return "incremental SMT2 solving via " + solver_process->description();
33150
}
34151

35152
std::size_t
@@ -40,9 +157,22 @@ smt2_incremental_decision_proceduret::get_number_of_solver_calls() const
40157

41158
void smt2_incremental_decision_proceduret::set_to(const exprt &expr, bool value)
42159
{
43-
UNIMPLEMENTED_FEATURE(
44-
"`set_to` (" + std::string{value ? "true" : "false"} + "):\n " +
45-
expr.pretty(2, 0));
160+
PRECONDITION(can_cast_type<bool_typet>(expr.type()));
161+
log.debug() << "`set_to` (" << std::string{value ? "true" : "false"}
162+
<< ") -\n " << expr.pretty(2, 0) << messaget::eom;
163+
164+
define_dependent_functions(expr);
165+
auto converted_term = [&]() -> smt_termt {
166+
const auto expression_handle_identifier =
167+
expression_handle_identifiers.find(expr);
168+
if(expression_handle_identifier != expression_handle_identifiers.cend())
169+
return expression_handle_identifier->second;
170+
else
171+
return convert_expr_to_smt(expr);
172+
}();
173+
if(!value)
174+
converted_term = smt_core_theoryt::make_not(converted_term);
175+
solver_process->send(smt_assert_commandt{converted_term});
46176
}
47177

48178
void smt2_incremental_decision_proceduret::push(
@@ -69,5 +199,7 @@ void smt2_incremental_decision_proceduret::pop()
69199
decision_proceduret::resultt smt2_incremental_decision_proceduret::dec_solve()
70200
{
71201
++number_of_solver_calls;
72-
UNIMPLEMENTED_FEATURE("solving.");
202+
solver_process->send(smt_check_sat_commandt{});
203+
const smt_responset result = solver_process->receive_response();
204+
UNIMPLEMENTED_FEATURE("handling solver response.");
73205
}

0 commit comments

Comments
 (0)