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 22using namespace clang; 23using namespace ento; 24 25namespace { 26class AdjustedReturnValueChecker : 27 public Checker< check::PostStmt<CallExpr> > { 28public: 29 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; 30}; 31} 32 33void 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 ProgramState *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 89void ento::registerAdjustedReturnValueChecker(CheckerManager &mgr) { 90 mgr.registerChecker<AdjustedReturnValueChecker>(); 91} 92