15 #include "llvm/ADT/StringSwitch.h"
16 #include "llvm/Support/ScopedPrinter.h"
18 using namespace clang;
22 class ExprInspectionChecker :
public Checker<eval::Call, check::DeadSymbols,
24 mutable std::unique_ptr<BugType> BT;
30 unsigned NumTimesReached;
32 mutable llvm::DenseMap<const CallExpr *, ReachedStat> ReachedStats;
45 typedef void (ExprInspectionChecker::*FnCheck)(
const CallExpr *,
66 FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
67 .Case(
"clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
68 .Case(
"clang_analyzer_checkInlined",
69 &ExprInspectionChecker::analyzerCheckInlined)
70 .Case(
"clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
71 .Case(
"clang_analyzer_warnIfReached",
72 &ExprInspectionChecker::analyzerWarnIfReached)
73 .Case(
"clang_analyzer_warnOnDeadSymbol",
74 &ExprInspectionChecker::analyzerWarnOnDeadSymbol)
75 .StartsWith(
"clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain)
76 .StartsWith(
"clang_analyzer_dump", &ExprInspectionChecker::analyzerDump)
77 .Case(
"clang_analyzer_getExtent", &ExprInspectionChecker::analyzerGetExtent)
78 .Case(
"clang_analyzer_printState",
79 &ExprInspectionChecker::analyzerPrintState)
80 .Case(
"clang_analyzer_numTimesReached",
81 &ExprInspectionChecker::analyzerNumTimesReached)
87 (this->*Handler)(CE, C);
94 return "Missing assertion argument";
101 SVal AssertionVal = State->getSVal(Assertion, LC);
107 std::tie(StTrue, StFalse) =
119 llvm_unreachable(
"Invalid constraint; neither true or false.");
123 ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
130 ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
137 BT.reset(
new BugType(
this,
"Checking analyzer assumptions",
"debug"));
139 BR.
emitReport(llvm::make_unique<BugReport>(*BT, Msg, N));
143 void ExprInspectionChecker::analyzerEval(
const CallExpr *CE,
155 void ExprInspectionChecker::analyzerWarnIfReached(
const CallExpr *CE,
157 reportBug(
"REACHABLE", C);
160 void ExprInspectionChecker::analyzerNumTimesReached(
const CallExpr *CE,
162 ++ReachedStats[CE].NumTimesReached;
163 if (!ReachedStats[CE].ExampleNode) {
169 void ExprInspectionChecker::analyzerCheckInlined(
const CallExpr *CE,
184 void ExprInspectionChecker::analyzerExplain(
const CallExpr *CE,
187 reportBug(
"Missing argument for explaining", C);
193 reportBug(Ex.Visit(V), C);
196 void ExprInspectionChecker::analyzerDump(
const CallExpr *CE,
199 reportBug(
"Missing argument for dumping", C);
206 llvm::raw_svector_ostream OS(Str);
208 reportBug(OS.str(), C);
211 void ExprInspectionChecker::analyzerGetExtent(
const CallExpr *CE,
214 reportBug(
"Missing region for obtaining extent", C);
218 auto MR = dyn_cast_or_null<SubRegion>(C.
getSVal(CE->
getArg(0)).getAsRegion());
220 reportBug(
"Obtaining extent of a non-region", C);
230 void ExprInspectionChecker::analyzerPrintState(
const CallExpr *CE,
235 void ExprInspectionChecker::analyzerWarnOnDeadSymbol(
const CallExpr *CE,
245 State = State->add<MarkedSymbols>(Sym);
249 void ExprInspectionChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
252 const MarkedSymbolsTy &Syms = State->get<MarkedSymbols>();
254 for (
auto I = Syms.begin(),
E = Syms.end();
I !=
E; ++
I) {
256 if (!SymReaper.
isDead(Sym))
260 if (
ExplodedNode *BugNode = reportBug(
"SYMBOL DEAD", C))
262 State = State->remove<MarkedSymbols>(Sym);
269 for (
auto Item: ReachedStats) {
270 unsigned NumTimesReached = Item.second.NumTimesReached;
273 reportBug(llvm::to_string(NumTimesReached), BR, N);
277 void ExprInspectionChecker::analyzerCrash(
const CallExpr *CE,
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
ExplodedNode * getPredecessor()
Returns the previous node in the exploded graph, which includes the state of the program before the c...
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
BugReporter & getBugReporter()
detail::InMemoryDirectory::const_iterator I
const LocationContext * getLocationContext() const
bool isDead(SymbolRef sym) const
Returns whether or not a symbol has been confirmed dead.
Expr - This represents one expression.
const ProgramStateRef & getState() const
const ProgramStateRef & getState() const
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
BugReporter is a utility class for generating PathDiagnostics for analysis.
CHECKER * registerChecker()
Used to register checkers.
const StackFrameContext * getCurrentStackFrame() const
void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
A class responsible for cleaning up unused symbols.
const LocationContext * getParent() const
ASTContext & getASTContext()
static const char * getArgumentValueString(const CallExpr *CE, CheckerContext &C)
detail::InMemoryDirectory::const_iterator E
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
void dumpToStream(raw_ostream &OS) const
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
SValBuilder & getSValBuilder()
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
const LocationContext * getLocationContext() const
SVal getSVal(const Stmt *S) const
Get the value of arbitrary expressions at this point in the path.