Skip to content

Commit 8a720e0

Browse files
authored
Merge pull request #6474 from thomasspriggs/tas/smt_sat_unsat
Add interpretation of SMT check-sat responses for incremental SMT solving support
2 parents 1afc3ae + 1441111 commit 8a720e0

File tree

7 files changed

+315
-43
lines changed

7 files changed

+315
-43
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
int main()
3+
{
4+
int x;
5+
int y;
6+
if(y)
7+
y = x;
8+
else
9+
y = x;
10+
__CPROVER_assert(y == x, "Nondeterministic int assert.");
11+
return 0;
12+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE winbug
2+
valid_unsat.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 - \(check-sat\)
6+
Solver response - unsat
7+
VERIFICATION SUCCESSFUL
8+
^EXIT=0$
9+
^SIGNAL=0$
10+
--
11+
type: pointer
12+
--
13+
Test that given a `.c` program where all assertions hold, the solver responds
14+
with unsat and CBMC reports that verification is successful.

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,48 @@
55
#include <solvers/smt2_incremental/convert_expr_to_smt.h>
66
#include <solvers/smt2_incremental/smt_commands.h>
77
#include <solvers/smt2_incremental/smt_core_theory.h>
8+
#include <solvers/smt2_incremental/smt_responses.h>
89
#include <solvers/smt2_incremental/smt_solver_process.h>
910
#include <solvers/smt2_incremental/smt_terms.h>
1011
#include <util/expr.h>
1112
#include <util/namespace.h>
13+
#include <util/nodiscard.h>
1214
#include <util/range.h>
1315
#include <util/std_expr.h>
1416
#include <util/string_utils.h>
1517
#include <util/symbol.h>
1618

1719
#include <stack>
1820

21+
/// Issues a command to the solving process which is expected to optionally
22+
/// return a success status followed by the actual response of interest.
23+
static smt_responset get_response_to_command(
24+
smt_base_solver_processt &solver_process,
25+
const smt_commandt &command)
26+
{
27+
solver_process.send(command);
28+
auto response = solver_process.receive_response();
29+
if(response.cast<smt_success_responset>())
30+
return solver_process.receive_response();
31+
else
32+
return response;
33+
}
34+
35+
static optionalt<std::string>
36+
get_problem_messages(const smt_responset &response)
37+
{
38+
if(const auto error = response.cast<smt_error_responset>())
39+
{
40+
return "SMT solver returned an error message - " +
41+
id2string(error->message());
42+
}
43+
if(response.cast<smt_unsupported_responset>())
44+
{
45+
return {"SMT solver does not support given command."};
46+
}
47+
return {};
48+
}
49+
1950
/// \brief Find all sub expressions of the given \p expr which need to be
2051
/// expressed as separate smt commands.
2152
/// \return A collection of sub expressions, which need to be expressed as
@@ -196,10 +227,31 @@ void smt2_incremental_decision_proceduret::pop()
196227
UNIMPLEMENTED_FEATURE("`pop`.");
197228
}
198229

230+
NODISCARD
231+
static decision_proceduret::resultt lookup_decision_procedure_result(
232+
const smt_check_sat_response_kindt &response_kind)
233+
{
234+
if(response_kind.cast<smt_sat_responset>())
235+
return decision_proceduret::resultt::D_SATISFIABLE;
236+
if(response_kind.cast<smt_unsat_responset>())
237+
return decision_proceduret::resultt::D_UNSATISFIABLE;
238+
if(response_kind.cast<smt_unknown_responset>())
239+
return decision_proceduret::resultt::D_ERROR;
240+
UNREACHABLE;
241+
}
242+
199243
decision_proceduret::resultt smt2_incremental_decision_proceduret::dec_solve()
200244
{
201245
++number_of_solver_calls;
202-
solver_process->send(smt_check_sat_commandt{});
203-
const smt_responset result = solver_process->receive_response();
204-
UNIMPLEMENTED_FEATURE("handling solver response.");
246+
const smt_responset result =
247+
get_response_to_command(*solver_process, smt_check_sat_commandt{});
248+
if(const auto check_sat_response = result.cast<smt_check_sat_responset>())
249+
{
250+
if(check_sat_response->kind().cast<smt_unknown_responset>())
251+
log.error() << "SMT2 solver returned \"unknown\"" << messaget::eom;
252+
return lookup_decision_procedure_result(check_sat_response->kind());
253+
}
254+
if(const auto problem = get_problem_messages(result))
255+
throw analysis_exceptiont{*problem};
256+
throw analysis_exceptiont{"Unexpected kind of response from SMT solver."};
205257
}

src/solvers/smt2_incremental/smt_response_validation.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <solvers/smt2_incremental/smt_responses.h>
77
#include <util/invariant.h>
8+
#include <util/nodiscard.h>
89
#include <util/optional.h>
910

1011
#include <string>
@@ -37,7 +38,7 @@ class response_or_errort final
3738
std::vector<std::string> messages;
3839
};
3940

40-
response_or_errort<smt_responset>
41+
NODISCARD response_or_errort<smt_responset>
4142
validate_smt_response(const irept &parse_tree);
4243

4344
#endif // CPROVER_SOLVERS_SMT2_INCREMENTAL_SMT_RESPONSE_VALIDATION_H

src/solvers/smt2_incremental/smt_solver_process.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
#include <solvers/smt2_incremental/smt_solver_process.h>
44

5+
#include <solvers/smt2/smt2irep.h>
6+
#include <solvers/smt2_incremental/smt_response_validation.h>
57
#include <solvers/smt2_incremental/smt_to_smt2_string.h>
8+
#include <util/exception_utils.h>
69
#include <util/invariant.h>
710
#include <util/string_utils.h>
811

@@ -28,9 +31,28 @@ void smt_piped_solver_processt::send(const smt_commandt &smt_command)
2831
process.send(command_string + "\n");
2932
}
3033

34+
/// Log messages and throw exception.
35+
static void handle_invalid_smt(
36+
const std::vector<std::string> &validation_errors,
37+
messaget &log)
38+
{
39+
for(const std::string &message : validation_errors)
40+
{
41+
log.error() << message << messaget::eom;
42+
}
43+
throw analysis_exceptiont{"Invalid SMT response received from solver."};
44+
}
45+
3146
smt_responset smt_piped_solver_processt::receive_response()
3247
{
3348
const auto response_text = process.wait_receive();
3449
log.debug() << "Solver response - " << response_text << messaget::eom;
35-
UNIMPLEMENTED_FEATURE("parsing of solver response.");
50+
response_stream << response_text;
51+
const auto parse_tree = smt2irep(response_stream, log.get_message_handler());
52+
if(!parse_tree)
53+
throw deserialization_exceptiont{"Incomplete SMT response."};
54+
const auto validation_result = validate_smt_response(*parse_tree);
55+
if(const auto validation_errors = validation_result.get_if_error())
56+
handle_invalid_smt(*validation_errors, log);
57+
return *validation_result.get_if_valid();
3658
}

src/solvers/smt2_incremental/smt_solver_process.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class smt_commandt;
99
#include <util/message.h>
1010
#include <util/piped_process.h>
1111

12+
#include <sstream>
1213
#include <string>
1314

1415
class smt_base_solver_processt
@@ -49,6 +50,8 @@ class smt_piped_solver_processt : public smt_base_solver_processt
4950
std::string command_line_description;
5051
/// The raw solver sub process.
5152
piped_processt process;
53+
/// For buffering / combining communications from the solver to cbmc.
54+
std::stringstream response_stream;
5255
/// For debug printing.
5356
messaget log;
5457
};

0 commit comments

Comments
 (0)