summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2010-02-04 00:47:48 +0000
committerTed Kremenek <kremenek@apple.com>2010-02-04 00:47:48 +0000
commit1e3b95580c3e2327377a0ea846bc63fc9b845a69 (patch)
treeac98ca97ce44628334b9fde68b3cbda0c350a29b
parentb8355e3b9f4419f7cd0c85bcddc58feb4b26d07a (diff)
downloadbcm5719-llvm-1e3b95580c3e2327377a0ea846bc63fc9b845a69.tar.gz
bcm5719-llvm-1e3b95580c3e2327377a0ea846bc63fc9b845a69.zip
static analyzer: handle casts of a function to a function pointer with
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). llvm-svn: 95268
-rw-r--r--clang/lib/Checker/AdjustedReturnValueChecker.cpp90
-rw-r--r--clang/lib/Checker/CMakeLists.txt3
-rw-r--r--clang/lib/Checker/GRExprEngine.cpp1
-rw-r--r--clang/lib/Checker/GRExprEngineInternalChecks.h1
-rw-r--r--clang/test/Analysis/misc-ps.m14
5 files changed, 108 insertions, 1 deletions
diff --git a/clang/lib/Checker/AdjustedReturnValueChecker.cpp b/clang/lib/Checker/AdjustedReturnValueChecker.cpp
new file mode 100644
index 00000000000..898ce76a991
--- /dev/null
+++ b/clang/lib/Checker/AdjustedReturnValueChecker.cpp
@@ -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()));
+ }
+}
diff --git a/clang/lib/Checker/CMakeLists.txt b/clang/lib/Checker/CMakeLists.txt
index 033ad338143..130378a2477 100644
--- a/clang/lib/Checker/CMakeLists.txt
+++ b/clang/lib/Checker/CMakeLists.txt
@@ -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
diff --git a/clang/lib/Checker/GRExprEngine.cpp b/clang/lib/Checker/GRExprEngine.cpp
index 52e4fc12f8b..1e16bde5f1e 100644
--- a/clang/lib/Checker/GRExprEngine.cpp
+++ b/clang/lib/Checker/GRExprEngine.cpp
@@ -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);
diff --git a/clang/lib/Checker/GRExprEngineInternalChecks.h b/clang/lib/Checker/GRExprEngineInternalChecks.h
index e2354ed0988..1246703b86f 100644
--- a/clang/lib/Checker/GRExprEngineInternalChecks.h
+++ b/clang/lib/Checker/GRExprEngineInternalChecks.h
@@ -19,6 +19,7 @@ namespace clang {
class GRExprEngine;
+void RegisterAdjustedReturnValueChecker(GRExprEngine &Eng);
void RegisterAttrNonNullChecker(GRExprEngine &Eng);
void RegisterDereferenceChecker(GRExprEngine &Eng);
void RegisterDivZeroChecker(GRExprEngine &Eng);
diff --git a/clang/test/Analysis/misc-ps.m b/clang/test/Analysis/misc-ps.m
index 88c73bc22e0..949c51019f2 100644
--- a/clang/test/Analysis/misc-ps.m
+++ b/clang/test/Analysis/misc-ps.m
@@ -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;
+}
OpenPOWER on IntegriCloud