9#include "klee/Config/config.h"
23#include "llvm/Support/CommandLine.h"
24#include "llvm/Support/Errno.h"
34llvm::cl::opt<bool> DebugDumpSTPQueries(
35 "debug-dump-stp-queries", llvm::cl::init(
false),
36 llvm::cl::desc(
"Dump every STP query to stderr (default=false)"),
39llvm::cl::opt<bool> IgnoreSolverFailures(
40 "ignore-solver-failures", llvm::cl::init(
false),
41 llvm::cl::desc(
"Ignore any STP solver failures (default=false)"),
45#define vc_bvBoolExtract IAMTHESPAWNOFSATAN
47static unsigned char *shared_memory_ptr =
nullptr;
48static int shared_memory_id = 0;
55static const unsigned shared_memory_size = 1 << 16;
57static const unsigned shared_memory_size = 1 << 20;
60static void stp_error_handler(
const char *err_msg) {
61 fprintf(stderr,
"error: STP Error: %s\n", err_msg);
67class STPSolverImpl :
public SolverImpl {
73 SolverRunStatus runStatusCode;
76 explicit STPSolverImpl(
bool useForkedSTP,
bool optimizeDivides =
true);
77 ~STPSolverImpl()
override;
79 char *getConstraintLog(
const Query &)
override;
80 void setCoreSolverTimeout(time::Span timeout)
override { this->timeout = timeout; }
82 bool computeTruth(
const Query &,
bool &isValid)
override;
83 bool computeValue(
const Query &, ref<Expr> &result)
override;
84 bool computeInitialValues(
const Query &,
85 const std::vector<const Array *> &objects,
86 std::vector<std::vector<unsigned char>> &values,
87 bool &hasSolution)
override;
88 SolverRunStatus getOperationStatusCode()
override;
91STPSolverImpl::STPSolverImpl(
bool useForkedSTP,
bool optimizeDivides)
92 : vc(vc_createValidityChecker()),
93 builder(new STPBuilder(vc, optimizeDivides)),
94 useForkedSTP(useForkedSTP), runStatusCode(SOLVER_RUN_STATUS_FAILURE) {
95 assert(vc &&
"unable to create validity checker");
96 assert(builder &&
"unable to create STPBuilder");
104 vc_setInterfaceFlags(vc, EXPRDELETE, 0);
106 make_division_total(vc);
108 vc_registerErrorHandler(::stp_error_handler);
111 assert(shared_memory_id == 0 &&
"shared memory id already allocated");
113 shmget(IPC_PRIVATE, shared_memory_size, IPC_CREAT | 0700);
114 if (shared_memory_id < 0)
115 llvm::report_fatal_error(
"unable to allocate shared memory region");
116 shared_memory_ptr = (
unsigned char *)shmat(shared_memory_id,
nullptr, 0);
117 if (shared_memory_ptr == (
void *)-1)
118 llvm::report_fatal_error(
"unable to attach shared memory region");
119 shmctl(shared_memory_id, IPC_RMID,
nullptr);
123STPSolverImpl::~STPSolverImpl() {
125 shmdt(shared_memory_ptr);
126 shared_memory_ptr =
nullptr;
127 shared_memory_id = 0;
136char *STPSolverImpl::getConstraintLog(
const Query &query) {
139 for (
const auto &constraint : query.constraints)
140 vc_assertFormula(vc, builder->construct(constraint));
141 assert(query.expr == ConstantExpr::alloc(0, Expr::Bool) &&
142 "Unexpected expression in query!");
145 unsigned long length;
146 vc_printQueryStateToBuffer(vc, builder->getFalse(), &buffer, &length,
false);
152bool STPSolverImpl::computeTruth(
const Query &query,
bool &isValid) {
153 std::vector<const Array *> objects;
154 std::vector<std::vector<unsigned char>> values;
157 if (!computeInitialValues(query, objects, values, hasSolution))
160 isValid = !hasSolution;
164bool STPSolverImpl::computeValue(
const Query &query, ref<Expr> &result) {
165 std::vector<const Array *> objects;
166 std::vector<std::vector<unsigned char>> values;
172 if (!computeInitialValues(query.withFalse(), objects, values, hasSolution))
174 assert(hasSolution &&
"state has invalid constraint set");
177 Assignment a(objects, values);
178 result = a.evaluate(query.expr);
183static SolverImpl::SolverRunStatus
184runAndGetCex(::VC vc, STPBuilder *builder, ::VCExpr q,
185 const std::vector<const Array *> &objects,
186 std::vector<std::vector<unsigned char>> &values,
189 hasSolution = !vc_query(vc, q);
192 return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE;
194 values.reserve(objects.size());
196 for (
const auto object : objects) {
197 values.emplace_back(object->size);
199 for (
unsigned offset = 0; offset <
object->size; offset++) {
201 vc_getCounterExample(vc, builder->getInitialRead(
object, offset));
202 values[i][offset] =
static_cast<unsigned char>(getBVUnsigned(counter));
207 return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_SOLVABLE;
210static void stpTimeoutHandler(
int x) { _exit(52); }
212static SolverImpl::SolverRunStatus
213runAndGetCexForked(::VC vc, STPBuilder *builder, ::VCExpr q,
214 const std::vector<const Array *> &objects,
215 std::vector<std::vector<unsigned char>> &values,
216 bool &hasSolution, time::Span timeout) {
217 unsigned char *pos = shared_memory_ptr;
219 for (
const auto object : objects)
221 if (sum >= shared_memory_size)
222 llvm::report_fatal_error(
"not enough shared memory for counterexample");
231 klee_warning(
"fork failed (for STP) - %s", llvm::sys::StrError(errno).c_str());
232 if (!IgnoreSolverFailures)
234 return SolverImpl::SOLVER_RUN_STATUS_FORK_FAILED;
240 ::signal(SIGALRM, stpTimeoutHandler);
241 ::alarm(std::max(1u,
static_cast<unsigned>(timeout.toSeconds())));
243 int res = vc_query(vc, q);
245 for (
const auto object : objects) {
246 for (
unsigned offset = 0; offset <
object->size; offset++) {
248 vc_getCounterExample(vc, builder->getInitialRead(
object, offset));
249 *pos++ =
static_cast<unsigned char>(getBVUnsigned(counter));
260 res = waitpid(pid, &status, 0);
261 }
while (res < 0 && errno == EINTR);
265 if (!IgnoreSolverFailures)
267 return SolverImpl::SOLVER_RUN_STATUS_WAITPID_FAILED;
273 if (WIFSIGNALED(status) || !WIFEXITED(status)) {
274 klee_warning(
"STP did not return successfully. Most likely you forgot "
275 "to run 'ulimit -s unlimited'");
276 if (!IgnoreSolverFailures) {
279 return SolverImpl::SOLVER_RUN_STATUS_INTERRUPTED;
282 int exitcode = WEXITSTATUS(status);
288 values.reserve(objects.size());
289 for (
const auto object : objects) {
290 values.emplace_back(pos, pos + object->size);
294 return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_SOLVABLE;
300 return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE;
304 if (exitcode == 52) {
307 return SolverImpl::SOLVER_RUN_STATUS_TIMEOUT;
312 if (!IgnoreSolverFailures)
314 return SolverImpl::SOLVER_RUN_STATUS_UNEXPECTED_EXIT_CODE;
318bool STPSolverImpl::computeInitialValues(
319 const Query &query,
const std::vector<const Array *> &objects,
320 std::vector<std::vector<unsigned char>> &values,
bool &hasSolution) {
321 runStatusCode = SOLVER_RUN_STATUS_FAILURE;
326 for (
const auto &constraint : query.constraints)
327 vc_assertFormula(vc, builder->construct(constraint));
332 ExprHandle stp_e = builder->construct(query.expr);
334 if (DebugDumpSTPQueries) {
337 vc_printQueryStateToBuffer(vc, stp_e, &buf, &len,
false);
344 runStatusCode = runAndGetCexForked(vc, builder, stp_e, objects, values,
345 hasSolution, timeout);
346 success = ((SOLVER_RUN_STATUS_SUCCESS_SOLVABLE == runStatusCode) ||
347 (SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE == runStatusCode));
350 runAndGetCex(vc, builder, stp_e, objects, values, hasSolution);
366SolverImpl::SolverRunStatus STPSolverImpl::getOperationStatusCode() {
367 return runStatusCode;
370STPSolver::STPSolver(
bool useForkedSTP,
bool optimizeDivides)
371 : Solver(new STPSolverImpl(useForkedSTP, optimizeDivides)) {}
373char *STPSolver::getConstraintLog(
const Query &query) {
374 return impl->getConstraintLog(query);
377void STPSolver::setCoreSolverTimeout(time::Span timeout) {
378 impl->setCoreSolverTimeout(timeout);
void klee_warning(char *name)
Statistic queryCounterexamples
void findSymbolicObjects(ref< Expr > e, std::vector< const Array * > &results)
llvm::cl::OptionCategory SolvingCat