Skip to content

Fix quantifiers for arrays only works with Z3 and CVC4 #6270

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion regression/cbmc/Malloc22/test.desc
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
CORE
KNOWNBUG
main.c
--unwind 2 --smt2 --outfile main.smt2
^EXIT=0$
^SIGNAL=0$
--
^Invalid expression: failed to get width of byte_update
--
20220523: Marked as KNOWNBUG due to encoding into some solvers not being
done correctly. This works for z3 and cvc4, but not other solvers.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CORE broken-smt-backend
KNOWNBUG broken-smt-backend
main.c
--smt2 --outfile -
\(= \(select array_of\.2 i\) \(ite false #b1 #b0\)\)
Expand All @@ -11,6 +11,10 @@ main.c
\(= \(select array\.3 \(\(_ zero_extend 32\) \|main::1::idx!0@1#1\|\)\) #b1 #b0\)
\(= \(select array\.3 \(_ bv\d+ 64\)\) false\)
--
20220523: Marked as KNOWNBUG due to encoding into some solvers not being
done correctly. This works for z3 and cvc4, but not other solvers. Old
comments below.

This test checks for correctness of BitVec-array encoding of Boolean arrays.

Ideally, we shouldn't have to check the SMT output, but should run with backend
Expand Down
35 changes: 25 additions & 10 deletions src/solvers/smt2/smt2_conv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4721,21 +4721,36 @@ void smt2_convt::find_symbols(const exprt &expr)
convert_type(array_type);
out << ")\n";

// use a quantifier-based initialization instead of lambda
out << "(assert (forall ((i ";
convert_type(array_type.size().type());
out << ")) (= (select " << id << " i) ";
if(array_type.element_type().id() == ID_bool && !use_array_of_bool)
// The code below only works in Z3 and CVC4, it was added (and
// approved/merged) despite breaking other solvers.
// This conditional removes this for other solvers
if(solver == solvert::CVC4 || solver == solvert::Z3)
Copy link
Contributor

@SaswatPadhi SaswatPadhi Aug 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing this. In my original commit, I didn't realize that we also support solvers that do not have quantifier support.

Instead of checking for specific solvers, should we introduce use_quantified_array_init? This can be set to true for Z3 and CVC4in the case split we have in the constructor, and we wouldn't need the solver-specific checks or the comments above and below. We use the same pattern for other solver-specific features, e.g. array of Bools support, as const support etc.

Actually, may be we should have a use_quantifier flag instead to track solvers that support quantifiers. The issue here is with the use of quantifiers, not really specific to array initialization. May be we should also go over other uses of quantifiers in this file and guard them with use_quantifier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree that a flag for quantifiers is probably the better approach, the PR above is a bit limited and incomplete (also we should have a flag and not solver specific code in random places).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've gone with a very lightweight (minimum) fix and rebase for now. Is this still blocking?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! No this isn't a blocker currently.

{
out << "(ite ";
convert_expr(array_of.what());
out << " #b1 #b0)";
// use a quantifier-based initialization instead of lambda
out << "(assert (forall ((i ";
convert_type(array_type.size().type());
out << ")) (= (select " << id << " i) ";
if(array_type.element_type().id() == ID_bool && !use_array_of_bool)
{
out << "(ite ";
convert_expr(array_of.what());
out << " #b1 #b0)";
}
else
{
convert_expr(array_of.what());
}
out << ")))\n";
}
else
{
convert_expr(array_of.what());
// This is where an alternate for other solvers that does not use
// quantifiers should go.
INVARIANT(
false,
"Cannot substitute quantified expression for lambda in current "
"solver.");
}
out << ")))\n";

defined_expressions[expr] = id;
}
Expand Down