clang  3.7.0
ExprInspectionChecker.cpp
Go to the documentation of this file.
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"
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 std::unique_ptr<BugType> BT;
22 
23  void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
24  void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const;
25  void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const;
26  void analyzerCrash(const CallExpr *CE, CheckerContext &C) const;
27 
28  typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
29  CheckerContext &C) const;
30 
31 public:
32  bool evalCall(const CallExpr *CE, CheckerContext &C) const;
33 };
34 }
35 
36 bool ExprInspectionChecker::evalCall(const CallExpr *CE,
37  CheckerContext &C) const {
38  // These checks should have no effect on the surrounding environment
39  // (globals should not be invalidated, etc), hence the use of evalCall.
40  FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
41  .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
42  .Case("clang_analyzer_checkInlined",
43  &ExprInspectionChecker::analyzerCheckInlined)
44  .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
45  .Case("clang_analyzer_warnIfReached", &ExprInspectionChecker::analyzerWarnIfReached)
46  .Default(nullptr);
47 
48  if (!Handler)
49  return false;
50 
51  (this->*Handler)(CE, C);
52  return true;
53 }
54 
55 static const char *getArgumentValueString(const CallExpr *CE,
56  CheckerContext &C) {
57  if (CE->getNumArgs() == 0)
58  return "Missing assertion argument";
59 
61  const LocationContext *LC = N->getLocationContext();
63 
64  const Expr *Assertion = CE->getArg(0);
65  SVal AssertionVal = State->getSVal(Assertion, LC);
66 
67  if (AssertionVal.isUndef())
68  return "UNDEFINED";
69 
70  ProgramStateRef StTrue, StFalse;
71  std::tie(StTrue, StFalse) =
72  State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
73 
74  if (StTrue) {
75  if (StFalse)
76  return "UNKNOWN";
77  else
78  return "TRUE";
79  } else {
80  if (StFalse)
81  return "FALSE";
82  else
83  llvm_unreachable("Invalid constraint; neither true or false.");
84  }
85 }
86 
87 void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
88  CheckerContext &C) const {
90  const LocationContext *LC = N->getLocationContext();
91 
92  // A specific instantiation of an inlined function may have more constrained
93  // values than can generally be assumed. Skip the check.
94  if (LC->getCurrentStackFrame()->getParent() != nullptr)
95  return;
96 
97  if (!BT)
98  BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
99 
100  C.emitReport(
101  llvm::make_unique<BugReport>(*BT, getArgumentValueString(CE, C), N));
102 }
103 
104 void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE,
105  CheckerContext &C) const {
106  ExplodedNode *N = C.getPredecessor();
107 
108  if (!BT)
109  BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
110 
111  C.emitReport(llvm::make_unique<BugReport>(*BT, "REACHABLE", N));
112 }
113 
114 void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
115  CheckerContext &C) const {
116  ExplodedNode *N = C.getPredecessor();
117  const LocationContext *LC = N->getLocationContext();
118 
119  // An inlined function could conceivably also be analyzed as a top-level
120  // function. We ignore this case and only emit a message (TRUE or FALSE)
121  // when we are analyzing it as an inlined function. This means that
122  // clang_analyzer_checkInlined(true) should always print TRUE, but
123  // clang_analyzer_checkInlined(false) should never actually print anything.
124  if (LC->getCurrentStackFrame()->getParent() == nullptr)
125  return;
126 
127  if (!BT)
128  BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
129 
130  C.emitReport(
131  llvm::make_unique<BugReport>(*BT, getArgumentValueString(CE, C), N));
132 }
133 
134 void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
135  CheckerContext &C) const {
136  LLVM_BUILTIN_TRAP;
137 }
138 
139 void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
140  Mgr.registerChecker<ExprInspectionChecker>();
141 }
142 
StringRef getCalleeName(const FunctionDecl *FunDecl) const
Get the name of the called function (path-sensitive).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2216
ExplodedNode * getPredecessor()
Returns the previous node in the exploded graph, which includes the state of the program before the c...
LineState State
const LocationContext * getLocationContext() const
const ProgramStateRef & getState() const
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker()
Used to register checkers.
const StackFrameContext * getCurrentStackFrame() const
bool isUndef() const
Definition: SVals.h:121
const LocationContext * getParent() const
static const char * getArgumentValueString(const CallExpr *CE, CheckerContext &C)
unsigned getNumArgs() const
Definition: Expr.h:2205
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition: SVals.h:75