aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorTaras Bereznyak <bereznyak.taras1@huawei.com>2021-11-04 13:33:01 +0300
committerCristian Cadar <c.cadar@imperial.ac.uk>2021-11-20 12:34:37 +0100
commit0379144709c2bc47b6fc4bc42c5fe00a24d01a0d (patch)
tree375dfb5b52d24bb4aa1aecb98d708c6d82379ae6
parentf4c4f164a2d9132fcc53c0ce44ea8c5379d4d93e (diff)
downloadklee-0379144709c2bc47b6fc4bc42c5fe00a24d01a0d.tar.gz
Fixed fail with preferCex, removed relation from first argument
-rw-r--r--lib/Core/ExecutionState.cpp5
-rw-r--r--lib/Core/ExecutionState.h6
-rw-r--r--lib/Core/Executor.cpp34
-rw-r--r--lib/Core/Memory.h6
-rw-r--r--lib/Core/SpecialFunctionHandler.cpp8
-rw-r--r--test/Replay/libkleeruntest/replay_cex_after_assumed_malloc.c25
-rw-r--r--test/Replay/libkleeruntest/replay_cex_incorrect_result.c51
7 files changed, 101 insertions, 34 deletions
diff --git a/lib/Core/ExecutionState.cpp b/lib/Core/ExecutionState.cpp
index 47a3b3c6..2f585f96 100644
--- a/lib/Core/ExecutionState.cpp
+++ b/lib/Core/ExecutionState.cpp
@@ -103,6 +103,7 @@ ExecutionState::ExecutionState(const ExecutionState& state):
symPathOS(state.symPathOS),
coveredLines(state.coveredLines),
symbolics(state.symbolics),
+ cexPreferences(state.cexPreferences),
arrayNames(state.arrayNames),
openMergeStack(state.openMergeStack),
steppedInstructions(state.steppedInstructions),
@@ -358,3 +359,7 @@ void ExecutionState::addConstraint(ref<Expr> e) {
ConstraintManager c(constraints);
c.addConstraint(e);
}
+
+void ExecutionState::addCexPreference(const ref<Expr> &cond) {
+ cexPreferences = cexPreferences.insert(cond);
+}
diff --git a/lib/Core/ExecutionState.h b/lib/Core/ExecutionState.h
index f91790d5..8f5e57e8 100644
--- a/lib/Core/ExecutionState.h
+++ b/lib/Core/ExecutionState.h
@@ -13,6 +13,7 @@
#include "AddressSpace.h"
#include "MergeHandler.h"
+#include "klee/ADT/ImmutableSet.h"
#include "klee/ADT/TreeStream.h"
#include "klee/Expr/Constraints.h"
#include "klee/Expr/Expr.h"
@@ -207,6 +208,10 @@ public:
// FIXME: Move to a shared list structure (not critical).
std::vector<std::pair<ref<const MemoryObject>, const Array *>> symbolics;
+ /// @brief A set of boolean expressions
+ /// the user has requested be true of a counterexample.
+ ImmutableSet<ref<Expr>> cexPreferences;
+
/// @brief Set of used array names for this state. Used to avoid collisions.
std::set<std::string> arrayNames;
@@ -259,6 +264,7 @@ public:
void addSymbolic(const MemoryObject *mo, const Array *array);
void addConstraint(ref<Expr> e);
+ void addCexPreference(const ref<Expr> &cond);
bool merge(const ExecutionState &b);
void dumpStack(llvm::raw_ostream &out) const;
diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp
index dcb078df..3d6ea4ae 100644
--- a/lib/Core/Executor.cpp
+++ b/lib/Core/Executor.cpp
@@ -4560,27 +4560,19 @@ bool Executor::getSymbolicSolution(const ExecutionState &state,
// the preferred constraints. See test/Features/PreferCex.c for
// an example) While this process can be very expensive, it can
// also make understanding individual test cases much easier.
- for (unsigned i = 0; i != state.symbolics.size(); ++i) {
- const auto &mo = state.symbolics[i].first;
- std::vector< ref<Expr> >::const_iterator pi =
- mo->cexPreferences.begin(), pie = mo->cexPreferences.end();
- for (; pi != pie; ++pi) {
- bool mustBeTrue;
- // Attempt to bound byte to constraints held in cexPreferences
- bool success =
- solver->mustBeTrue(extendedConstraints, Expr::createIsZero(*pi),
- mustBeTrue, state.queryMetaData);
- // If it isn't possible to constrain this particular byte in the desired
- // way (normally this would mean that the byte can't be constrained to
- // be between 0 and 127 without making the entire constraint list UNSAT)
- // then just continue on to the next byte.
- if (!success) break;
- // If the particular constraint operated on in this iteration through
- // the loop isn't implied then add it to the list of constraints.
- if (!mustBeTrue)
- cm.addConstraint(*pi);
- }
- if (pi!=pie) break;
+ for (auto& pi: state.cexPreferences) {
+ bool mustBeTrue;
+ // Attempt to bound byte to constraints held in cexPreferences
+ bool success =
+ solver->mustBeTrue(extendedConstraints, Expr::createIsZero(pi),
+ mustBeTrue, state.queryMetaData);
+ // If it isn't possible to add the condition without making the entire list
+ // UNSAT, then just continue to the next condition
+ if (!success) break;
+ // If the particular constraint operated on in this iteration through
+ // the loop isn't implied then add it to the list of constraints.
+ if (!mustBeTrue)
+ cm.addConstraint(pi);
}
std::vector< std::vector<unsigned char> > values;
diff --git a/lib/Core/Memory.h b/lib/Core/Memory.h
index e88d5f55..d5189df5 100644
--- a/lib/Core/Memory.h
+++ b/lib/Core/Memory.h
@@ -64,12 +64,6 @@ public:
/// should be either the allocating instruction or the global object
/// it was allocated for (or whatever else makes sense).
const llvm::Value *allocSite;
-
- /// A list of boolean expressions the user has requested be true of
- /// a counterexample. Mutable since we play a little fast and loose
- /// with allowing it to be added to during execution (although
- /// should sensibly be only at creation time).
- mutable std::vector< ref<Expr> > cexPreferences;
// DO NOT IMPLEMENT
MemoryObject(const MemoryObject &b);
diff --git a/lib/Core/SpecialFunctionHandler.cpp b/lib/Core/SpecialFunctionHandler.cpp
index 27ca385c..94c4dc3c 100644
--- a/lib/Core/SpecialFunctionHandler.cpp
+++ b/lib/Core/SpecialFunctionHandler.cpp
@@ -549,13 +549,7 @@ void SpecialFunctionHandler::handlePreferCex(ExecutionState &state,
if (cond->getWidth() != Expr::Bool)
cond = NeExpr::create(cond, ConstantExpr::alloc(0, cond->getWidth()));
- Executor::ExactResolutionList rl;
- executor.resolveExact(state, arguments[0], rl, "prefex_cex");
-
- assert(rl.size() == 1 &&
- "prefer_cex target must resolve to precisely one object");
-
- rl[0].first.first->cexPreferences.push_back(cond);
+ state.addCexPreference(cond);
}
void SpecialFunctionHandler::handlePosixPreferCex(ExecutionState &state,
diff --git a/test/Replay/libkleeruntest/replay_cex_after_assumed_malloc.c b/test/Replay/libkleeruntest/replay_cex_after_assumed_malloc.c
new file mode 100644
index 00000000..09d60e79
--- /dev/null
+++ b/test/Replay/libkleeruntest/replay_cex_after_assumed_malloc.c
@@ -0,0 +1,25 @@
+// RUN: %clang %s -S -emit-llvm -g -c -o %t.ll
+// RUN: rm -rf %t.klee-out
+// RUN: %klee --output-dir=%t.klee-out %t.ll
+// KLEE just must not fail
+#include "klee/klee.h"
+
+int main() {
+ char i;
+ char *p;
+ char *q;
+ klee_make_symbolic(&i, sizeof(i), "i");
+ klee_make_symbolic(&p, sizeof(p), "p");
+
+ if (i) {}
+
+ q = malloc(sizeof (char));
+ klee_assume(p == q);
+ klee_make_symbolic(p, sizeof (char), "p[0]");
+
+ char condition = (*p);
+ if (*p) condition = 1;
+ klee_prefer_cex(&i, condition);
+ if (i+5) {}
+ return 0;
+}
diff --git a/test/Replay/libkleeruntest/replay_cex_incorrect_result.c b/test/Replay/libkleeruntest/replay_cex_incorrect_result.c
new file mode 100644
index 00000000..46fab72e
--- /dev/null
+++ b/test/Replay/libkleeruntest/replay_cex_incorrect_result.c
@@ -0,0 +1,51 @@
+// RUN: %clang %s -S -emit-llvm -g -c -o %t.ll
+// RUN: rm -rf %t.klee-out
+// RUN: %klee --search=dfs --output-dir=%t.klee-out %t.ll
+
+// This should produce four test cases.
+// RUN: test -f %t.klee-out/test000001.ktest
+// RUN: test -f %t.klee-out/test000002.ktest
+// RUN: test -f %t.klee-out/test000003.ktest
+// RUN: test -f %t.klee-out/test000004.ktest
+// RUN: test ! -f %t.klee-out/test000005.ktest
+
+// Now try to replay with libkleeRuntest
+// RUN: %cc -DPRINT_VALUE %s %libkleeruntest -Wl,-rpath %libkleeruntestdir -o %t_runner
+
+// RUN: env KTEST_FILE=%t.klee-out/test000001.ktest %t_runner 2>&1 | FileCheck -check-prefix=CHECK_1 %s
+// RUN: env KTEST_FILE=%t.klee-out/test000002.ktest %t_runner 2>&1 | FileCheck -check-prefix=CHECK_2 %s
+// RUN: env KTEST_FILE=%t.klee-out/test000003.ktest %t_runner 2>&1 | FileCheck -check-prefix=CHECK_3 %s
+// RUN: env KTEST_FILE=%t.klee-out/test000004.ktest %t_runner 2>&1 | FileCheck -check-prefix=CHECK_4 %s
+
+#include <klee/klee.h>
+#include <stdio.h>
+
+void f0(void) {}
+void f1(void) {}
+void f2(void) {}
+void f3(void) {}
+
+int main() {
+ int x = klee_range(0, 256, "x");
+
+ if (x == 17) {
+ f0();
+ // CHECK_4: x=17
+ } else if (x == 32) {
+ f1();
+ // CHECK_3: x=32
+ } else if (x == 99) {
+ f2();
+ // CHECK_2: x=99
+ } else {
+ klee_prefer_cex(&x, x == 0);
+ f3();
+ // CHECK_1: x=0
+ }
+
+#ifdef PRINT_VALUE
+ printf("x=%d\n", x);
+#endif
+
+ return 0;
+}