]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / ExprInspectionChecker.cpp
1 //==- ExprInspectionChecker.cpp - Used for regression tests ------*- 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 #include "ClangSACheckers.h"
11 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
12 #include "clang/StaticAnalyzer/Core/Checker.h"
13 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
14 #include "llvm/ADT/StringSwitch.h"
15
16 using namespace clang;
17 using namespace ento;
18
19 namespace {
20 class ExprInspectionChecker : public Checker< eval::Call > {
21   mutable OwningPtr<BugType> BT;
22
23   void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
24   void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const;
25
26   typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
27                                                  CheckerContext &C) const;
28
29 public:
30   bool evalCall(const CallExpr *CE, CheckerContext &C) const;
31 };
32 }
33
34 bool ExprInspectionChecker::evalCall(const CallExpr *CE,
35                                      CheckerContext &C) const {
36   // These checks should have no effect on the surrounding environment
37   // (globals should not be invalidated, etc), hence the use of evalCall.
38   FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
39     .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
40     .Case("clang_analyzer_checkInlined",
41           &ExprInspectionChecker::analyzerCheckInlined)
42     .Default(0);
43
44   if (!Handler)
45     return false;
46
47   (this->*Handler)(CE, C);
48   return true;
49 }
50
51 static const char *getArgumentValueString(const CallExpr *CE,
52                                           CheckerContext &C) {
53   if (CE->getNumArgs() == 0)
54     return "Missing assertion argument";
55
56   ExplodedNode *N = C.getPredecessor();
57   const LocationContext *LC = N->getLocationContext();
58   ProgramStateRef State = N->getState();
59
60   const Expr *Assertion = CE->getArg(0);
61   SVal AssertionVal = State->getSVal(Assertion, LC);
62
63   if (AssertionVal.isUndef())
64     return "UNDEFINED";
65
66   ProgramStateRef StTrue, StFalse;
67   llvm::tie(StTrue, StFalse) =
68     State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
69
70   if (StTrue) {
71     if (StFalse)
72       return "UNKNOWN";
73     else
74       return "TRUE";
75   } else {
76     if (StFalse)
77       return "FALSE";
78     else
79       llvm_unreachable("Invalid constraint; neither true or false.");
80   }
81 }
82
83 void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
84                                          CheckerContext &C) const {
85   ExplodedNode *N = C.getPredecessor();
86   const LocationContext *LC = N->getLocationContext();
87
88   // A specific instantiation of an inlined function may have more constrained
89   // values than can generally be assumed. Skip the check.
90   if (LC->getCurrentStackFrame()->getParent() != 0)
91     return;
92
93   if (!BT)
94     BT.reset(new BugType("Checking analyzer assumptions", "debug"));
95
96   BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
97   C.emitReport(R);
98 }
99
100 void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
101                                                  CheckerContext &C) const {
102   ExplodedNode *N = C.getPredecessor();
103   const LocationContext *LC = N->getLocationContext();
104
105   // An inlined function could conceivably also be analyzed as a top-level
106   // function. We ignore this case and only emit a message (TRUE or FALSE)
107   // when we are analyzing it as an inlined function. This means that
108   // clang_analyzer_checkInlined(true) should always print TRUE, but
109   // clang_analyzer_checkInlined(false) should never actually print anything.
110   if (LC->getCurrentStackFrame()->getParent() == 0)
111     return;
112
113   if (!BT)
114     BT.reset(new BugType("Checking analyzer assumptions", "debug"));
115
116   BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
117   C.emitReport(R);
118 }
119
120 void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
121   Mgr.registerChecker<ExprInspectionChecker>();
122 }
123