clang API Documentation
00001 //== AdjustedReturnValueChecker.cpp -----------------------------*- C++ -*--==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines AdjustedReturnValueChecker, a simple check to see if the 00011 // return value of a function call is different than the one the caller thinks 00012 // it is. 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #include "ClangSACheckers.h" 00017 #include "clang/StaticAnalyzer/Core/Checker.h" 00018 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00019 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00020 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 00021 00022 using namespace clang; 00023 using namespace ento; 00024 00025 namespace { 00026 class AdjustedReturnValueChecker : 00027 public Checker< check::PostStmt<CallExpr> > { 00028 public: 00029 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; 00030 }; 00031 } 00032 00033 void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE, 00034 CheckerContext &C) const { 00035 00036 // Get the result type of the call. 00037 QualType expectedResultTy = CE->getType(); 00038 00039 // Fetch the signature of the called function. 00040 ProgramStateRef state = C.getState(); 00041 const LocationContext *LCtx = C.getLocationContext(); 00042 00043 SVal V = state->getSVal(CE, LCtx); 00044 00045 if (V.isUnknown()) 00046 return; 00047 00048 // Casting to void? Discard the value. 00049 if (expectedResultTy->isVoidType()) { 00050 C.addTransition(state->BindExpr(CE, LCtx, UnknownVal())); 00051 return; 00052 } 00053 00054 const MemRegion *callee = state->getSVal(CE->getCallee(), LCtx).getAsRegion(); 00055 if (!callee) 00056 return; 00057 00058 QualType actualResultTy; 00059 00060 if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) { 00061 const FunctionDecl *FD = FT->getDecl(); 00062 actualResultTy = FD->getResultType(); 00063 } 00064 else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) { 00065 const BlockTextRegion *BR = BD->getCodeRegion(); 00066 const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>(); 00067 const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>(); 00068 actualResultTy = FT->getResultType(); 00069 } 00070 00071 // Can this happen? 00072 if (actualResultTy.isNull()) 00073 return; 00074 00075 // For now, ignore references. 00076 if (actualResultTy->getAs<ReferenceType>()) 00077 return; 00078 00079 00080 // Are they the same? 00081 if (expectedResultTy != actualResultTy) { 00082 // FIXME: Do more checking and actual emit an error. At least performing 00083 // the cast avoids some assertion failures elsewhere. 00084 SValBuilder &svalBuilder = C.getSValBuilder(); 00085 V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy); 00086 C.addTransition(state->BindExpr(CE, LCtx, V)); 00087 } 00088 } 00089 00090 void ento::registerAdjustedReturnValueChecker(CheckerManager &mgr) { 00091 mgr.registerChecker<AdjustedReturnValueChecker>(); 00092 }