]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / AdjustedReturnValueChecker.cpp
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   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
89 void ento::registerAdjustedReturnValueChecker(CheckerManager &mgr) {
90   mgr.registerChecker<AdjustedReturnValueChecker>();
91 }