diff options
author | Dan Liew <daniel.liew@imperial.ac.uk> | 2016-01-07 11:29:41 +0000 |
---|---|---|
committer | Dan Liew <daniel.liew@imperial.ac.uk> | 2016-01-12 11:40:39 +0000 |
commit | c02b778b45449684d764fdbbc88648390abab7d7 (patch) | |
tree | a737148bb81ad4d8a17b788311c13dc3579a2ec4 | |
parent | 93d58323eba68e1aa80f1b7210f0d2a0968b2717 (diff) | |
download | klee-c02b778b45449684d764fdbbc88648390abab7d7.tar.gz |
Refactor MetaSMTSolver and MetaSMTSolverImpl out of Solver.cpp into
their own file ``MetaSMTSolver.cpp``. Whilst I'm here also clang-format the modified code. This might not be a NFC (non functional change) as there's a good chance this has broken the MetaSMT build of KLEE. I don't have a build of MetaSMT to hand and there is no TravisCI build. At this point because there is no maintainer for this code I think we should consider removing it as it is going bitrot.
-rw-r--r-- | lib/Solver/MetaSMTSolver.cpp | 466 | ||||
-rw-r--r-- | lib/Solver/Solver.cpp | 462 |
2 files changed, 466 insertions, 462 deletions
diff --git a/lib/Solver/MetaSMTSolver.cpp b/lib/Solver/MetaSMTSolver.cpp new file mode 100644 index 00000000..8394bbf3 --- /dev/null +++ b/lib/Solver/MetaSMTSolver.cpp @@ -0,0 +1,466 @@ +//===-- MetaSMTSolver.cpp -------------------------------------------------===// +// +// The KLEE Symbolic Virtual Machine +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifdef SUPPORT_METASMT + +#include "MetaSMTBuilder.h" +#include "klee/Constraints.h" +#include "klee/Solver.h" +#include "klee/SolverImpl.h" +#include "klee/util/Assignment.h" +#include "klee/util/ExprUtil.h" + +#include <metaSMT/DirectSolver_Context.hpp> +#include <metaSMT/backend/Z3_Backend.hpp> +#include <metaSMT/backend/Boolector.hpp> +#include <metaSMT/backend/MiniSAT.hpp> +#include <metaSMT/support/run_algorithm.hpp> +#include <metaSMT/API/Stack.hpp> +#include <metaSMT/API/Group.hpp> + +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <sys/wait.h> +#include <sys/ipc.h> +#include <sys/shm.h> + + +static unsigned char *shared_memory_ptr; +static int shared_memory_id = 0; +// Darwin by default has a very small limit on the maximum amount of shared +// memory, which will quickly be exhausted by KLEE running its tests in +// parallel. For now, we work around this by just requesting a smaller size -- +// in practice users hitting this limit on counterexample sizes probably already +// are hitting more serious scalability issues. +#ifdef __APPLE__ +static const unsigned shared_memory_size = 1 << 16; +#else +static const unsigned shared_memory_size = 1 << 20; +#endif + +namespace klee { + +template <typename SolverContext> class MetaSMTSolverImpl : public SolverImpl { +private: + SolverContext _meta_solver; + MetaSMTSolver<SolverContext> *_solver; + MetaSMTBuilder<SolverContext> *_builder; + double _timeout; + bool _useForked; + SolverRunStatus _runStatusCode; + +public: + MetaSMTSolverImpl(MetaSMTSolver<SolverContext> *solver, bool useForked, + bool optimizeDivides); + virtual ~MetaSMTSolverImpl(); + + char *getConstraintLog(const Query &); + void setCoreSolverTimeout(double timeout) { _timeout = timeout; } + + bool computeTruth(const Query &, bool &isValid); + bool computeValue(const Query &, ref<Expr> &result); + + bool computeInitialValues(const Query &query, + const std::vector<const Array *> &objects, + std::vector<std::vector<unsigned char> > &values, + bool &hasSolution); + + SolverImpl::SolverRunStatus + runAndGetCex(ref<Expr> query_expr, const std::vector<const Array *> &objects, + std::vector<std::vector<unsigned char> > &values, + bool &hasSolution); + + SolverImpl::SolverRunStatus + runAndGetCexForked(const Query &query, + const std::vector<const Array *> &objects, + std::vector<std::vector<unsigned char> > &values, + bool &hasSolution, double timeout); + + SolverRunStatus getOperationStatusCode(); + + SolverContext &get_meta_solver() { return (_meta_solver); }; +}; + +template <typename SolverContext> +MetaSMTSolverImpl<SolverContext>::MetaSMTSolverImpl( + MetaSMTSolver<SolverContext> *solver, bool useForked, bool optimizeDivides) + : _solver(solver), _builder(new MetaSMTBuilder<SolverContext>( + _meta_solver, optimizeDivides)), + _timeout(0.0), _useForked(useForked) { + assert(_solver && "unable to create MetaSMTSolver"); + assert(_builder && "unable to create MetaSMTBuilder"); + + if (_useForked) { + shared_memory_id = + shmget(IPC_PRIVATE, shared_memory_size, IPC_CREAT | 0700); + assert(shared_memory_id >= 0 && "shmget failed"); + shared_memory_ptr = (unsigned char *)shmat(shared_memory_id, NULL, 0); + assert(shared_memory_ptr != (void *)-1 && "shmat failed"); + shmctl(shared_memory_id, IPC_RMID, NULL); + } +} + +template <typename SolverContext> +MetaSMTSolverImpl<SolverContext>::~MetaSMTSolverImpl() {} + +template <typename SolverContext> +char *MetaSMTSolverImpl<SolverContext>::getConstraintLog(const Query &) { + const char *msg = "Not supported"; + char *buf = new char[strlen(msg) + 1]; + strcpy(buf, msg); + return (buf); +} + +template <typename SolverContext> +bool MetaSMTSolverImpl<SolverContext>::computeTruth(const Query &query, + bool &isValid) { + + bool success = false; + std::vector<const Array *> objects; + std::vector<std::vector<unsigned char> > values; + bool hasSolution; + + if (computeInitialValues(query, objects, values, hasSolution)) { + // query.expr is valid iff !query.expr is not satisfiable + isValid = !hasSolution; + success = true; + } + + return (success); +} + +template <typename SolverContext> +bool MetaSMTSolverImpl<SolverContext>::computeValue(const Query &query, + ref<Expr> &result) { + + bool success = false; + std::vector<const Array *> objects; + std::vector<std::vector<unsigned char> > values; + bool hasSolution; + + // Find the object used in the expression, and compute an assignment for them. + findSymbolicObjects(query.expr, objects); + if (computeInitialValues(query.withFalse(), objects, values, hasSolution)) { + assert(hasSolution && "state has invalid constraint set"); + // Evaluate the expression with the computed assignment. + Assignment a(objects, values); + result = a.evaluate(query.expr); + success = true; + } + + return (success); +} + +template <typename SolverContext> +bool MetaSMTSolverImpl<SolverContext>::computeInitialValues( + const Query &query, const std::vector<const Array *> &objects, + std::vector<std::vector<unsigned char> > &values, bool &hasSolution) { + + _runStatusCode = SOLVER_RUN_STATUS_FAILURE; + + TimerStatIncrementer t(stats::queryTime); + assert(_builder); + + /* + * FIXME push() and pop() work for Z3 but not for Boolector. + * If using Z3, use push() and pop() and assert constraints. + * If using Boolector, assume constrainsts instead of asserting them. + */ + // push(_meta_solver); + + if (!_useForked) { + for (ConstraintManager::const_iterator it = query.constraints.begin(), + ie = query.constraints.end(); + it != ie; ++it) { + // assertion(_meta_solver, _builder->construct(*it)); + assumption(_meta_solver, _builder->construct(*it)); + } + } + + ++stats::queries; + ++stats::queryCounterexamples; + + bool success = true; + if (_useForked) { + _runStatusCode = + runAndGetCexForked(query, objects, values, hasSolution, _timeout); + success = ((SOLVER_RUN_STATUS_SUCCESS_SOLVABLE == _runStatusCode) || + (SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE == _runStatusCode)); + } else { + _runStatusCode = runAndGetCex(query.expr, objects, values, hasSolution); + success = true; + } + + if (success) { + if (hasSolution) { + ++stats::queriesInvalid; + } else { + ++stats::queriesValid; + } + } + + // pop(_meta_solver); + + return (success); +} + +template <typename SolverContext> +SolverImpl::SolverRunStatus MetaSMTSolverImpl<SolverContext>::runAndGetCex( + ref<Expr> query_expr, const std::vector<const Array *> &objects, + std::vector<std::vector<unsigned char> > &values, bool &hasSolution) { + + // assume the negation of the query + assumption(_meta_solver, _builder->construct(Expr::createIsZero(query_expr))); + hasSolution = solve(_meta_solver); + + if (hasSolution) { + values.reserve(objects.size()); + for (std::vector<const Array *>::const_iterator it = objects.begin(), + ie = objects.end(); + it != ie; ++it) { + + const Array *array = *it; + assert(array); + typename SolverContext::result_type array_exp = + _builder->getInitialArray(array); + + std::vector<unsigned char> data; + data.reserve(array->size); + + for (unsigned offset = 0; offset < array->size; offset++) { + typename SolverContext::result_type elem_exp = evaluate( + _meta_solver, metaSMT::logic::Array::select( + array_exp, bvuint(offset, array->getDomain()))); + unsigned char elem_value = metaSMT::read_value(_meta_solver, elem_exp); + data.push_back(elem_value); + } + + values.push_back(data); + } + } + + if (true == hasSolution) { + return (SolverImpl::SOLVER_RUN_STATUS_SUCCESS_SOLVABLE); + } else { + return (SolverImpl::SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE); + } +} + +static void metaSMTTimeoutHandler(int x) { _exit(52); } + +template <typename SolverContext> +SolverImpl::SolverRunStatus +MetaSMTSolverImpl<SolverContext>::runAndGetCexForked( + const Query &query, const std::vector<const Array *> &objects, + std::vector<std::vector<unsigned char> > &values, bool &hasSolution, + double timeout) { + unsigned char *pos = shared_memory_ptr; + unsigned sum = 0; + for (std::vector<const Array *>::const_iterator it = objects.begin(), + ie = objects.end(); + it != ie; ++it) { + sum += (*it)->size; + } + // sum += sizeof(uint64_t); + sum += sizeof(stats::queryConstructs); + assert(sum < shared_memory_size && + "not enough shared memory for counterexample"); + + fflush(stdout); + fflush(stderr); + int pid = fork(); + if (pid == -1) { + fprintf(stderr, "error: fork failed (for metaSMT)"); + return (SolverImpl::SOLVER_RUN_STATUS_FORK_FAILED); + } + + if (pid == 0) { + if (timeout) { + ::alarm(0); /* Turn off alarm so we can safely set signal handler */ + ::signal(SIGALRM, metaSMTTimeoutHandler); + ::alarm(std::max(1, (int)timeout)); + } + + for (ConstraintManager::const_iterator it = query.constraints.begin(), + ie = query.constraints.end(); + it != ie; ++it) { + assertion(_meta_solver, _builder->construct(*it)); + // assumption(_meta_solver, _builder->construct(*it)); + } + + std::vector<std::vector<typename SolverContext::result_type> > + aux_arr_exprs; + if (UseMetaSMT == METASMT_BACKEND_BOOLECTOR) { + for (std::vector<const Array *>::const_iterator it = objects.begin(), + ie = objects.end(); + it != ie; ++it) { + + std::vector<typename SolverContext::result_type> aux_arr; + const Array *array = *it; + assert(array); + typename SolverContext::result_type array_exp = + _builder->getInitialArray(array); + + for (unsigned offset = 0; offset < array->size; offset++) { + typename SolverContext::result_type elem_exp = evaluate( + _meta_solver, metaSMT::logic::Array::select( + array_exp, bvuint(offset, array->getDomain()))); + aux_arr.push_back(elem_exp); + } + aux_arr_exprs.push_back(aux_arr); + } + assert(aux_arr_exprs.size() == objects.size()); + } + + // assume the negation of the query + // can be also asserted instead of assumed as we are in a child process + assumption(_meta_solver, + _builder->construct(Expr::createIsZero(query.expr))); + unsigned res = solve(_meta_solver); + + if (res) { + + if (UseMetaSMT != METASMT_BACKEND_BOOLECTOR) { + + for (std::vector<const Array *>::const_iterator it = objects.begin(), + ie = objects.end(); + it != ie; ++it) { + + const Array *array = *it; + assert(array); + typename SolverContext::result_type array_exp = + _builder->getInitialArray(array); + + for (unsigned offset = 0; offset < array->size; offset++) { + + typename SolverContext::result_type elem_exp = + evaluate(_meta_solver, + metaSMT::logic::Array::select( + array_exp, bvuint(offset, array->getDomain()))); + unsigned char elem_value = + metaSMT::read_value(_meta_solver, elem_exp); + *pos++ = elem_value; + } + } + } else { + typename std::vector< + std::vector<typename SolverContext::result_type> >::const_iterator + eit = aux_arr_exprs.begin(), + eie = aux_arr_exprs.end(); + for (std::vector<const Array *>::const_iterator it = objects.begin(), + ie = objects.end(); + it != ie, eit != eie; ++it, ++eit) { + const Array *array = *it; + const std::vector<typename SolverContext::result_type> &arr_exp = + *eit; + assert(array); + assert(array->size == arr_exp.size()); + + for (unsigned offset = 0; offset < array->size; offset++) { + unsigned char elem_value = + metaSMT::read_value(_meta_solver, arr_exp[offset]); + *pos++ = elem_value; + } + } + } + } + assert((uint64_t *)pos); + *((uint64_t *)pos) = stats::queryConstructs; + + _exit(!res); + } else { + int status; + pid_t res; + + do { + res = waitpid(pid, &status, 0); + } while (res < 0 && errno == EINTR); + + if (res < 0) { + fprintf(stderr, "error: waitpid() for metaSMT failed"); + return (SolverImpl::SOLVER_RUN_STATUS_WAITPID_FAILED); + } + + // From timed_run.py: It appears that linux at least will on + // "occasion" return a status when the process was terminated by a + // signal, so test signal first. + if (WIFSIGNALED(status) || !WIFEXITED(status)) { + fprintf(stderr, + "error: metaSMT did not return successfully (status = %d) \n", + WTERMSIG(status)); + return (SolverImpl::SOLVER_RUN_STATUS_INTERRUPTED); + } + + int exitcode = WEXITSTATUS(status); + if (exitcode == 0) { + hasSolution = true; + } else if (exitcode == 1) { + hasSolution = false; + } else if (exitcode == 52) { + fprintf(stderr, "error: metaSMT timed out"); + return (SolverImpl::SOLVER_RUN_STATUS_TIMEOUT); + } else { + fprintf(stderr, "error: metaSMT did not return a recognized code"); + return (SolverImpl::SOLVER_RUN_STATUS_UNEXPECTED_EXIT_CODE); + } + + if (hasSolution) { + values = std::vector<std::vector<unsigned char> >(objects.size()); + unsigned i = 0; + for (std::vector<const Array *>::const_iterator it = objects.begin(), + ie = objects.end(); + it != ie; ++it) { + const Array *array = *it; + assert(array); + std::vector<unsigned char> &data = values[i++]; + data.insert(data.begin(), pos, pos + array->size); + pos += array->size; + } + } + stats::queryConstructs += (*((uint64_t *)pos) - stats::queryConstructs); + + if (true == hasSolution) { + return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_SOLVABLE; + } else { + return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE; + } + } +} + +template <typename SolverContext> +SolverImpl::SolverRunStatus +MetaSMTSolverImpl<SolverContext>::getOperationStatusCode() { + return _runStatusCode; +} + +template class MetaSMTSolver<DirectSolver_Context<Boolector> >; +template class MetaSMTSolver<DirectSolver_Context<Z3_Backend> >; +template class MetaSMTSolver<DirectSolver_Context<STP_Backend> >; + +template <typename SolverContext> +MetaSMTSolver<SolverContext>::MetaSMTSolver(bool useForked, + bool optimizeDivides) + : Solver(new MetaSMTSolverImpl<SolverContext>(this, useForked, + optimizeDivides)) {} + +template <typename SolverContext> +MetaSMTSolver<SolverContext>::~MetaSMTSolver() {} + +template <typename SolverContext> +char *MetaSMTSolver<SolverContext>::getConstraintLog(const Query &query) { + return (impl->getConstraintLog(query)); +} + +template <typename SolverContext> +void MetaSMTSolver<SolverContext>::setCoreSolverTimeout(double timeout) { + impl->setCoreSolverTimeout(timeout); +} +} +#endif // SUPPORT_METASMT diff --git a/lib/Solver/Solver.cpp b/lib/Solver/Solver.cpp index a391ada4..bb4bef69 100644 --- a/lib/Solver/Solver.cpp +++ b/lib/Solver/Solver.cpp @@ -10,7 +10,6 @@ #include "klee/Solver.h" #include "klee/SolverImpl.h" -#include "MetaSMTBuilder.h" #include "klee/Constraints.h" #include "klee/Expr.h" @@ -29,34 +28,11 @@ #include <map> #include <vector> -#include <errno.h> -#include <unistd.h> -#include <signal.h> -#include <sys/wait.h> -#include <sys/ipc.h> -#include <sys/shm.h> - #include "llvm/Support/ErrorHandling.h" using namespace klee; - -#ifdef SUPPORT_METASMT - -#include <metaSMT/DirectSolver_Context.hpp> -#include <metaSMT/backend/Z3_Backend.hpp> -#include <metaSMT/backend/Boolector.hpp> -#include <metaSMT/backend/MiniSAT.hpp> -#include <metaSMT/support/run_algorithm.hpp> -#include <metaSMT/API/Stack.hpp> -#include <metaSMT/API/Group.hpp> - -using namespace metaSMT; -using namespace metaSMT::solver; - -#endif /* SUPPORT_METASMT */ - const char *Solver::validity_to_str(Validity v) { switch (v) { default: return "Unknown"; @@ -264,444 +240,6 @@ std::pair< ref<Expr>, ref<Expr> > Solver::getRange(const Query& query) { ConstantExpr::create(max, width)); } -/***/ - -#ifdef SUPPORT_METASMT - -static unsigned char *shared_memory_ptr; -static int shared_memory_id = 0; -// Darwin by default has a very small limit on the maximum amount of shared -// memory, which will quickly be exhausted by KLEE running its tests in -// parallel. For now, we work around this by just requesting a smaller size -- -// in practice users hitting this limit on counterexample sizes probably already -// are hitting more serious scalability issues. -#ifdef __APPLE__ -static const unsigned shared_memory_size = 1<<16; -#else -static const unsigned shared_memory_size = 1<<20; -#endif - -// ------------------------------------- MetaSMTSolverImpl class declaration ------------------------------ - -template<typename SolverContext> -class MetaSMTSolverImpl : public SolverImpl { -private: - - SolverContext _meta_solver; - MetaSMTSolver<SolverContext> *_solver; - MetaSMTBuilder<SolverContext> *_builder; - double _timeout; - bool _useForked; - SolverRunStatus _runStatusCode; - -public: - MetaSMTSolverImpl(MetaSMTSolver<SolverContext> *solver, bool useForked, bool optimizeDivides); - virtual ~MetaSMTSolverImpl(); - - char *getConstraintLog(const Query&); - void setCoreSolverTimeout(double timeout) { _timeout = timeout; } - - bool computeTruth(const Query&, bool &isValid); - bool computeValue(const Query&, ref<Expr> &result); - - bool computeInitialValues(const Query &query, - const std::vector<const Array*> &objects, - std::vector< std::vector<unsigned char> > &values, - bool &hasSolution); - - SolverImpl::SolverRunStatus runAndGetCex(ref<Expr> query_expr, - const std::vector<const Array*> &objects, - std::vector< std::vector<unsigned char> > &values, - bool &hasSolution); - - SolverImpl::SolverRunStatus runAndGetCexForked(const Query &query, - const std::vector<const Array*> &objects, - std::vector< std::vector<unsigned char> > &values, - bool &hasSolution, - double timeout); - - SolverRunStatus getOperationStatusCode(); - - SolverContext& get_meta_solver() { return(_meta_solver); }; - -}; - - -// ------------------------------------- MetaSMTSolver methods -------------------------------------------- - - -template<typename SolverContext> -MetaSMTSolver<SolverContext>::MetaSMTSolver(bool useForked, bool optimizeDivides) - : Solver(new MetaSMTSolverImpl<SolverContext>(this, useForked, optimizeDivides)) -{ - -} - -template<typename SolverContext> -MetaSMTSolver<SolverContext>::~MetaSMTSolver() -{ - -} - -template<typename SolverContext> -char *MetaSMTSolver<SolverContext>::getConstraintLog(const Query& query) { - return(impl->getConstraintLog(query)); -} - -template<typename SolverContext> -void MetaSMTSolver<SolverContext>::setCoreSolverTimeout(double timeout) { - impl->setCoreSolverTimeout(timeout); -} - - -// ------------------------------------- MetaSMTSolverImpl methods ---------------------------------------- - - - -template<typename SolverContext> -MetaSMTSolverImpl<SolverContext>::MetaSMTSolverImpl(MetaSMTSolver<SolverContext> *solver, bool useForked, bool optimizeDivides) - : _solver(solver), - _builder(new MetaSMTBuilder<SolverContext>(_meta_solver, optimizeDivides)), - _timeout(0.0), - _useForked(useForked) -{ - assert(_solver && "unable to create MetaSMTSolver"); - assert(_builder && "unable to create MetaSMTBuilder"); - - if (_useForked) { - shared_memory_id = shmget(IPC_PRIVATE, shared_memory_size, IPC_CREAT | 0700); - assert(shared_memory_id >= 0 && "shmget failed"); - shared_memory_ptr = (unsigned char*) shmat(shared_memory_id, NULL, 0); - assert(shared_memory_ptr != (void*) -1 && "shmat failed"); - shmctl(shared_memory_id, IPC_RMID, NULL); - } -} - -template<typename SolverContext> -MetaSMTSolverImpl<SolverContext>::~MetaSMTSolverImpl() { - -} - -template<typename SolverContext> -char *MetaSMTSolverImpl<SolverContext>::getConstraintLog(const Query&) { - const char* msg = "Not supported"; - char *buf = new char[strlen(msg) + 1]; - strcpy(buf, msg); - return(buf); -} - -template<typename SolverContext> -bool MetaSMTSolverImpl<SolverContext>::computeTruth(const Query& query, bool &isValid) { - - bool success = false; - std::vector<const Array*> objects; - std::vector< std::vector<unsigned char> > values; - bool hasSolution; - - if (computeInitialValues(query, objects, values, hasSolution)) { - // query.expr is valid iff !query.expr is not satisfiable - isValid = !hasSolution; - success = true; - } - - return(success); -} - -template<typename SolverContext> -bool MetaSMTSolverImpl<SolverContext>::computeValue(const Query& query, ref<Expr> &result) { - - bool success = false; - std::vector<const Array*> objects; - std::vector< std::vector<unsigned char> > values; - bool hasSolution; - - // Find the object used in the expression, and compute an assignment for them. - findSymbolicObjects(query.expr, objects); - if (computeInitialValues(query.withFalse(), objects, values, hasSolution)) { - assert(hasSolution && "state has invalid constraint set"); - // Evaluate the expression with the computed assignment. - Assignment a(objects, values); - result = a.evaluate(query.expr); - success = true; - } - - return(success); -} - - -template<typename SolverContext> -bool MetaSMTSolverImpl<SolverContext>::computeInitialValues(const Query &query, - const std::vector<const Array*> &objects, - std::vector< std::vector<unsigned char> > &values, - bool &hasSolution) { - - _runStatusCode = SOLVER_RUN_STATUS_FAILURE; - - TimerStatIncrementer t(stats::queryTime); - assert(_builder); - - /* - * FIXME push() and pop() work for Z3 but not for Boolector. - * If using Z3, use push() and pop() and assert constraints. - * If using Boolector, assume constrainsts instead of asserting them. - */ - //push(_meta_solver); - - if (!_useForked) { - for (ConstraintManager::const_iterator it = query.constraints.begin(), ie = query.constraints.end(); it != ie; ++it) { - //assertion(_meta_solver, _builder->construct(*it)); - assumption(_meta_solver, _builder->construct(*it)); - } - } - - ++stats::queries; - ++stats::queryCounterexamples; - - bool success = true; - if (_useForked) { - _runStatusCode = runAndGetCexForked(query, objects, values, hasSolution, _timeout); - success = ((SOLVER_RUN_STATUS_SUCCESS_SOLVABLE == _runStatusCode) || (SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE == _runStatusCode)); - } - else { - _runStatusCode = runAndGetCex(query.expr, objects, values, hasSolution); - success = true; - } - - if (success) { - if (hasSolution) { - ++stats::queriesInvalid; - } - else { - ++stats::queriesValid; - } - } - - //pop(_meta_solver); - - return(success); -} - -template<typename SolverContext> -SolverImpl::SolverRunStatus MetaSMTSolverImpl<SolverContext>::runAndGetCex(ref<Expr> query_expr, - const std::vector<const Array*> &objects, - std::vector< std::vector<unsigned char> > &values, - bool &hasSolution) -{ - - // assume the negation of the query - assumption(_meta_solver, _builder->construct(Expr::createIsZero(query_expr))); - hasSolution = solve(_meta_solver); - - if (hasSolution) { - values.reserve(objects.size()); - for (std::vector<const Array*>::const_iterator it = objects.begin(), ie = objects.end(); it != ie; ++it) { - - const Array *array = *it; - assert(array); - typename SolverContext::result_type array_exp = _builder->getInitialArray(array); - - std::vector<unsigned char> data; - data.reserve(array->size); - - for (unsigned offset = 0; offset < array->size; offset++) { - typename SolverContext::result_type elem_exp = evaluate( - _meta_solver, - metaSMT::logic::Array::select(array_exp, bvuint(offset, array->getDomain()))); - unsigned char elem_value = metaSMT::read_value(_meta_solver, elem_exp); - data.push_back(elem_value); - } - - values.push_back(data); - } - } - - if (true == hasSolution) { - return(SolverImpl::SOLVER_RUN_STATUS_SUCCESS_SOLVABLE); - } - else { - return(SolverImpl::SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE); - } -} - -static void metaSMTTimeoutHandler(int x) { - _exit(52); -} - -template<typename SolverContext> -SolverImpl::SolverRunStatus MetaSMTSolverImpl<SolverContext>::runAndGetCexForked(const Query &query, - const std::vector<const Array*> &objects, - std::vector< std::vector<unsigned char> > &values, - bool &hasSolution, - double timeout) -{ - unsigned char *pos = shared_memory_ptr; - unsigned sum = 0; - for (std::vector<const Array*>::const_iterator it = objects.begin(), ie = objects.end(); it != ie; ++it) { - sum += (*it)->size; - } - // sum += sizeof(uint64_t); - sum += sizeof(stats::queryConstructs); - assert(sum < shared_memory_size && "not enough shared memory for counterexample"); - - fflush(stdout); - fflush(stderr); - int pid = fork(); - if (pid == -1) { - fprintf(stderr, "error: fork failed (for metaSMT)"); - return(SolverImpl::SOLVER_RUN_STATUS_FORK_FAILED); - } - - if (pid == 0) { - if (timeout) { - ::alarm(0); /* Turn off alarm so we can safely set signal handler */ - ::signal(SIGALRM, metaSMTTimeoutHandler); - ::alarm(std::max(1, (int) timeout)); - } - - for (ConstraintManager::const_iterator it = query.constraints.begin(), ie = query.constraints.end(); it != ie; ++it) { - assertion(_meta_solver, _builder->construct(*it)); - //assumption(_meta_solver, _builder->construct(*it)); - } - - - std::vector< std::vector<typename SolverContext::result_type> > aux_arr_exprs; - if (UseMetaSMT == METASMT_BACKEND_BOOLECTOR) { - for (std::vector<const Array*>::const_iterator it = objects.begin(), ie = objects.end(); it != ie; ++it) { - - std::vector<typename SolverContext::result_type> aux_arr; - const Array *array = *it; - assert(array); - typename SolverContext::result_type array_exp = _builder->getInitialArray(array); - - for (unsigned offset = 0; offset < array->size; offset++) { - typename SolverContext::result_type elem_exp = evaluate( - _meta_solver, - metaSMT::logic::Array::select(array_exp, bvuint(offset, array->getDomain()))); - aux_arr.push_back(elem_exp); - } - aux_arr_exprs.push_back(aux_arr); - } - assert(aux_arr_exprs.size() == objects.size()); - } - - - // assume the negation of the query - // can be also asserted instead of assumed as we are in a child process - assumption(_meta_solver, _builder->construct(Expr::createIsZero(query.expr))); - unsigned res = solve(_meta_solver); - - if (res) { - - if (UseMetaSMT != METASMT_BACKEND_BOOLECTOR) { - - for (std::vector<const Array*>::const_iterator it = objects.begin(), ie = objects.end(); it != ie; ++it) { - - const Array *array = *it; - assert(array); - typename SolverContext::result_type array_exp = _builder->getInitialArray(array); - - for (unsigned offset = 0; offset < array->size; offset++) { - - typename SolverContext::result_type elem_exp = evaluate( - _meta_solver, - metaSMT::logic::Array::select(array_exp, bvuint(offset, array->getDomain()))); - unsigned char elem_value = metaSMT::read_value(_meta_solver, elem_exp); - *pos++ = elem_value; - } - } - } - else { - typename std::vector< std::vector<typename SolverContext::result_type> >::const_iterator eit = aux_arr_exprs.begin(), eie = aux_arr_exprs.end(); - for (std::vector<const Array*>::const_iterator it = objects.begin(), ie = objects.end(); it != ie, eit != eie; ++it, ++eit) { - const Array *array = *it; - const std::vector<typename SolverContext::result_type>& arr_exp = *eit; - assert(array); - assert(array->size == arr_exp.size()); - - for (unsigned offset = 0; offset < array->size; offset++) { - unsigned char elem_value = metaSMT::read_value(_meta_solver, arr_exp[offset]); - *pos++ = elem_value; - } - } - } - } - assert((uint64_t*) pos); - *((uint64_t*) pos) = stats::queryConstructs; - - _exit(!res); - } - else { - int status; - pid_t res; - - do { - res = waitpid(pid, &status, 0); - } - while (res < 0 && errno == EINTR); - - if (res < 0) { - fprintf(stderr, "error: waitpid() for metaSMT failed"); - return(SolverImpl::SOLVER_RUN_STATUS_WAITPID_FAILED); - } - - // From timed_run.py: It appears that linux at least will on - // "occasion" return a status when the process was terminated by a - // signal, so test signal first. - if (WIFSIGNALED(status) || !WIFEXITED(status)) { - fprintf(stderr, "error: metaSMT did not return successfully (status = %d) \n", WTERMSIG(status)); - return(SolverImpl::SOLVER_RUN_STATUS_INTERRUPTED); - } - - int exitcode = WEXITSTATUS(status); - if (exitcode == 0) { - hasSolution = true; - } - else if (exitcode == 1) { - hasSolution = false; - } - else if (exitcode == 52) { - fprintf(stderr, "error: metaSMT timed out"); - return(SolverImpl::SOLVER_RUN_STATUS_TIMEOUT); - } - else { - fprintf(stderr, "error: metaSMT did not return a recognized code"); - return(SolverImpl::SOLVER_RUN_STATUS_UNEXPECTED_EXIT_CODE); - } - - if (hasSolution) { - values = std::vector< std::vector<unsigned char> >(objects.size()); - unsigned i = 0; - for (std::vector<const Array*>::const_iterator it = objects.begin(), ie = objects.end(); it != ie; ++it) { - const Array *array = *it; - assert(array); - std::vector<unsigned char> &data = values[i++]; - data.insert(data.begin(), pos, pos + array->size); - pos += array->size; - } - } - stats::queryConstructs += (*((uint64_t*) pos) - stats::queryConstructs); - - if (true == hasSolution) { - return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_SOLVABLE; - } - else { - return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE; - } - } -} - -template<typename SolverContext> -SolverImpl::SolverRunStatus MetaSMTSolverImpl<SolverContext>::getOperationStatusCode() { - return _runStatusCode; -} - -template class MetaSMTSolver< DirectSolver_Context < Boolector> >; -template class MetaSMTSolver< DirectSolver_Context < Z3_Backend> >; -template class MetaSMTSolver< DirectSolver_Context < STP_Backend> >; - -#endif /* SUPPORT_METASMT */ -/// - void Query::dump() const { llvm::errs() << "Constraints [\n"; for (ConstraintManager::const_iterator i = constraints.begin(); |