Skip to content

Commit 00c32e3

Browse files
authored
Merge pull request #6215 from TGWDB/SMT-cache-values-and-handle-z3-errors
SMT cache values and handle z3 errors
2 parents cd1ec89 + e66aa29 commit 00c32e3

File tree

5 files changed

+73
-13
lines changed

5 files changed

+73
-13
lines changed

regression/cbmc/z3/Issue5970.c

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <assert.h>
2+
3+
void main()
4+
{
5+
unsigned A, x[64];
6+
// clang-format off
7+
__CPROVER_assume(0 <= A && A < 64);
8+
__CPROVER_assume(__CPROVER_forall { int i ; (0 <= i && i < A) ==> x[i] >= 1 });
9+
// clang-format on
10+
assert(x[0] > 0);
11+
}

regression/cbmc/z3/Issue5970.desc

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE smt-backend broken-cprover-smt-backend
2+
Issue5970.c
3+
--z3
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[main\.assertion\.1\] line [0-9]+ assertion x\[0\] > 0: FAILURE$
7+
--
8+
invalid get-value term, term must be ground and must not contain quantifiers
9+
^\[main\.assertion\.1\] line [0-9]+ assertion x\[0\] > 0: ERROR$
10+
--
11+
This tests that attempts to "(get-value |XXX|)" from z3 sat results
12+
are handled and do not cause an error message or ERROR result.

src/solvers/smt2/smt2_conv.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -4415,6 +4415,7 @@ void smt2_convt::set_to(const exprt &expr, bool value)
44154415
// This is a converted expression, we can just assert the literal name
44164416
// since the expression is already defined
44174417
out << found_literal->second;
4418+
set_values[found_literal->second] = value;
44184419
}
44194420
else
44204421
{

src/solvers/smt2/smt2_conv.h

+4
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,10 @@ class smt2_convt : public stack_decision_proceduret
250250

251251
typedef std::map<exprt, irep_idt> defined_expressionst;
252252
defined_expressionst defined_expressions;
253+
/// The values which boolean identifiers have been `smt2_convt::set_to` or
254+
/// in other words those which are asserted as true / false in the output
255+
/// smt2 formula.
256+
std::unordered_map<irep_idt, bool> set_values;
253257

254258
defined_expressionst object_sizes;
255259

src/solvers/smt2/smt2_dec.cpp

+45-13
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ decision_proceduret::resultt smt2_dect::read_result(std::istream &in)
139139
boolean_assignment.resize(no_boolean_variables, false);
140140

141141
typedef std::unordered_map<irep_idt, irept> valuest;
142-
valuest values;
142+
valuest parsed_values;
143143

144144
while(in)
145145
{
@@ -167,37 +167,69 @@ decision_proceduret::resultt smt2_dect::read_result(std::istream &in)
167167
// ( (|some_integer| 0) )
168168
// ( (|some_integer| (- 10)) )
169169

170-
values[s0.id()]=s1;
170+
parsed_values[s0.id()] = s1;
171171
}
172172
else if(
173173
parsed.id().empty() && parsed.get_sub().size() == 2 &&
174174
parsed.get_sub().front().id() == "error")
175175
{
176176
// We ignore errors after UNSAT because get-value after check-sat
177177
// returns unsat will give an error.
178-
if(res!=resultt::D_UNSATISFIABLE)
178+
if(res != resultt::D_UNSATISFIABLE)
179179
{
180-
messaget log{message_handler};
181-
log.error() << "SMT2 solver returned error message:\n"
182-
<< "\t\"" << parsed.get_sub()[1].id() << "\""
183-
<< messaget::eom;
184-
return decision_proceduret::resultt::D_ERROR;
180+
const auto &message = id2string(parsed.get_sub()[1].id());
181+
// Special case error handling
182+
if(
183+
solver == solvert::Z3 &&
184+
message.find("must not contain quantifiers") != std::string::npos)
185+
{
186+
// We tried to "(get-value |XXXX|)" where |XXXX| is determined to
187+
// include a quantified expression
188+
// Nothing to do, this should be caught and value assigned by the
189+
// set_to defaults later.
190+
}
191+
// Unhandled error, log the error and report it back up to caller
192+
else
193+
{
194+
messaget log{message_handler};
195+
log.error() << "SMT2 solver returned error message:\n"
196+
<< "\t\"" << message << "\"" << messaget::eom;
197+
return decision_proceduret::resultt::D_ERROR;
198+
}
185199
}
186200
}
187201
}
188202

203+
// If the result is not satisfiable don't bother updating the assignments and
204+
// values (since we didn't get any), just return.
205+
if(res != resultt::D_SATISFIABLE)
206+
return res;
207+
189208
for(auto &assignment : identifier_map)
190209
{
191-
std::string conv_id=convert_identifier(assignment.first);
192-
const irept &value=values[conv_id];
193-
assignment.second.value=parse_rec(value, assignment.second.type);
210+
std::string conv_id = convert_identifier(assignment.first);
211+
const irept &value = parsed_values[conv_id];
212+
assignment.second.value = parse_rec(value, assignment.second.type);
194213
}
195214

196215
// Booleans
197216
for(unsigned v=0; v<no_boolean_variables; v++)
198217
{
199-
const irept &value=values["B"+std::to_string(v)];
200-
boolean_assignment[v]=(value.id()==ID_true);
218+
const std::string boolean_identifier = "B" + std::to_string(v);
219+
boolean_assignment[v] = [&]() {
220+
const auto found_parsed_value = parsed_values.find(boolean_identifier);
221+
if(found_parsed_value != parsed_values.end())
222+
return found_parsed_value->second.id() == ID_true;
223+
// Work out the value based on what set_to was called with.
224+
const auto found_set_value =
225+
set_values.find('|' + boolean_identifier + '|');
226+
if(found_set_value != set_values.end())
227+
return found_set_value->second;
228+
// Old code used the computation
229+
// const irept &value=values["B"+std::to_string(v)];
230+
// boolean_assignment[v]=(value.id()==ID_true);
231+
return parsed_values[boolean_identifier].id() == ID_true;
232+
}();
201233
}
202234

203235
return res;

0 commit comments

Comments
 (0)