aboutsummaryrefslogtreecommitdiffhomepage
path: root/lib
diff options
context:
space:
mode:
authorJulian Büning <julian.buening@comsys.rwth-aachen.de>2021-05-06 22:01:30 +0200
committerMartinNowack <2443641+MartinNowack@users.noreply.github.com>2021-05-10 17:48:34 +0100
commit24badb5bf17ff586dc3f1856901f27210713b2ac (patch)
tree00368e6c71eda9911768946649fddef855d88cf5 /lib
parentc155cc7132a4d4bff042bf982ee08bf142a21b5e (diff)
downloadklee-24badb5bf17ff586dc3f1856901f27210713b2ac.tar.gz
allocate memory objects for functions
Before, we reused the llvm::Function* value in the target program, even though it stems from KLEE's own address space. This leads to non-deterministic function pointers, even with --allocate-determ. This issue was identified in the MoKLEE paper. Now, we allocate a memory object per function, for its (potentially) deterministic address. Mapping this address back to llvm::Functions is done by the legalFunctions map. Also, pointer width now depends on the target, not the host.
Diffstat (limited to 'lib')
-rw-r--r--lib/Core/Executor.cpp17
-rw-r--r--lib/Core/Executor.h7
2 files changed, 15 insertions, 9 deletions
diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp
index fb83c883..a81c4882 100644
--- a/lib/Core/Executor.cpp
+++ b/lib/Core/Executor.cpp
@@ -670,7 +670,7 @@ void Executor::initializeGlobals(ExecutionState &state) {
}
void Executor::allocateGlobalObjects(ExecutionState &state) {
- const Module *m = kmodule->module.get();
+ Module *m = kmodule->module.get();
if (m->getModuleInlineAsm() != "")
klee_warning("executable has module level assembly (ignoring)");
@@ -678,7 +678,7 @@ void Executor::allocateGlobalObjects(ExecutionState &state) {
// object. given that we use malloc to allocate memory in states this also
// ensures that we won't conflict. we don't need to allocate a memory object
// since reading/writing via a function pointer is unsupported anyway.
- for (const Function &f : *m) {
+ for (Function &f : *m) {
ref<ConstantExpr> addr;
// If the symbol has external weak linkage then it is implicitly
@@ -688,8 +688,12 @@ void Executor::allocateGlobalObjects(ExecutionState &state) {
!externalDispatcher->resolveSymbol(f.getName().str())) {
addr = Expr::createPointer(0);
} else {
- addr = Expr::createPointer(reinterpret_cast<std::uint64_t>(&f));
- legalFunctions.insert(reinterpret_cast<std::uint64_t>(&f));
+ // We allocate an object to represent each function,
+ // its address can be used for function pointers.
+ // TODO: Check whether the object is accessed?
+ auto mo = memory->allocate(8, false, true, &f, 8);
+ addr = Expr::createPointer(mo->address);
+ legalFunctions.emplace(mo->address, &f);
}
globalAddresses.emplace(&f, addr);
@@ -2462,8 +2466,9 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) {
StatePair res = fork(*free, EqExpr::create(v, value), true);
if (res.first) {
uint64_t addr = value->getZExtValue();
- if (legalFunctions.count(addr)) {
- f = (Function*) addr;
+ auto it = legalFunctions.find(addr);
+ if (it != legalFunctions.end()) {
+ f = it->second;
// Don't give warning on unique resolution
if (res.second || !first)
diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h
index ae960731..987edf47 100644
--- a/lib/Core/Executor.h
+++ b/lib/Core/Executor.h
@@ -34,6 +34,7 @@
#include <memory>
#include <set>
#include <string>
+#include <unordered_map>
#include <vector>
struct KTest;
@@ -164,9 +165,9 @@ private:
/// globals that have no representative object (i.e. functions).
std::map<const llvm::GlobalValue*, ref<ConstantExpr> > globalAddresses;
- /// The set of legal function addresses, used to validate function
- /// pointers. We use the actual Function* address as the function address.
- std::set<uint64_t> legalFunctions;
+ /// Map of legal function addresses to the corresponding Function.
+ /// Used to validate and dereference function pointers.
+ std::unordered_map<std::uint64_t, llvm::Function*> legalFunctions;
/// When non-null the bindings that will be used for calls to
/// klee_make_symbolic in order replay.