diff options
author | Andrea Mattavelli <andreamattavelli@users.noreply.github.com> | 2017-02-21 22:23:52 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-21 22:23:52 +0000 |
commit | 62ee2e574b9f920e6679c91da25f8941552277d9 (patch) | |
tree | b476d2df666340ad26f63d8fd3c4e07b2a248f11 | |
parent | 27f414cc48bf086552ee4cba7784354c162a8301 (diff) | |
parent | 70715151746a24c4c6919292956111b00fcd3a26 (diff) | |
download | klee-62ee2e574b9f920e6679c91da25f8941552277d9.tar.gz |
Merge pull request #514 from delcypher/fix_klee_get_direct_call_bitcast_weak_alias
Fix assertion failure when klee::getDirectCallTarget() is used on call to bitcasted weak alias
-rw-r--r-- | include/klee/Internal/Support/ModuleUtil.h | 6 | ||||
-rw-r--r-- | lib/Core/StatsTracker.cpp | 6 | ||||
-rw-r--r-- | lib/Module/ModuleUtil.cpp | 42 | ||||
-rw-r--r-- | test/regression/2016-11-24-bitcast-weak-alias.c | 43 |
4 files changed, 78 insertions, 19 deletions
diff --git a/include/klee/Internal/Support/ModuleUtil.h b/include/klee/Internal/Support/ModuleUtil.h index 29adc94a..c85ba591 100644 --- a/include/klee/Internal/Support/ModuleUtil.h +++ b/include/klee/Internal/Support/ModuleUtil.h @@ -29,7 +29,11 @@ namespace klee { /// null if it cannot be determined (should be only for indirect /// calls, although complicated constant expressions might be /// another possibility). - llvm::Function *getDirectCallTarget(llvm::CallSite); + /// + /// If `moduleIsFullyLinked` is set to true it will be assumed that the + // module containing the `llvm::CallSite` is fully linked. This assumption + // allows resolution of functions that are marked as overridable. + llvm::Function *getDirectCallTarget(llvm::CallSite, bool moduleIsFullyLinked); /// Return true iff the given Function value is used in something /// other than a direct call (or a constant expression that diff --git a/lib/Core/StatsTracker.cpp b/lib/Core/StatsTracker.cpp index 97ed26ea..dbd86524 100644 --- a/lib/Core/StatsTracker.cpp +++ b/lib/Core/StatsTracker.cpp @@ -167,7 +167,8 @@ static bool instructionIsCoverable(Instruction *i) { } else { Instruction *prev = --it; if (isa<CallInst>(prev) || isa<InvokeInst>(prev)) { - Function *target = getDirectCallTarget(prev); + Function *target = + getDirectCallTarget(prev, /*moduleIsFullyLinked=*/true); if (target && target->doesNotReturn()) return false; } @@ -690,7 +691,8 @@ void StatsTracker::computeReachableUncovered() { // (which should be correct anyhow). callTargets.insert(std::make_pair(it, std::vector<Function*>())); - } else if (Function *target = getDirectCallTarget(cs)) { + } else if (Function *target = getDirectCallTarget( + cs, /*moduleIsFullyLinked=*/true)) { callTargets[it].push_back(target); } else { callTargets[it] = diff --git a/lib/Module/ModuleUtil.cpp b/lib/Module/ModuleUtil.cpp index a5394067..2cd41c89 100644 --- a/lib/Module/ModuleUtil.cpp +++ b/lib/Module/ModuleUtil.cpp @@ -436,23 +436,33 @@ Module *klee::linkWithLibrary(Module *module, #endif } - - -Function *klee::getDirectCallTarget(CallSite cs) { +Function *klee::getDirectCallTarget(CallSite cs, bool moduleIsFullyLinked) { Value *v = cs.getCalledValue(); - if (Function *f = dyn_cast<Function>(v)) { - return f; - } else if (llvm::ConstantExpr *ce = dyn_cast<llvm::ConstantExpr>(v)) { - if (ce->getOpcode()==Instruction::BitCast) - if (Function *f = dyn_cast<Function>(ce->getOperand(0)->stripPointerCasts())) - return f; - - // NOTE: This assert may fire, it isn't necessarily a problem and - // can be disabled, I just wanted to know when and if it happened. - assert(0 && "FIXME: Unresolved direct target for a constant expression."); - } - - return 0; + bool viaConstantExpr = false; + // Walk through aliases and bitcasts to try to find + // the function being called. + do { + if (Function *f = dyn_cast<Function>(v)) { + return f; + } else if (llvm::GlobalAlias *ga = dyn_cast<GlobalAlias>(v)) { + if (moduleIsFullyLinked || !(ga->mayBeOverridden())) { + v = ga->getAliasee(); + } else { + v = NULL; + } + } else if (llvm::ConstantExpr *ce = dyn_cast<llvm::ConstantExpr>(v)) { + viaConstantExpr = true; + v = ce->getOperand(0)->stripPointerCasts(); + } else { + v = NULL; + } + } while (v != NULL); + + // NOTE: This assert may fire, it isn't necessarily a problem and + // can be disabled, I just wanted to know when and if it happened. + assert((!viaConstantExpr) && + "FIXME: Unresolved direct target for a constant expression"); + return NULL; } static bool valueIsOnlyCalled(const Value *v) { diff --git a/test/regression/2016-11-24-bitcast-weak-alias.c b/test/regression/2016-11-24-bitcast-weak-alias.c new file mode 100644 index 00000000..f115731b --- /dev/null +++ b/test/regression/2016-11-24-bitcast-weak-alias.c @@ -0,0 +1,43 @@ +// RUN: %llvmgcc %s -Wall -emit-llvm -g -O0 -c -o %t.bc +// RUN: rm -rf %t.klee-out +// RUN: klee --output-dir=%t.klee-out -exit-on-error -search=nurs:covnew %t.bc DUMMY_ARG >%t1.log 2>&1 +// RUN: FileCheck -input-file=%t1.log %s + +// This test case is designed to cover code in `klee::getDirectCallTarget(CallSite)`. +// In particular it designed to test the case where a bitcasted function call, calls +// a weak alias. +struct v1 { + int c; + int d; +}; + +int __real_function(struct v1 *unused, struct v1 *unused2, int unused3) { + return 0; +} + +struct v2 { + int e; + int f; +}; + +int alias_function(struct v1 *, struct v1 *, int) + __attribute__((weak, alias("__real_function"))); + +int main(int argc, char** argv) { + struct v2 local = { .e= 0, .f=0 }; + int choice = (argc == 1); + int number = 0; + + // FIXME: Drop the guard when llvm 2.9 is dropped. + // Prevent actually making the call at runtime due to llvm-gcc + // injecting an abort if the call is made. The call is guarded + // in such a way that the compiler cannot remove the call. + if (choice) { + // Call via a bitcasted alias. + number = ((int (*)(struct v2 *, struct v2 *, int))alias_function)( + &local, &local, 0); + } + return number % 255; +} + +// CHECK: KLEE: done: completed paths = 1 |