From 0c08a0ed0e83faaa7c63bf3db55b9f65d6f73388 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Fri, 18 Feb 2022 16:10:52 -0600 Subject: [PATCH] Add well formed term check to solver engine (#8056) Fixes cvc5/cvc5-projects#413. --- src/smt/solver_engine.cpp | 23 +++++++++++++++++++++++ src/smt/solver_engine.h | 10 ++++++++++ test/unit/api/cpp/solver_black.cpp | 16 ++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/src/smt/solver_engine.cpp b/src/smt/solver_engine.cpp index 546fdc34f..e67877fad 100644 --- a/src/smt/solver_engine.cpp +++ b/src/smt/solver_engine.cpp @@ -22,6 +22,7 @@ #include "decision/decision_engine.h" #include "expr/bound_var_manager.h" #include "expr/node.h" +#include "expr/node_algorithm.h" #include "options/base_options.h" #include "options/expr_options.h" #include "options/language.h" @@ -869,6 +870,8 @@ Result SolverEngine::assertFormula(const Node& formula) finishInit(); d_state->doPendingPops(); + // as an optimization we do not check whether formula is well-formed here, and + // defer this check for certain cases within the assertions module. Trace("smt") << "SolverEngine::assertFormula(" << formula << ")" << endl; // Substitute out any abstract values in ex @@ -980,6 +983,7 @@ Node SolverEngine::getValue(const Node& ex) const { SolverEngineScope smts(this); + ensureWellFormedTerm(ex, "get value"); Trace("smt") << "SMT getValue(" << ex << ")" << endl; TypeNode expectedType = ex.getType(); @@ -1152,6 +1156,11 @@ Result SolverEngine::blockModelValues(const std::vector& exprs) finishInit(); + for (const Node& e : exprs) + { + ensureWellFormedTerm(e, "block model values"); + } + TheoryModel* m = getAvailableModel("block model values"); // get expanded assertions @@ -1199,6 +1208,20 @@ std::vector SolverEngine::getAssertionsInternal() const Options& SolverEngine::options() const { return d_env->getOptions(); } +void SolverEngine::ensureWellFormedTerm(const Node& n, + const std::string& src) const +{ + bool wasShadow = false; + if (expr::hasFreeOrShadowedVar(n, wasShadow)) + { + std::string varType(wasShadow ? "shadowed" : "free"); + std::stringstream se; + se << "Cannot process term with " << varType << " variable in " << src + << "."; + throw ModalException(se.str().c_str()); + } +} + std::vector SolverEngine::getExpandedAssertions() { std::vector easserts = getAssertions(); diff --git a/src/smt/solver_engine.h b/src/smt/solver_engine.h index dd98c674e..3d7dd5be7 100644 --- a/src/smt/solver_engine.h +++ b/src/smt/solver_engine.h @@ -1048,6 +1048,16 @@ class CVC5_EXPORT SolverEngine */ const Options& options() const; + /** + * Check that the given term is a valid closed term, which can be used as an + * argument to, e.g., assert, get-value, block-model-values, etc. + * + * @param n The node to check + * @param src The source of the check, which is printed in the exception if + * this check fails. + */ + void ensureWellFormedTerm(const Node& n, const std::string& src) const; + /* Members -------------------------------------------------------------- */ /** Solver instance that owns this SolverEngine instance. */ diff --git a/test/unit/api/cpp/solver_black.cpp b/test/unit/api/cpp/solver_black.cpp index 3cb5155ab..f8ace3570 100644 --- a/test/unit/api/cpp/solver_black.cpp +++ b/test/unit/api/cpp/solver_black.cpp @@ -3003,5 +3003,21 @@ TEST_F(TestApiBlackSolver, proj_issue414) ASSERT_NO_THROW(slv.simplify(t54)); } +TEST_F(TestApiBlackSolver, proj_issue431) +{ + Solver slv; + slv.setOption("produce-models", "true"); + slv.setOption("produce-unsat-assumptions", "true"); + slv.setOption("produce-assertions", "true"); + Sort s1 = slv.getStringSort(); + Sort s3 = slv.getIntegerSort(); + Sort s7 = slv.mkArraySort(s1, s3); + Term t3 = slv.mkConst(s1, "_x2"); + Term t57 = slv.mkVar(s7, "_x38"); + Term t103 = slv.mkTerm(Kind::SELECT, {t57, t3}); + slv.checkSat(); + ASSERT_THROW(slv.blockModelValues({t103}), CVC5ApiException); +} + } // namespace test } // namespace cvc5 -- 2.30.2