Home | History | Annotate | Download | only in Checkers
      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