blob: 4cb59539ec5c1db81c0a7a327784f808c1d3c275 [file] [log] [blame]
Jordy Rose93a9d822012-05-16 16:01:07 +00001//==- 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/Checker.h"
12#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
13#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Benjamin Kramer9852f582012-12-01 16:35:25 +000014#include "llvm/ADT/StringSwitch.h"
Jordy Rose93a9d822012-05-16 16:01:07 +000015
16using namespace clang;
17using namespace ento;
18
19namespace {
20class ExprInspectionChecker : public Checker< eval::Call > {
21 mutable OwningPtr<BugType> BT;
Jordan Rosee5399f12012-08-10 22:26:29 +000022
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
Jordy Rose93a9d822012-05-16 16:01:07 +000029public:
30 bool evalCall(const CallExpr *CE, CheckerContext &C) const;
31};
32}
33
34bool ExprInspectionChecker::evalCall(const CallExpr *CE,
Jordan Rosee5399f12012-08-10 22:26:29 +000035 CheckerContext &C) const {
Jordy Rose93a9d822012-05-16 16:01:07 +000036 // These checks should have no effect on the surrounding environment
Jordan Rosee5399f12012-08-10 22:26:29 +000037 // (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
51static 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(cast<DefinedOrUnknownSVal>(AssertionVal));
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
83void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
84 CheckerContext &C) const {
Jordy Rose93a9d822012-05-16 16:01:07 +000085 ExplodedNode *N = C.getPredecessor();
86 const LocationContext *LC = N->getLocationContext();
87
Jordy Rose93a9d822012-05-16 16:01:07 +000088 // A specific instantiation of an inlined function may have more constrained
89 // values than can generally be assumed. Skip the check.
Jordan Rosee5399f12012-08-10 22:26:29 +000090 if (LC->getCurrentStackFrame()->getParent() != 0)
91 return;
Jordy Rose93a9d822012-05-16 16:01:07 +000092
93 if (!BT)
94 BT.reset(new BugType("Checking analyzer assumptions", "debug"));
95
Jordan Rosee5399f12012-08-10 22:26:29 +000096 BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
Jordan Rose785950e2012-11-02 01:53:40 +000097 C.emitReport(R);
Jordan Rosee5399f12012-08-10 22:26:29 +000098}
Jordy Rose93a9d822012-05-16 16:01:07 +000099
Jordan Rosee5399f12012-08-10 22:26:29 +0000100void 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);
Jordan Rose785950e2012-11-02 01:53:40 +0000117 C.emitReport(R);
Jordy Rose93a9d822012-05-16 16:01:07 +0000118}
119
120void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
121 Mgr.registerChecker<ExprInspectionChecker>();
122}
123