about summary refs log tree commit diff homepage
diff options
context:
space:
mode:
authorNguyễn Gia Phong <cnx@loang.net>2023-11-10 12:23:37 +0900
committerNguyễn Gia Phong <cnx@loang.net>2024-03-05 17:53:27 +0900
commit25ea1e3bbb2ff2abf57dd348af62837425dba8a7 (patch)
tree97b02b37a91353c01fedd2c721619c1f78814725
parentae1f642b1f04bce817fa66b92515da9459f1a4d0 (diff)
downloadklee-25ea1e3bbb2ff2abf57dd348af62837425dba8a7.tar.gz
Implement detection of implicit return via pointer
-rw-r--r--lib/Core/Executor.cpp78
-rw-r--r--lib/Core/Executor.h11
2 files changed, 67 insertions, 22 deletions
diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp
index 4763fdb5..d26e5d04 100644
--- a/lib/Core/Executor.cpp
+++ b/lib/Core/Executor.cpp
@@ -2125,11 +2125,17 @@ Function *Executor::getTargetFunction(Value *calledVal) {
   }
 }
 
+bool patchLocal(llvm::Function *fn) {
+    if (PatchedFile.empty()
+        || fn->getSubprogram()->getFilename() != PatchedFile)
+      return false;
+    auto const name = fn->getName();
+    return name != "__choose" && name.substr(0, 7) != "__klee_";
+}
+
 void Executor::registerOutput(ExecutionState &state, Function *fn,
     std::string var, Expr::Width bits, ref<Expr> val) {
-  if (state.patchLocs == 0 || fn->getName() == "__choose"
-      || (!PatchedFile.empty()
-          && fn->getSubprogram()->getFilename() != PatchedFile))
+  if (state.patchLocs == 0 || !patchLocal(fn))
     return;
   size_t bytes = bits == Expr::Bool ? 1u : bits >> 3;
   auto const inst = state.prevPC->inst;
@@ -2168,6 +2174,33 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) {
       assert(!caller && "caller set on initial stack frame");
       terminateStateOnExit(state);
     } else {
+      std::vector<ref<Expr>> arguments;
+      auto const fp = cast<CallBase>(*caller).getCalledOperand();
+      if (auto const fn = getTargetFunction(fp)) {
+        auto const kf = kmodule->functionMap[fn];
+        auto const ft = fn->getFunctionType();
+        auto k = fn->arg_size();
+        while (k--) {
+          auto const t = ft->getParamType(k);
+          if (!t->isPointerTy())
+            continue;
+          auto const addr = getArgumentCell(state, kf, k).value;
+          // FIXME: changed to getPointerElementType in LLVM 14
+          // and removed (!!!) in favor of opaque pointers in LLVM 15
+          auto const pt = cast<PointerType>(t)->getElementType();
+          if (pt->isFunctionTy() || !patchLocal(fn))
+            continue;
+          auto const size = getWidthForLLVMType(pt);
+          auto const& val = executeMemoryOperation(state, false, addr,
+                                                   0, nullptr, size);
+          if (val.isNull())
+            klee_warning("failed to make argument %s:%s#%zu symbolic",
+                         fn->getSubprogram()->getFilename().data(),
+                         fn->getName().data(), k);
+          else
+            registerOutput(state, fn, "parg" + llvm::utostr(k), size, val);
+        }
+      }
       state.popFrame();
 
       if (statsTracker)
@@ -4635,13 +4668,18 @@ void Executor::resolveExact(ExecutionState &state,
   }
 }
 
-void Executor::executeMemoryOperation(ExecutionState &state,
-                                      bool isWrite,
-                                      ref<Expr> address,
-                                      ref<Expr> value /* undef if read */,
-                                      KInstruction *target /* undef if write */) {
-  Expr::Width type = (isWrite ? value->getWidth() : 
-                     getWidthForLLVMType(target->inst->getType()));
+ref<Expr> Executor::executeMemoryOperation(ExecutionState &state,
+                                           bool isWrite,
+                                           ref<Expr> address,
+                                           ref<Expr> value /* undef if read */,
+                                           KInstruction *target,
+                                           Expr::Width type) {
+  if (isWrite)
+    type = value->getWidth();
+  else if (target)
+    type = getWidthForLLVMType(target->inst->getType());
+  else
+    assert(type != Expr::InvalidWidth);
   unsigned bytes = Expr::getMinBytesForWidth(type);
 
   if (SimplifySymIndices) {
@@ -4711,7 +4749,7 @@ void Executor::executeMemoryOperation(ExecutionState &state,
       if (!success) {
         state.pc = state.prevPC;
         terminateStateOnSolverError(state, "Query timed out (bounds check).");
-        return;
+        return {};
       }
 
       if (inBounds) {
@@ -4729,11 +4767,13 @@ void Executor::executeMemoryOperation(ExecutionState &state,
 
           if (interpreterOpts.MakeConcreteSymbolic)
             result = replaceReadWithSymbolic(state, result);
-
-          bindLocal(target, state, result);
+          if (target)
+            bindLocal(target, state, result);
+          else
+            return result;
         }
 
-        return;
+        return {};
       }
     }
   }
@@ -4776,7 +4816,10 @@ void Executor::executeMemoryOperation(ExecutionState &state,
         }
       } else {
         ref<Expr> result = os->read(mo->getOffsetExpr(address), type);
-        bindLocal(target, *bound, result);
+        if (target)
+          bindLocal(target, *bound, result);
+        else
+          return result;
       }
     }
 
@@ -4789,6 +4832,8 @@ void Executor::executeMemoryOperation(ExecutionState &state,
   if (unbound) {
     if (incomplete) {
       terminateStateOnSolverError(*unbound, "Query timed out (resolve).");
+    } else if (!isWrite && !target) {
+      return {};
     } else {
       if (auto CE = dyn_cast<ConstantExpr>(address)) {
         std::uintptr_t ptrval = CE->getZExtValue();
@@ -4797,7 +4842,6 @@ void Executor::executeMemoryOperation(ExecutionState &state,
           terminateStateOnProgramError(
               *unbound, "memory error: null page access",
               StateTerminationType::Ptr, getAddressInfo(*unbound, address));
-          return;
         } else if (MemoryManager::isDeterministic) {
           using kdalloc::LocationInfo;
           auto li = unbound->heapAllocator.locationInfo(ptr, bytes);
@@ -4811,7 +4855,6 @@ void Executor::executeMemoryOperation(ExecutionState &state,
               terminateStateOnProgramError(
                   *unbound, "memory error: use after free",
                   StateTerminationType::Ptr, getAddressInfo(*unbound, address));
-              return;
             }
           }
         }
@@ -4821,6 +4864,7 @@ void Executor::executeMemoryOperation(ExecutionState &state,
           StateTerminationType::Ptr, getAddressInfo(*unbound, address));
     }
   }
+  return {};
 }
 
 void Executor::executeMakeSymbolic(ExecutionState &state, 
diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h
index a179c66d..870e5801 100644
--- a/lib/Core/Executor.h
+++ b/lib/Core/Executor.h
@@ -354,11 +354,12 @@ private:
                    
   // do address resolution / object binding / out of bounds checking
   // and perform the operation
-  void executeMemoryOperation(ExecutionState &state,
-                              bool isWrite,
-                              ref<Expr> address,
-                              ref<Expr> value /* undef if read */,
-                              KInstruction *target /* undef if write */);
+  ref<Expr> executeMemoryOperation(ExecutionState &state,
+                                   bool isWrite,
+                                   ref<Expr> address,
+                                   ref<Expr> value /* undef if read */,
+                                   KInstruction *target,
+                                   Expr::Width type = Expr::InvalidWidth);
 
   void executeMakeSymbolic(ExecutionState &state, const MemoryObject *mo,
                            const std::string &name);