diff options
author | Ted Kremenek <kremenek@apple.com> | 2010-02-04 00:47:48 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2010-02-04 00:47:48 +0000 |
commit | 40c37e1a624c27f987458a3234f615d929e9d813 (patch) | |
tree | 328ac7dd44b457e58b48c7cafe688456fc13963e /lib/Checker | |
parent | 2663f527c2717295fbaed4715945b879ad68f4cf (diff) |
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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95268 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Checker')
-rw-r--r-- | lib/Checker/AdjustedReturnValueChecker.cpp | 90 | ||||
-rw-r--r-- | lib/Checker/CMakeLists.txt | 3 | ||||
-rw-r--r-- | lib/Checker/GRExprEngine.cpp | 1 | ||||
-rw-r--r-- | lib/Checker/GRExprEngineInternalChecks.h | 1 |
4 files changed, 94 insertions, 1 deletions
diff --git a/lib/Checker/AdjustedReturnValueChecker.cpp b/lib/Checker/AdjustedReturnValueChecker.cpp new file mode 100644 index 0000000000..898ce76a99 --- /dev/null +++ b/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/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt index 033ad33814..130378a247 100644 --- a/lib/Checker/CMakeLists.txt +++ b/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/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 52e4fc12f8..1e16bde5f1 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/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/lib/Checker/GRExprEngineInternalChecks.h b/lib/Checker/GRExprEngineInternalChecks.h index e2354ed098..1246703b86 100644 --- a/lib/Checker/GRExprEngineInternalChecks.h +++ b/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); |