9#include "klee/Config/config.h"
22#include "llvm/Support/ErrorHandling.h"
24#include <metaSMT/DirectSolver_Context.hpp>
27#include <metaSMT/backend/Z3_Backend.hpp>
30#ifdef METASMT_HAVE_BTOR
31#include <metaSMT/backend/Boolector.hpp>
34#ifdef METASMT_HAVE_CVC4
35#include <metaSMT/backend/CVC4.hpp>
38#ifdef METASMT_HAVE_YICES2
39#include <metaSMT/backend/Yices2.hpp>
42#ifdef METASMT_HAVE_STP
45#define STP STP_Backend
46#define type_t STP_type_t
47#include <metaSMT/backend/STP.hpp>
61static unsigned char *shared_memory_ptr;
62static int shared_memory_id = 0;
69static const unsigned shared_memory_size = 1 << 16;
71static const unsigned shared_memory_size = 1 << 20;
76template <
typename SolverContext>
class MetaSMTSolverImpl :
public SolverImpl {
78 SolverContext _meta_solver;
79 MetaSMTSolver<SolverContext> *_solver;
80 MetaSMTBuilder<SolverContext> *_builder;
83 SolverRunStatus _runStatusCode;
86 MetaSMTSolverImpl(MetaSMTSolver<SolverContext> *solver,
bool useForked,
87 bool optimizeDivides);
88 virtual ~MetaSMTSolverImpl();
90 char *getConstraintLog(
const Query &);
91 void setCoreSolverTimeout(time::Span timeout) { _timeout = timeout; }
93 bool computeTruth(
const Query &,
bool &isValid);
94 bool computeValue(
const Query &, ref<Expr> &result);
96 bool computeInitialValues(
const Query &query,
97 const std::vector<const Array *> &objects,
98 std::vector<std::vector<unsigned char> > &values,
102 runAndGetCex(
const Query &query,
const std::vector<const Array *> &objects,
103 std::vector<std::vector<unsigned char> > &values,
107 runAndGetCexForked(
const Query &query,
108 const std::vector<const Array *> &objects,
109 std::vector<std::vector<unsigned char> > &values,
110 bool &hasSolution, time::Span timeout);
112 SolverRunStatus getOperationStatusCode();
114 SolverContext &get_meta_solver() {
return _meta_solver; };
117template <
typename SolverContext>
118MetaSMTSolverImpl<SolverContext>::MetaSMTSolverImpl(
119 MetaSMTSolver<SolverContext> *solver,
bool useForked,
bool optimizeDivides)
120 : _solver(solver), _builder(new MetaSMTBuilder<SolverContext>(
121 _meta_solver, optimizeDivides)),
122 _useForked(useForked) {
123 assert(_solver &&
"unable to create MetaSMTSolver");
124 assert(_builder &&
"unable to create MetaSMTBuilder");
128 shmget(IPC_PRIVATE, shared_memory_size, IPC_CREAT | 0700);
129 assert(shared_memory_id >= 0 &&
"shmget failed");
130 shared_memory_ptr = (
unsigned char *)shmat(shared_memory_id, NULL, 0);
131 assert(shared_memory_ptr != (
void *)-1 &&
"shmat failed");
132 shmctl(shared_memory_id, IPC_RMID, NULL);
136template <
typename SolverContext>
137MetaSMTSolverImpl<SolverContext>::~MetaSMTSolverImpl() {}
139template <
typename SolverContext>
140char *MetaSMTSolverImpl<SolverContext>::getConstraintLog(
const Query &) {
141 const char *msg =
"Not supported";
142 char *buf =
new char[strlen(msg) + 1];
147template <
typename SolverContext>
148bool MetaSMTSolverImpl<SolverContext>::computeTruth(
const Query &query,
151 bool success =
false;
152 std::vector<const Array *> objects;
153 std::vector<std::vector<unsigned char> > values;
156 if (computeInitialValues(query, objects, values, hasSolution)) {
158 isValid = !hasSolution;
165template <
typename SolverContext>
166bool MetaSMTSolverImpl<SolverContext>::computeValue(
const Query &query,
169 bool success =
false;
170 std::vector<const Array *> objects;
171 std::vector<std::vector<unsigned char> > values;
176 if (computeInitialValues(query.withFalse(), objects, values, hasSolution)) {
177 assert(hasSolution &&
"state has invalid constraint set");
179 Assignment a(objects, values);
180 result = a.evaluate(query.expr);
187template <
typename SolverContext>
188bool MetaSMTSolverImpl<SolverContext>::computeInitialValues(
189 const Query &query,
const std::vector<const Array *> &objects,
190 std::vector<std::vector<unsigned char> > &values,
bool &hasSolution) {
192 _runStatusCode = SOLVER_RUN_STATUS_FAILURE;
203 runAndGetCexForked(query, objects, values, hasSolution, _timeout);
204 success = ((SOLVER_RUN_STATUS_SUCCESS_SOLVABLE == _runStatusCode) ||
205 (SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE == _runStatusCode));
207 _runStatusCode = runAndGetCex(query, objects, values, hasSolution);
222template <
typename SolverContext>
223SolverImpl::SolverRunStatus MetaSMTSolverImpl<SolverContext>::runAndGetCex(
224 const Query &query,
const std::vector<const Array *> &objects,
225 std::vector<std::vector<unsigned char> > &values,
bool &hasSolution) {
228 for (
auto &constraint : query.constraints)
229 assumption(_meta_solver, _builder->construct(constraint));
232 assumption(_meta_solver, _builder->construct(Expr::createIsZero(query.expr)));
233 hasSolution = solve(_meta_solver);
236 values.reserve(objects.size());
237 for (std::vector<const Array *>::const_iterator it = objects.begin(),
241 const Array *array = *it;
243 typename SolverContext::result_type array_exp =
244 _builder->getInitialArray(array);
246 std::vector<unsigned char> data;
247 data.reserve(array->size);
249 for (
unsigned offset = 0; offset < array->size; offset++) {
250 typename SolverContext::result_type elem_exp = evaluate(
251 _meta_solver, metaSMT::logic::Array::select(
252 array_exp, bvuint(offset, array->getDomain())));
253 unsigned char elem_value = metaSMT::read_value(_meta_solver, elem_exp);
254 data.push_back(elem_value);
257 values.push_back(data);
261 if (
true == hasSolution) {
262 return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_SOLVABLE;
264 return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE;
268static void metaSMTTimeoutHandler(
int x) { _exit(52); }
270template <
typename SolverContext>
271SolverImpl::SolverRunStatus
272MetaSMTSolverImpl<SolverContext>::runAndGetCexForked(
273 const Query &query,
const std::vector<const Array *> &objects,
274 std::vector<std::vector<unsigned char> > &values,
bool &hasSolution,
275 time::Span timeout) {
276 unsigned char *pos = shared_memory_ptr;
278 for (std::vector<const Array *>::const_iterator it = objects.begin(),
285 assert(sum < shared_memory_size &&
286 "not enough shared memory for counterexample");
293 return SolverImpl::SOLVER_RUN_STATUS_FORK_FAILED;
299 ::signal(SIGALRM, metaSMTTimeoutHandler);
300 ::alarm(std::max(1u,
static_cast<unsigned>(timeout.toSeconds())));
304 for (
const auto &constraint : query.constraints) {
305 assertion(_meta_solver, _builder->construct(constraint));
310 assertion(_meta_solver,
311 _builder->construct(Expr::createIsZero(query.expr)));
312 unsigned res = solve(_meta_solver);
315 for (std::vector<const Array *>::const_iterator it = objects.begin(),
319 const Array *array = *it;
321 typename SolverContext::result_type array_exp =
322 _builder->getInitialArray(array);
324 for (
unsigned offset = 0; offset < array->size; offset++) {
326 typename SolverContext::result_type elem_exp = evaluate(
327 _meta_solver, metaSMT::logic::Array::select(
328 array_exp, bvuint(offset, array->getDomain())));
329 unsigned char elem_value =
330 metaSMT::read_value(_meta_solver, elem_exp);
335 assert((uint64_t *)pos);
344 res = waitpid(pid, &status, 0);
345 }
while (res < 0 && errno == EINTR);
349 return SolverImpl::SOLVER_RUN_STATUS_WAITPID_FAILED;
355 if (WIFSIGNALED(status) || !WIFEXITED(status)) {
357 "error: metaSMT did not return successfully (status = %d) \n",
359 return SolverImpl::SOLVER_RUN_STATUS_INTERRUPTED;
362 int exitcode = WEXITSTATUS(status);
365 }
else if (exitcode == 1) {
367 }
else if (exitcode == 52) {
369 return SolverImpl::SOLVER_RUN_STATUS_TIMEOUT;
371 klee_warning(
"metaSMT did not return a recognized code");
372 return SolverImpl::SOLVER_RUN_STATUS_UNEXPECTED_EXIT_CODE;
376 values = std::vector<std::vector<unsigned char> >(objects.size());
378 for (std::vector<const Array *>::const_iterator it = objects.begin(),
381 const Array *array = *it;
383 std::vector<unsigned char> &data = values[i++];
384 data.insert(data.begin(), pos, pos + array->size);
390 if (
true == hasSolution) {
391 return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_SOLVABLE;
393 return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE;
398template <
typename SolverContext>
399SolverImpl::SolverRunStatus
400MetaSMTSolverImpl<SolverContext>::getOperationStatusCode() {
401 return _runStatusCode;
404template <
typename SolverContext>
405MetaSMTSolver<SolverContext>::MetaSMTSolver(
bool useForked,
406 bool optimizeDivides)
407 : Solver(new MetaSMTSolverImpl<SolverContext>(this, useForked,
410template <
typename SolverContext>
411MetaSMTSolver<SolverContext>::~MetaSMTSolver() {}
413template <
typename SolverContext>
414char *MetaSMTSolver<SolverContext>::getConstraintLog(
const Query &query) {
415 return impl->getConstraintLog(query);
418template <
typename SolverContext>
419void MetaSMTSolver<SolverContext>::setCoreSolverTimeout(time::Span timeout) {
420 impl->setCoreSolverTimeout(timeout);
424 using namespace metaSMT;
426 Solver *coreSolver = NULL;
428 switch (MetaSMTBackend) {
429#ifdef METASMT_HAVE_STP
430 case METASMT_BACKEND_STP:
432 coreSolver =
new MetaSMTSolver<DirectSolver_Context<solver::STP_Backend> >(
436#ifdef METASMT_HAVE_Z3
437 case METASMT_BACKEND_Z3:
439 coreSolver =
new MetaSMTSolver<DirectSolver_Context<solver::Z3_Backend> >(
443#ifdef METASMT_HAVE_BTOR
444 case METASMT_BACKEND_BOOLECTOR:
445 backend =
"Boolector";
446 coreSolver =
new MetaSMTSolver<DirectSolver_Context<solver::Boolector> >(
450#ifdef METASMT_HAVE_CVC4
451 case METASMT_BACKEND_CVC4:
453 coreSolver =
new MetaSMTSolver<DirectSolver_Context<solver::CVC4> >(
457#ifdef METASMT_HAVE_YICES2
458 case METASMT_BACKEND_YICES2:
460 coreSolver =
new MetaSMTSolver<DirectSolver_Context<solver::Yices2> >(
465 llvm_unreachable(
"Unrecognised MetaSMT backend");
468 klee_message(
"Starting MetaSMTSolver(%s)", backend.c_str());
void klee_warning(char *name)
Statistic queryConstructs
Statistic queryCounterexamples
void findSymbolicObjects(ref< Expr > e, std::vector< const Array * > &results)
Solver * createMetaSMTSolver()
void klee_message(const char *msg,...) __attribute__((format(printf
llvm::cl::opt< bool > UseForkedCoreSolver
llvm::cl::opt< bool > CoreSolverOptimizeDivides