clang API Documentation

AdjustedReturnValueChecker.cpp
Go to the documentation of this file.
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 }