]> granicus.if.org Git - clang/commitdiff
static analyzer: handle casts of a function to a function pointer with
authorTed Kremenek <kremenek@apple.com>
Thu, 4 Feb 2010 00:47:48 +0000 (00:47 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 4 Feb 2010 00:47:48 +0000 (00:47 +0000)
a different return type.  While we don't emit any errors (yet), at
least we avoid cases where we might crash because of an assertion
failure later on (when the return type differs from what is expected).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95268 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Checker/AdjustedReturnValueChecker.cpp [new file with mode: 0644]
lib/Checker/CMakeLists.txt
lib/Checker/GRExprEngine.cpp
lib/Checker/GRExprEngineInternalChecks.h
test/Analysis/misc-ps.m

diff --git a/lib/Checker/AdjustedReturnValueChecker.cpp b/lib/Checker/AdjustedReturnValueChecker.cpp
new file mode 100644 (file)
index 0000000..898ce76
--- /dev/null
@@ -0,0 +1,90 @@
+//== AdjustedReturnValueChecker.cpp -----------------------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines AdjustedReturnValueChecker, a simple check to see if the
+// return value of a function call is different than the one the caller thinks
+// it is.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+
+namespace {
+class AdjustedReturnValueChecker : 
+    public CheckerVisitor<AdjustedReturnValueChecker> {      
+public:
+  AdjustedReturnValueChecker() {}
+
+  void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+      
+  static void *getTag() {
+    static int x = 0; return &x;
+  }      
+};
+}
+
+void clang::RegisterAdjustedReturnValueChecker(GRExprEngine &Eng) {
+  Eng.registerCheck(new AdjustedReturnValueChecker());
+}
+
+void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C,
+                                                   const CallExpr *CE) {
+  
+  // Fetch the signature of the called function.
+  const GRState *state = C.getState();
+
+  SVal V = state->getSVal(CE);
+  if (V.isUnknown())
+    return;
+
+  const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion();
+  if (!callee)
+    return;
+
+  QualType actualResultTy;
+  
+  if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) {
+    const FunctionDecl *FD = FT->getDecl();
+    actualResultTy = FD->getResultType();
+  }
+  else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) {
+    const BlockTextRegion *BR = BD->getCodeRegion();
+    const BlockPointerType *BT =
+      BR->getLocationType(C.getASTContext())->getAs<BlockPointerType>();
+    const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
+    actualResultTy = FT->getResultType();
+  }
+
+  // Can this happen?
+  if (actualResultTy.isNull())
+    return;
+
+  // For now, ignore references.
+  if (actualResultTy->getAs<ReferenceType>())
+    return;
+  
+  // Get the result type of the call.
+  QualType expectedResultTy = CE->getType();
+
+  // Are they the same?
+  if (expectedResultTy != actualResultTy) {
+    // FIXME: Do more checking and actual emit an error. At least performing
+    // the cast avoids some assertion failures elsewhere.
+    SValuator &SVator = C.getSValuator();
+    const SValuator::CastResult &R = SVator.EvalCast(V, state, expectedResultTy, actualResultTy);
+    C.GenerateNode(R.getState()->BindExpr(CE, R.getSVal()));
+  }
+}
index 033ad338143028688494546a834bd323a43b9373..130378a2477aa361f418972fce800c546648db66 100644 (file)
@@ -1,6 +1,7 @@
 set(LLVM_NO_RTTI 1)
 
 add_clang_library(clangChecker
+  AdjustedReturnValueChecker.cpp
   ArrayBoundChecker.cpp
   AttrNonNullChecker.cpp
   BasicConstraintManager.cpp
@@ -26,8 +27,8 @@ add_clang_library(clangChecker
   DivZeroChecker.cpp
   Environment.cpp
   ExplodedGraph.cpp
-  FlatStore.cpp
   FixedAddressChecker.cpp
+  FlatStore.cpp
   GRBlockCounter.cpp
   GRCoreEngine.cpp
   GRExprEngine.cpp
index 52e4fc12f8b18f7b88eae2fb537fc8d6cc505f6b..1e16bde5f1e412ec5170e305413d11002276f5df 100644 (file)
@@ -301,6 +301,7 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
   // their associated BugType will get registered with the BugReporter
   // automatically.  Note that the check itself is owned by the GRExprEngine
   // object.  
+  RegisterAdjustedReturnValueChecker(Eng);
   RegisterAttrNonNullChecker(Eng);
   RegisterCallAndMessageChecker(Eng);
   RegisterDereferenceChecker(Eng);
index e2354ed098880791e4d61af834cda9693ab75751..1246703b86f32d2820672dd69e13d30267846b79 100644 (file)
@@ -19,6 +19,7 @@ namespace clang {
 
 class GRExprEngine;
 
+void RegisterAdjustedReturnValueChecker(GRExprEngine &Eng);
 void RegisterAttrNonNullChecker(GRExprEngine &Eng);
 void RegisterDereferenceChecker(GRExprEngine &Eng);
 void RegisterDivZeroChecker(GRExprEngine &Eng);
index 88c73bc22e024b6e398cf1c3f1cfbe733d2e6f2b..949c51019f2525b705745ec2326ee922130e3c9a 100644 (file)
@@ -879,3 +879,17 @@ void foo_rev95192(int **x) {
   **x = 1; // no-warning
 }
 
+//===----------------------------------------------------------------------===//
+// Handle casts of a function to a function pointer with a different return
+// value.  We don't yet emit an error for such cases, but we now we at least
+// don't crash when the return value gets interpreted in a way that
+// violates our invariants.
+//===----------------------------------------------------------------------===//
+
+void *foo_rev95267();
+int bar_rev95267() {
+  char (*Callback_rev95267)(void) = (char (*)(void)) foo_rev95267;
+  if ((*Callback_rev95267)() == (char) 0)
+    return 1;
+  return 0;
+}