Skip to content

Commit b0eedde

Browse files
committed
SMT2 back-end: detect when solver returns unexpected model
We have seen examples of Z3 responding with ``` ((B1502 (forall ((|main::tmp_cc$0!0@1#0| (_ BitVec 64))) (let ((a!1 (or (and (not (bvule #x000000000000000c |main::tmp_cc$0!0@1#0|)) (bvule #x000000000000000b |main::tmp_cc$0!0@1#0|) [...] ``` when we expected just `true` or `false` as model (which Bitwuzla seemed to get right on the very same input program). Report these as errors rather than using the incomplete assignment. Such an incomplete assignment would make us re-try forever without making progress. Fixes: #8365
1 parent 629dbcd commit b0eedde

File tree

4 files changed

+42
-16
lines changed

4 files changed

+42
-16
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE smt-backend no-new-smt
1+
KNOWNBUG smt-backend no-new-smt
22
smt_missing_range_check.c
33
--no-malloc-may-fail --pointer-check -z3
44
^EXIT=10$
@@ -9,7 +9,10 @@ smt_missing_range_check.c
99
--
1010
--
1111
Check that memory checks fail for pointer dereferences inside an existential
12-
qualifier, for out of bounds memory access, when using the smt backend and
12+
quantifier, for out of bounds memory access, when using the smt backend and
1313
the range of the index is unbound. Note that this test is not expected to work
1414
with the SAT backend at the time of writing, as the SAT backend does not support
15-
qualifiers in this form.
15+
quantifiers in this form.
16+
17+
Neither Z3 nor CVC5 currently return complete models, and Bitwuzla does not
18+
complete in more than 5 minutes.

regression/cbmc/Quantifiers-assertion/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE no-new-smt
1+
CORE broken-z3-smt-backend no-new-smt
22
main.c
33

44
^\*\* Results:$

regression/cbmc/z3/Issue5977.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Issue5977.c
33
--z3
44
^EXIT=(6|10)$
55
^SIGNAL=0$
6-
^SMT2 solver returned "unknown"$
6+
^SMT2 solver returned ("unknown"|non-constant value for variable B\d+)$
77
--
88
--
99
This tests that an "unknown" result from the SMT solver is reported.

src/solvers/smt2/smt2_dec.cpp

+34-11
Original file line numberDiff line numberDiff line change
@@ -236,22 +236,45 @@ decision_proceduret::resultt smt2_dect::read_result(std::istream &in)
236236
{
237237
const std::string boolean_identifier =
238238
convert_identifier("B" + std::to_string(v));
239-
boolean_assignment[v] = [&]() {
240239
const auto found_parsed_value =
241240
parsed_values.find(drop_quotes(boolean_identifier));
242241
if(found_parsed_value != parsed_values.end())
243242
{
244-
return found_parsed_value->second.id() == ID_true;
243+
const irept &value = found_parsed_value->second;
244+
245+
if(value.id() != ID_true && value.id() != ID_false)
246+
{
247+
messaget log{message_handler};
248+
log.error() << "SMT2 solver returned non-constant value for variable "
249+
<< boolean_identifier << messaget::eom;
250+
return decision_proceduret::resultt::D_ERROR;
251+
}
252+
boolean_assignment[v] = value.id() == ID_true;
253+
}
254+
else
255+
{
256+
// Work out the value based on what set_to was called with.
257+
const auto found_set_value = set_values.find(boolean_identifier);
258+
if(found_set_value != set_values.end())
259+
boolean_assignment[v] = found_set_value->second;
260+
else
261+
{
262+
// Old code used the computation
263+
// const irept &value=values["B"+std::to_string(v)];
264+
// boolean_assignment[v]=(value.id()==ID_true);
265+
const irept &value = parsed_values[boolean_identifier];
266+
267+
if(value.id() != ID_true && value.id() != ID_false)
268+
{
269+
messaget log{message_handler};
270+
log.error()
271+
<< "SMT2 solver returned non-Boolean value for variable "
272+
<< boolean_identifier << messaget::eom;
273+
return decision_proceduret::resultt::D_ERROR;
274+
}
275+
boolean_assignment[v] = value.id() == ID_true;
276+
}
245277
}
246-
// Work out the value based on what set_to was called with.
247-
const auto found_set_value = set_values.find(boolean_identifier);
248-
if(found_set_value != set_values.end())
249-
return found_set_value->second;
250-
// Old code used the computation
251-
// const irept &value=values["B"+std::to_string(v)];
252-
// boolean_assignment[v]=(value.id()==ID_true);
253-
return parsed_values[boolean_identifier].id() == ID_true;
254-
}();
255278
}
256279

257280
return res;

0 commit comments

Comments
 (0)