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 33 void 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 ProgramStateRef state = C.getState(); 41 const LocationContext *LCtx = C.getLocationContext(); 42 43 SVal V = state->getSVal(CE, LCtx); 44 45 if (V.isUnknown()) 46 return; 47 48 // Casting to void? Discard the value. 49 if (expectedResultTy->isVoidType()) { 50 C.addTransition(state->BindExpr(CE, LCtx, UnknownVal())); 51 return; 52 } 53 54 const MemRegion *callee = state->getSVal(CE->getCallee(), LCtx).getAsRegion(); 55 if (!callee) 56 return; 57 58 QualType actualResultTy; 59 60 if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) { 61 const FunctionDecl *FD = FT->getDecl(); 62 actualResultTy = FD->getResultType(); 63 } 64 else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) { 65 const BlockTextRegion *BR = BD->getCodeRegion(); 66 const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>(); 67 const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>(); 68 actualResultTy = FT->getResultType(); 69 } 70 71 // Can this happen? 72 if (actualResultTy.isNull()) 73 return; 74 75 // For now, ignore references. 76 if (actualResultTy->getAs<ReferenceType>()) 77 return; 78 79 80 // Are they the same? 81 if (expectedResultTy != actualResultTy) { 82 // FIXME: Do more checking and actual emit an error. At least performing 83 // the cast avoids some assertion failures elsewhere. 84 SValBuilder &svalBuilder = C.getSValBuilder(); 85 V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy); 86 C.addTransition(state->BindExpr(CE, LCtx, V)); 87 } 88 } 89 90 void ento::registerAdjustedReturnValueChecker(CheckerManager &mgr) { 91 mgr.registerChecker<AdjustedReturnValueChecker>(); 92 } 93