1 //== AdjustedReturnValueChecker.cpp -----------------------------*- C++ -*--==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines AdjustedReturnValueChecker, a simple check to see if the 11 // return value of a function call is different than the one the caller thinks 12 // it is. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "ClangSACheckers.h" 17 #include "clang/StaticAnalyzer/Core/Checker.h" 18 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 19 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 20 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 21 22 using namespace clang; 23 using namespace ento; 24 25 namespace { 26 class AdjustedReturnValueChecker : 27 public Checker< check::PostStmt<CallExpr> > { 28 public: 29 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; 30 }; 31 } 32 checkPostStmt(const CallExpr * CE,CheckerContext & C) const33void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE, 34 CheckerContext &C) const { 35 36 // Get the result type of the call. 37 QualType expectedResultTy = CE->getType(); 38 39 // Fetch the signature of the called function. 40 const GRState *state = C.getState(); 41 42 SVal V = state->getSVal(CE); 43 44 if (V.isUnknown()) 45 return; 46 47 // Casting to void? Discard the value. 48 if (expectedResultTy->isVoidType()) { 49 C.generateNode(state->BindExpr(CE, UnknownVal())); 50 return; 51 } 52 53 const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion(); 54 if (!callee) 55 return; 56 57 QualType actualResultTy; 58 59 if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) { 60 const FunctionDecl *FD = FT->getDecl(); 61 actualResultTy = FD->getResultType(); 62 } 63 else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) { 64 const BlockTextRegion *BR = BD->getCodeRegion(); 65 const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>(); 66 const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>(); 67 actualResultTy = FT->getResultType(); 68 } 69 70 // Can this happen? 71 if (actualResultTy.isNull()) 72 return; 73 74 // For now, ignore references. 75 if (actualResultTy->getAs<ReferenceType>()) 76 return; 77 78 79 // Are they the same? 80 if (expectedResultTy != actualResultTy) { 81 // FIXME: Do more checking and actual emit an error. At least performing 82 // the cast avoids some assertion failures elsewhere. 83 SValBuilder &svalBuilder = C.getSValBuilder(); 84 V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy); 85 C.generateNode(state->BindExpr(CE, V)); 86 } 87 } 88 registerAdjustedReturnValueChecker(CheckerManager & mgr)89void ento::registerAdjustedReturnValueChecker(CheckerManager &mgr) { 90 mgr.registerChecker<AdjustedReturnValueChecker>(); 91 } 92