00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "klee/Solver.h"
00011 #include "klee/SolverImpl.h"
00012
00013 #include "SolverStats.h"
00014 #include "STPBuilder.h"
00015
00016 #include "klee/Constraints.h"
00017 #include "klee/Expr.h"
00018 #include "klee/TimerStatIncrementer.h"
00019 #include "klee/util/Assignment.h"
00020 #include "klee/util/ExprPPrinter.h"
00021 #include "klee/util/ExprUtil.h"
00022 #include "klee/Internal/Support/Timer.h"
00023
00024 #define vc_bvBoolExtract IAMTHESPAWNOFSATAN
00025
00026 #include <cassert>
00027 #include <cstdio>
00028 #include <map>
00029 #include <vector>
00030
00031 #include <signal.h>
00032 #include <sys/wait.h>
00033 #include <sys/ipc.h>
00034 #include <sys/shm.h>
00035
00036 using namespace klee;
00037
00038
00039
00040 const char *Solver::validity_to_str(Validity v) {
00041 switch (v) {
00042 default: return "Unknown";
00043 case True: return "True";
00044 case False: return "False";
00045 }
00046 }
00047
00048 Solver::~Solver() {
00049 delete impl;
00050 }
00051
00052 SolverImpl::~SolverImpl() {
00053 }
00054
00055 bool Solver::evaluate(const Query& query, Validity &result) {
00056 assert(query.expr->getWidth() == Expr::Bool && "Invalid expression type!");
00057
00058
00059 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(query.expr)) {
00060 result = CE->getConstantValue() ? True : False;
00061 return true;
00062 }
00063
00064 return impl->computeValidity(query, result);
00065 }
00066
00067 bool SolverImpl::computeValidity(const Query& query, Solver::Validity &result) {
00068 bool isTrue, isFalse;
00069 if (!computeTruth(query, isTrue))
00070 return false;
00071 if (isTrue) {
00072 result = Solver::True;
00073 } else {
00074 if (!computeTruth(query.negateExpr(), isFalse))
00075 return false;
00076 result = isFalse ? Solver::False : Solver::Unknown;
00077 }
00078 return true;
00079 }
00080
00081 bool Solver::mustBeTrue(const Query& query, bool &result) {
00082 assert(query.expr->getWidth() == Expr::Bool && "Invalid expression type!");
00083
00084
00085 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(query.expr)) {
00086 result = CE->getConstantValue() ? true : false;
00087 return true;
00088 }
00089
00090 return impl->computeTruth(query, result);
00091 }
00092
00093 bool Solver::mustBeFalse(const Query& query, bool &result) {
00094 return mustBeTrue(query.negateExpr(), result);
00095 }
00096
00097 bool Solver::mayBeTrue(const Query& query, bool &result) {
00098 bool res;
00099 if (!mustBeFalse(query, res))
00100 return false;
00101 result = !res;
00102 return true;
00103 }
00104
00105 bool Solver::mayBeFalse(const Query& query, bool &result) {
00106 bool res;
00107 if (!mustBeTrue(query, res))
00108 return false;
00109 result = !res;
00110 return true;
00111 }
00112
00113 bool Solver::getValue(const Query& query, ref<ConstantExpr> &result) {
00114
00115 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(query.expr)) {
00116 result = CE;
00117 return true;
00118 }
00119
00120
00121 ref<Expr> tmp;
00122 if (!impl->computeValue(query, tmp))
00123 return false;
00124
00125 result = cast<ConstantExpr>(tmp);
00126 return true;
00127 }
00128
00129 bool
00130 Solver::getInitialValues(const Query& query,
00131 const std::vector<const Array*> &objects,
00132 std::vector< std::vector<unsigned char> > &values) {
00133 bool hasSolution;
00134 bool success =
00135 impl->computeInitialValues(query, objects, values, hasSolution);
00136
00137 if (!hasSolution)
00138 return false;
00139
00140 return success;
00141 }
00142
00143 std::pair< ref<Expr>, ref<Expr> > Solver::getRange(const Query& query) {
00144 ref<Expr> e = query.expr;
00145 Expr::Width width = e->getWidth();
00146 uint64_t min, max;
00147
00148 if (width==1) {
00149 Solver::Validity result;
00150 if (!evaluate(query, result))
00151 assert(0 && "computeValidity failed");
00152 switch (result) {
00153 case Solver::True:
00154 min = max = 1; break;
00155 case Solver::False:
00156 min = max = 0; break;
00157 default:
00158 min = 0, max = 1; break;
00159 }
00160 } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(e)) {
00161 min = max = CE->getConstantValue();
00162 } else {
00163
00164 uint64_t lo=0, hi=width, mid, bits=0;
00165 while (lo<hi) {
00166 mid = (lo+hi)/2;
00167 bool res;
00168 bool success =
00169 mustBeTrue(query.withExpr(
00170 EqExpr::create(LShrExpr::create(e,
00171 ConstantExpr::create(mid,
00172 width)),
00173 ConstantExpr::create(0, width))),
00174 res);
00175
00176 assert(success && "FIXME: Unhandled solver failure");
00177 (void) success;
00178
00179 if (res) {
00180 hi = mid;
00181 } else {
00182 lo = mid+1;
00183 }
00184
00185 bits = lo;
00186 }
00187
00188
00189
00190
00191
00192 bool res = false;
00193 bool success =
00194 mayBeTrue(query.withExpr(EqExpr::create(e, ConstantExpr::create(0,
00195 width))),
00196 res);
00197
00198 assert(success && "FIXME: Unhandled solver failure");
00199 (void) success;
00200
00201 if (res) {
00202 min = 0;
00203 } else {
00204
00205 lo=0, hi=bits64::maxValueOfNBits(bits);
00206 while (lo<hi) {
00207 mid = (lo+hi)/2;
00208 bool res = false;
00209 bool success =
00210 mayBeTrue(query.withExpr(UleExpr::create(e,
00211 ConstantExpr::create(mid,
00212 width))),
00213 res);
00214
00215 assert(success && "FIXME: Unhandled solver failure");
00216 (void) success;
00217
00218 if (res) {
00219 hi = mid;
00220 } else {
00221 lo = mid+1;
00222 }
00223 }
00224
00225 min = lo;
00226 }
00227
00228
00229 lo=min, hi=bits64::maxValueOfNBits(bits);
00230 while (lo<hi) {
00231 mid = (lo+hi)/2;
00232 bool res;
00233 bool success =
00234 mustBeTrue(query.withExpr(UleExpr::create(e,
00235 ConstantExpr::create(mid,
00236 width))),
00237 res);
00238
00239 assert(success && "FIXME: Unhandled solver failure");
00240 (void) success;
00241
00242 if (res) {
00243 hi = mid;
00244 } else {
00245 lo = mid+1;
00246 }
00247 }
00248
00249 max = lo;
00250 }
00251
00252 return std::make_pair(ConstantExpr::create(min, width),
00253 ConstantExpr::create(max, width));
00254 }
00255
00256
00257
00258 class ValidatingSolver : public SolverImpl {
00259 private:
00260 Solver *solver, *oracle;
00261
00262 public:
00263 ValidatingSolver(Solver *_solver, Solver *_oracle)
00264 : solver(_solver), oracle(_oracle) {}
00265 ~ValidatingSolver() { delete solver; }
00266
00267 bool computeValidity(const Query&, Solver::Validity &result);
00268 bool computeTruth(const Query&, bool &isValid);
00269 bool computeValue(const Query&, ref<Expr> &result);
00270 bool computeInitialValues(const Query&,
00271 const std::vector<const Array*> &objects,
00272 std::vector< std::vector<unsigned char> > &values,
00273 bool &hasSolution);
00274 };
00275
00276 bool ValidatingSolver::computeTruth(const Query& query,
00277 bool &isValid) {
00278 bool answer;
00279
00280 if (!solver->impl->computeTruth(query, isValid))
00281 return false;
00282 if (!oracle->impl->computeTruth(query, answer))
00283 return false;
00284
00285 if (isValid != answer)
00286 assert(0 && "invalid solver result (computeTruth)");
00287
00288 return true;
00289 }
00290
00291 bool ValidatingSolver::computeValidity(const Query& query,
00292 Solver::Validity &result) {
00293 Solver::Validity answer;
00294
00295 if (!solver->impl->computeValidity(query, result))
00296 return false;
00297 if (!oracle->impl->computeValidity(query, answer))
00298 return false;
00299
00300 if (result != answer)
00301 assert(0 && "invalid solver result (computeValidity)");
00302
00303 return true;
00304 }
00305
00306 bool ValidatingSolver::computeValue(const Query& query,
00307 ref<Expr> &result) {
00308 bool answer;
00309
00310 if (!solver->impl->computeValue(query, result))
00311 return false;
00312
00313
00314 if (!oracle->impl->computeTruth(query.withExpr(NeExpr::create(query.expr,
00315 result)),
00316 answer))
00317 return false;
00318
00319 if (answer)
00320 assert(0 && "invalid solver result (computeValue)");
00321
00322 return true;
00323 }
00324
00325 bool
00326 ValidatingSolver::computeInitialValues(const Query& query,
00327 const std::vector<const Array*>
00328 &objects,
00329 std::vector< std::vector<unsigned char> >
00330 &values,
00331 bool &hasSolution) {
00332 bool answer;
00333
00334 if (!solver->impl->computeInitialValues(query, objects, values,
00335 hasSolution))
00336 return false;
00337
00338 if (hasSolution) {
00339
00340
00341 std::vector< ref<Expr> > bindings;
00342 for (unsigned i = 0; i != values.size(); ++i) {
00343 const Array *array = objects[i];
00344 for (unsigned j=0; j<array->size; j++) {
00345 unsigned char value = values[i][j];
00346 bindings.push_back(EqExpr::create(ReadExpr::create(UpdateList(array,
00347 true, 0),
00348 ConstantExpr::alloc(j, Expr::Int32)),
00349 ConstantExpr::alloc(value, Expr::Int8)));
00350 }
00351 }
00352 ConstraintManager tmp(bindings);
00353 ref<Expr> constraints = Expr::createNot(query.expr);
00354 for (ConstraintManager::const_iterator it = query.constraints.begin(),
00355 ie = query.constraints.end(); it != ie; ++it)
00356 constraints = AndExpr::create(constraints, *it);
00357
00358 if (!oracle->impl->computeTruth(Query(tmp, constraints), answer))
00359 return false;
00360 if (!answer)
00361 assert(0 && "invalid solver result (computeInitialValues)");
00362 } else {
00363 if (!oracle->impl->computeTruth(query, answer))
00364 return false;
00365 if (!answer)
00366 assert(0 && "invalid solver result (computeInitialValues)");
00367 }
00368
00369 return true;
00370 }
00371
00372 Solver *klee::createValidatingSolver(Solver *s, Solver *oracle) {
00373 return new Solver(new ValidatingSolver(s, oracle));
00374 }
00375
00376
00377
00378 class STPSolverImpl : public SolverImpl {
00379 private:
00381 STPSolver *solver;
00382 VC vc;
00383 STPBuilder *builder;
00384 double timeout;
00385 bool useForkedSTP;
00386
00387 public:
00388 STPSolverImpl(STPSolver *_solver, bool _useForkedSTP);
00389 ~STPSolverImpl();
00390
00391 char *getConstraintLog(const Query&);
00392 void setTimeout(double _timeout) { timeout = _timeout; }
00393
00394 bool computeTruth(const Query&, bool &isValid);
00395 bool computeValue(const Query&, ref<Expr> &result);
00396 bool computeInitialValues(const Query&,
00397 const std::vector<const Array*> &objects,
00398 std::vector< std::vector<unsigned char> > &values,
00399 bool &hasSolution);
00400 };
00401
00402 static unsigned char *shared_memory_ptr;
00403 static const unsigned shared_memory_size = 1<<20;
00404 static int shared_memory_id;
00405
00406 static void stp_error_handler(const char* err_msg) {
00407 fprintf(stderr, "error: STP Error: %s\n", err_msg);
00408 abort();
00409 }
00410
00411 STPSolverImpl::STPSolverImpl(STPSolver *_solver, bool _useForkedSTP)
00412 : solver(_solver),
00413 vc(vc_createValidityChecker()),
00414 builder(new STPBuilder(vc)),
00415 timeout(0.0),
00416 useForkedSTP(_useForkedSTP)
00417 {
00418 assert(vc && "unable to create validity checker");
00419 assert(builder && "unable to create STPBuilder");
00420
00421 vc_registerErrorHandler(::stp_error_handler);
00422
00423 if (useForkedSTP) {
00424 shared_memory_id = shmget(IPC_PRIVATE, shared_memory_size, IPC_CREAT | 0700);
00425 assert(shared_memory_id>=0 && "shmget failed");
00426 shared_memory_ptr = (unsigned char*) shmat(shared_memory_id, NULL, 0);
00427 assert(shared_memory_ptr!=(void*)-1 && "shmat failed");
00428 shmctl(shared_memory_id, IPC_RMID, NULL);
00429 }
00430 }
00431
00432 STPSolverImpl::~STPSolverImpl() {
00433 delete builder;
00434
00435 vc_Destroy(vc);
00436 }
00437
00438
00439
00440 STPSolver::STPSolver(bool useForkedSTP)
00441 : Solver(new STPSolverImpl(this, useForkedSTP))
00442 {
00443 }
00444
00445 char *STPSolver::getConstraintLog(const Query &query) {
00446 return static_cast<STPSolverImpl*>(impl)->getConstraintLog(query);
00447 }
00448
00449 void STPSolver::setTimeout(double timeout) {
00450 static_cast<STPSolverImpl*>(impl)->setTimeout(timeout);
00451 }
00452
00453
00454
00455 char *STPSolverImpl::getConstraintLog(const Query &query) {
00456 vc_push(vc);
00457 for (std::vector< ref<Expr> >::const_iterator it = query.constraints.begin(),
00458 ie = query.constraints.end(); it != ie; ++it)
00459 vc_assertFormula(vc, builder->construct(*it));
00460 assert(query.expr == ConstantExpr::alloc(0, Expr::Bool) &&
00461 "Unexpected expression in query!");
00462
00463 char *buffer;
00464 unsigned long length;
00465 vc_printQueryStateToBuffer(vc, builder->getFalse(),
00466 &buffer, &length, false);
00467 vc_pop(vc);
00468
00469 return buffer;
00470 }
00471
00472 bool STPSolverImpl::computeTruth(const Query& query,
00473 bool &isValid) {
00474 std::vector<const Array*> objects;
00475 std::vector< std::vector<unsigned char> > values;
00476 bool hasSolution;
00477
00478 if (!computeInitialValues(query, objects, values, hasSolution))
00479 return false;
00480
00481 isValid = !hasSolution;
00482 return true;
00483 }
00484
00485 bool STPSolverImpl::computeValue(const Query& query,
00486 ref<Expr> &result) {
00487 std::vector<const Array*> objects;
00488 std::vector< std::vector<unsigned char> > values;
00489 bool hasSolution;
00490
00491
00492
00493 findSymbolicObjects(query.expr, objects);
00494 if (!computeInitialValues(query.withFalse(), objects, values, hasSolution))
00495 return false;
00496 assert(hasSolution && "state has invalid constraint set");
00497
00498
00499 Assignment a(objects, values);
00500 result = a.evaluate(query.expr);
00501
00502 return true;
00503 }
00504
00505 static void runAndGetCex(::VC vc, STPBuilder *builder, ::VCExpr q,
00506 const std::vector<const Array*> &objects,
00507 std::vector< std::vector<unsigned char> > &values,
00508 bool &hasSolution) {
00509
00510 hasSolution = !vc_query(vc, q);
00511
00512 if (hasSolution) {
00513 values.reserve(objects.size());
00514 for (std::vector<const Array*>::const_iterator
00515 it = objects.begin(), ie = objects.end(); it != ie; ++it) {
00516 const Array *array = *it;
00517 std::vector<unsigned char> data;
00518
00519 data.reserve(array->size);
00520 for (unsigned offset = 0; offset < array->size; offset++) {
00521 ExprHandle counter =
00522 vc_getCounterExample(vc, builder->getInitialRead(array, offset));
00523 unsigned char val = getBVUnsigned(counter);
00524 data.push_back(val);
00525 }
00526
00527 values.push_back(data);
00528 }
00529 }
00530 }
00531
00532 static void stpTimeoutHandler(int x) {
00533 _exit(52);
00534 }
00535
00536 static bool runAndGetCexForked(::VC vc,
00537 STPBuilder *builder,
00538 ::VCExpr q,
00539 const std::vector<const Array*> &objects,
00540 std::vector< std::vector<unsigned char> >
00541 &values,
00542 bool &hasSolution,
00543 double timeout) {
00544 unsigned char *pos = shared_memory_ptr;
00545 unsigned sum = 0;
00546 for (std::vector<const Array*>::const_iterator
00547 it = objects.begin(), ie = objects.end(); it != ie; ++it)
00548 sum += (*it)->size;
00549 assert(sum<shared_memory_size && "not enough shared memory for counterexample");
00550
00551 fflush(stdout);
00552 fflush(stderr);
00553 int pid = fork();
00554 if (pid==-1) {
00555 fprintf(stderr, "error: fork failed (for STP)");
00556 return false;
00557 }
00558
00559 if (pid == 0) {
00560 if (timeout) {
00561 ::alarm(0);
00562 ::signal(SIGALRM, stpTimeoutHandler);
00563 ::alarm(std::max(1, (int)timeout));
00564 }
00565 unsigned res = vc_query(vc, q);
00566 if (!res) {
00567 for (std::vector<const Array*>::const_iterator
00568 it = objects.begin(), ie = objects.end(); it != ie; ++it) {
00569 const Array *array = *it;
00570 for (unsigned offset = 0; offset < array->size; offset++) {
00571 ExprHandle counter =
00572 vc_getCounterExample(vc, builder->getInitialRead(array, offset));
00573 *pos++ = getBVUnsigned(counter);
00574 }
00575 }
00576 }
00577 _exit(res);
00578 } else {
00579 int status;
00580 int res = waitpid(pid, &status, 0);
00581
00582 if (res<0) {
00583 fprintf(stderr, "error: waitpid() for STP failed");
00584 return false;
00585 }
00586
00587
00588
00589
00590 if (WIFSIGNALED(status) || !WIFEXITED(status)) {
00591 fprintf(stderr, "error: STP did not return successfully");
00592 return false;
00593 }
00594
00595 int exitcode = WEXITSTATUS(status);
00596 if (exitcode==0) {
00597 hasSolution = true;
00598 } else if (exitcode==1) {
00599 hasSolution = false;
00600 } else if (exitcode==52) {
00601 fprintf(stderr, "error: STP timed out");
00602 return false;
00603 } else {
00604 fprintf(stderr, "error: STP did not return a recognized code");
00605 return false;
00606 }
00607
00608 if (hasSolution) {
00609 values = std::vector< std::vector<unsigned char> >(objects.size());
00610 unsigned i=0;
00611 for (std::vector<const Array*>::const_iterator
00612 it = objects.begin(), ie = objects.end(); it != ie; ++it) {
00613 const Array *array = *it;
00614 std::vector<unsigned char> &data = values[i++];
00615 data.insert(data.begin(), pos, pos + array->size);
00616 pos += array->size;
00617 }
00618 }
00619
00620 return true;
00621 }
00622 }
00623
00624 bool
00625 STPSolverImpl::computeInitialValues(const Query &query,
00626 const std::vector<const Array*>
00627 &objects,
00628 std::vector< std::vector<unsigned char> >
00629 &values,
00630 bool &hasSolution) {
00631 TimerStatIncrementer t(stats::queryTime);
00632
00633 vc_push(vc);
00634
00635 for (ConstraintManager::const_iterator it = query.constraints.begin(),
00636 ie = query.constraints.end(); it != ie; ++it)
00637 vc_assertFormula(vc, builder->construct(*it));
00638
00639 ++stats::queries;
00640 ++stats::queryCounterexamples;
00641
00642 ExprHandle stp_e = builder->construct(query.expr);
00643
00644 bool success;
00645 if (useForkedSTP) {
00646 success = runAndGetCexForked(vc, builder, stp_e, objects, values,
00647 hasSolution, timeout);
00648 } else {
00649 runAndGetCex(vc, builder, stp_e, objects, values, hasSolution);
00650 success = true;
00651 }
00652
00653 if (success) {
00654 if (hasSolution)
00655 ++stats::queriesInvalid;
00656 else
00657 ++stats::queriesValid;
00658 }
00659
00660 vc_pop(vc);
00661
00662 return success;
00663 }