• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
checkPostStmt(const CallExpr * CE,CheckerContext & C) const33 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 
registerAdjustedReturnValueChecker(CheckerManager & mgr)90 void ento::registerAdjustedReturnValueChecker(CheckerManager &mgr) {
91   mgr.registerChecker<AdjustedReturnValueChecker>();
92 }
93