17330f729Sjoerg //==- ExprInspectionChecker.cpp - Used for regression tests ------*- C++ -*-==//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg
9*e038c9c4Sjoerg #include "Taint.h"
10*e038c9c4Sjoerg #include "clang/Analysis/IssueHash.h"
117330f729Sjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
127330f729Sjoerg #include "clang/StaticAnalyzer/Checkers/SValExplainer.h"
137330f729Sjoerg #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
147330f729Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
157330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
167330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
17*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
187330f729Sjoerg #include "llvm/ADT/StringSwitch.h"
197330f729Sjoerg #include "llvm/Support/ScopedPrinter.h"
207330f729Sjoerg
217330f729Sjoerg using namespace clang;
227330f729Sjoerg using namespace ento;
237330f729Sjoerg
247330f729Sjoerg namespace {
25*e038c9c4Sjoerg class ExprInspectionChecker
26*e038c9c4Sjoerg : public Checker<eval::Call, check::DeadSymbols, check::EndAnalysis> {
277330f729Sjoerg mutable std::unique_ptr<BugType> BT;
287330f729Sjoerg
297330f729Sjoerg // These stats are per-analysis, not per-branch, hence they shouldn't
307330f729Sjoerg // stay inside the program state.
317330f729Sjoerg struct ReachedStat {
327330f729Sjoerg ExplodedNode *ExampleNode;
337330f729Sjoerg unsigned NumTimesReached;
347330f729Sjoerg };
357330f729Sjoerg mutable llvm::DenseMap<const CallExpr *, ReachedStat> ReachedStats;
367330f729Sjoerg
377330f729Sjoerg void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
387330f729Sjoerg void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const;
397330f729Sjoerg void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const;
407330f729Sjoerg void analyzerNumTimesReached(const CallExpr *CE, CheckerContext &C) const;
417330f729Sjoerg void analyzerCrash(const CallExpr *CE, CheckerContext &C) const;
427330f729Sjoerg void analyzerWarnOnDeadSymbol(const CallExpr *CE, CheckerContext &C) const;
437330f729Sjoerg void analyzerDump(const CallExpr *CE, CheckerContext &C) const;
447330f729Sjoerg void analyzerExplain(const CallExpr *CE, CheckerContext &C) const;
457330f729Sjoerg void analyzerPrintState(const CallExpr *CE, CheckerContext &C) const;
467330f729Sjoerg void analyzerGetExtent(const CallExpr *CE, CheckerContext &C) const;
47*e038c9c4Sjoerg void analyzerDumpExtent(const CallExpr *CE, CheckerContext &C) const;
48*e038c9c4Sjoerg void analyzerDumpElementCount(const CallExpr *CE, CheckerContext &C) const;
497330f729Sjoerg void analyzerHashDump(const CallExpr *CE, CheckerContext &C) const;
507330f729Sjoerg void analyzerDenote(const CallExpr *CE, CheckerContext &C) const;
517330f729Sjoerg void analyzerExpress(const CallExpr *CE, CheckerContext &C) const;
52*e038c9c4Sjoerg void analyzerIsTainted(const CallExpr *CE, CheckerContext &C) const;
537330f729Sjoerg
547330f729Sjoerg typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
557330f729Sjoerg CheckerContext &C) const;
567330f729Sjoerg
57*e038c9c4Sjoerg // Optional parameter `ExprVal` for expression value to be marked interesting.
58*e038c9c4Sjoerg ExplodedNode *reportBug(llvm::StringRef Msg, CheckerContext &C,
59*e038c9c4Sjoerg Optional<SVal> ExprVal = None) const;
60*e038c9c4Sjoerg ExplodedNode *reportBug(llvm::StringRef Msg, BugReporter &BR, ExplodedNode *N,
61*e038c9c4Sjoerg Optional<SVal> ExprVal = None) const;
62*e038c9c4Sjoerg
63*e038c9c4Sjoerg const Expr *getArgExpr(const CallExpr *CE, CheckerContext &C) const;
64*e038c9c4Sjoerg const MemRegion *getArgRegion(const CallExpr *CE, CheckerContext &C) const;
657330f729Sjoerg
667330f729Sjoerg public:
677330f729Sjoerg bool evalCall(const CallEvent &Call, CheckerContext &C) const;
687330f729Sjoerg void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
697330f729Sjoerg void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
707330f729Sjoerg ExprEngine &Eng) const;
717330f729Sjoerg };
72*e038c9c4Sjoerg } // namespace
737330f729Sjoerg
REGISTER_SET_WITH_PROGRAMSTATE(MarkedSymbols,SymbolRef)747330f729Sjoerg REGISTER_SET_WITH_PROGRAMSTATE(MarkedSymbols, SymbolRef)
757330f729Sjoerg REGISTER_MAP_WITH_PROGRAMSTATE(DenotedSymbols, SymbolRef, const StringLiteral *)
767330f729Sjoerg
777330f729Sjoerg bool ExprInspectionChecker::evalCall(const CallEvent &Call,
787330f729Sjoerg CheckerContext &C) const {
797330f729Sjoerg const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
807330f729Sjoerg if (!CE)
817330f729Sjoerg return false;
827330f729Sjoerg
837330f729Sjoerg // These checks should have no effect on the surrounding environment
847330f729Sjoerg // (globals should not be invalidated, etc), hence the use of evalCall.
85*e038c9c4Sjoerg FnCheck Handler =
86*e038c9c4Sjoerg llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
877330f729Sjoerg .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
887330f729Sjoerg .Case("clang_analyzer_checkInlined",
897330f729Sjoerg &ExprInspectionChecker::analyzerCheckInlined)
907330f729Sjoerg .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
917330f729Sjoerg .Case("clang_analyzer_warnIfReached",
927330f729Sjoerg &ExprInspectionChecker::analyzerWarnIfReached)
937330f729Sjoerg .Case("clang_analyzer_warnOnDeadSymbol",
947330f729Sjoerg &ExprInspectionChecker::analyzerWarnOnDeadSymbol)
95*e038c9c4Sjoerg .StartsWith("clang_analyzer_explain",
96*e038c9c4Sjoerg &ExprInspectionChecker::analyzerExplain)
97*e038c9c4Sjoerg .Case("clang_analyzer_dumpExtent",
98*e038c9c4Sjoerg &ExprInspectionChecker::analyzerDumpExtent)
99*e038c9c4Sjoerg .Case("clang_analyzer_dumpElementCount",
100*e038c9c4Sjoerg &ExprInspectionChecker::analyzerDumpElementCount)
101*e038c9c4Sjoerg .StartsWith("clang_analyzer_dump",
102*e038c9c4Sjoerg &ExprInspectionChecker::analyzerDump)
103*e038c9c4Sjoerg .Case("clang_analyzer_getExtent",
104*e038c9c4Sjoerg &ExprInspectionChecker::analyzerGetExtent)
1057330f729Sjoerg .Case("clang_analyzer_printState",
1067330f729Sjoerg &ExprInspectionChecker::analyzerPrintState)
1077330f729Sjoerg .Case("clang_analyzer_numTimesReached",
1087330f729Sjoerg &ExprInspectionChecker::analyzerNumTimesReached)
109*e038c9c4Sjoerg .Case("clang_analyzer_hashDump",
110*e038c9c4Sjoerg &ExprInspectionChecker::analyzerHashDump)
1117330f729Sjoerg .Case("clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote)
112*e038c9c4Sjoerg .Case("clang_analyzer_express",
113*e038c9c4Sjoerg &ExprInspectionChecker::analyzerExpress)
114*e038c9c4Sjoerg .StartsWith("clang_analyzer_isTainted",
115*e038c9c4Sjoerg &ExprInspectionChecker::analyzerIsTainted)
1167330f729Sjoerg .Default(nullptr);
1177330f729Sjoerg
1187330f729Sjoerg if (!Handler)
1197330f729Sjoerg return false;
1207330f729Sjoerg
1217330f729Sjoerg (this->*Handler)(CE, C);
1227330f729Sjoerg return true;
1237330f729Sjoerg }
1247330f729Sjoerg
getArgumentValueString(const CallExpr * CE,CheckerContext & C)1257330f729Sjoerg static const char *getArgumentValueString(const CallExpr *CE,
1267330f729Sjoerg CheckerContext &C) {
1277330f729Sjoerg if (CE->getNumArgs() == 0)
1287330f729Sjoerg return "Missing assertion argument";
1297330f729Sjoerg
1307330f729Sjoerg ExplodedNode *N = C.getPredecessor();
1317330f729Sjoerg const LocationContext *LC = N->getLocationContext();
1327330f729Sjoerg ProgramStateRef State = N->getState();
1337330f729Sjoerg
1347330f729Sjoerg const Expr *Assertion = CE->getArg(0);
1357330f729Sjoerg SVal AssertionVal = State->getSVal(Assertion, LC);
1367330f729Sjoerg
1377330f729Sjoerg if (AssertionVal.isUndef())
1387330f729Sjoerg return "UNDEFINED";
1397330f729Sjoerg
1407330f729Sjoerg ProgramStateRef StTrue, StFalse;
1417330f729Sjoerg std::tie(StTrue, StFalse) =
1427330f729Sjoerg State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
1437330f729Sjoerg
1447330f729Sjoerg if (StTrue) {
1457330f729Sjoerg if (StFalse)
1467330f729Sjoerg return "UNKNOWN";
1477330f729Sjoerg else
1487330f729Sjoerg return "TRUE";
1497330f729Sjoerg } else {
1507330f729Sjoerg if (StFalse)
1517330f729Sjoerg return "FALSE";
1527330f729Sjoerg else
1537330f729Sjoerg llvm_unreachable("Invalid constraint; neither true or false.");
1547330f729Sjoerg }
1557330f729Sjoerg }
1567330f729Sjoerg
reportBug(llvm::StringRef Msg,CheckerContext & C,Optional<SVal> ExprVal) const1577330f729Sjoerg ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
158*e038c9c4Sjoerg CheckerContext &C,
159*e038c9c4Sjoerg Optional<SVal> ExprVal) const {
1607330f729Sjoerg ExplodedNode *N = C.generateNonFatalErrorNode();
161*e038c9c4Sjoerg reportBug(Msg, C.getBugReporter(), N, ExprVal);
1627330f729Sjoerg return N;
1637330f729Sjoerg }
1647330f729Sjoerg
reportBug(llvm::StringRef Msg,BugReporter & BR,ExplodedNode * N,Optional<SVal> ExprVal) const1657330f729Sjoerg ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
166*e038c9c4Sjoerg BugReporter &BR, ExplodedNode *N,
167*e038c9c4Sjoerg Optional<SVal> ExprVal) const {
1687330f729Sjoerg if (!N)
1697330f729Sjoerg return nullptr;
1707330f729Sjoerg
1717330f729Sjoerg if (!BT)
1727330f729Sjoerg BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
1737330f729Sjoerg
174*e038c9c4Sjoerg auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
175*e038c9c4Sjoerg if (ExprVal) {
176*e038c9c4Sjoerg R->markInteresting(*ExprVal);
177*e038c9c4Sjoerg }
178*e038c9c4Sjoerg BR.emitReport(std::move(R));
1797330f729Sjoerg return N;
1807330f729Sjoerg }
1817330f729Sjoerg
getArgExpr(const CallExpr * CE,CheckerContext & C) const182*e038c9c4Sjoerg const Expr *ExprInspectionChecker::getArgExpr(const CallExpr *CE,
183*e038c9c4Sjoerg CheckerContext &C) const {
184*e038c9c4Sjoerg if (CE->getNumArgs() == 0) {
185*e038c9c4Sjoerg reportBug("Missing argument", C);
186*e038c9c4Sjoerg return nullptr;
187*e038c9c4Sjoerg }
188*e038c9c4Sjoerg return CE->getArg(0);
189*e038c9c4Sjoerg }
190*e038c9c4Sjoerg
getArgRegion(const CallExpr * CE,CheckerContext & C) const191*e038c9c4Sjoerg const MemRegion *ExprInspectionChecker::getArgRegion(const CallExpr *CE,
192*e038c9c4Sjoerg CheckerContext &C) const {
193*e038c9c4Sjoerg const Expr *Arg = getArgExpr(CE, C);
194*e038c9c4Sjoerg if (!Arg)
195*e038c9c4Sjoerg return nullptr;
196*e038c9c4Sjoerg
197*e038c9c4Sjoerg const MemRegion *MR = C.getSVal(Arg).getAsRegion();
198*e038c9c4Sjoerg if (!MR) {
199*e038c9c4Sjoerg reportBug("Cannot obtain the region", C);
200*e038c9c4Sjoerg return nullptr;
201*e038c9c4Sjoerg }
202*e038c9c4Sjoerg
203*e038c9c4Sjoerg return MR;
204*e038c9c4Sjoerg }
205*e038c9c4Sjoerg
analyzerEval(const CallExpr * CE,CheckerContext & C) const2067330f729Sjoerg void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
2077330f729Sjoerg CheckerContext &C) const {
2087330f729Sjoerg const LocationContext *LC = C.getPredecessor()->getLocationContext();
2097330f729Sjoerg
2107330f729Sjoerg // A specific instantiation of an inlined function may have more constrained
2117330f729Sjoerg // values than can generally be assumed. Skip the check.
2127330f729Sjoerg if (LC->getStackFrame()->getParent() != nullptr)
2137330f729Sjoerg return;
2147330f729Sjoerg
2157330f729Sjoerg reportBug(getArgumentValueString(CE, C), C);
2167330f729Sjoerg }
2177330f729Sjoerg
analyzerWarnIfReached(const CallExpr * CE,CheckerContext & C) const2187330f729Sjoerg void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE,
2197330f729Sjoerg CheckerContext &C) const {
2207330f729Sjoerg reportBug("REACHABLE", C);
2217330f729Sjoerg }
2227330f729Sjoerg
analyzerNumTimesReached(const CallExpr * CE,CheckerContext & C) const2237330f729Sjoerg void ExprInspectionChecker::analyzerNumTimesReached(const CallExpr *CE,
2247330f729Sjoerg CheckerContext &C) const {
2257330f729Sjoerg ++ReachedStats[CE].NumTimesReached;
2267330f729Sjoerg if (!ReachedStats[CE].ExampleNode) {
2277330f729Sjoerg // Later, in checkEndAnalysis, we'd throw a report against it.
2287330f729Sjoerg ReachedStats[CE].ExampleNode = C.generateNonFatalErrorNode();
2297330f729Sjoerg }
2307330f729Sjoerg }
2317330f729Sjoerg
analyzerCheckInlined(const CallExpr * CE,CheckerContext & C) const2327330f729Sjoerg void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
2337330f729Sjoerg CheckerContext &C) const {
2347330f729Sjoerg const LocationContext *LC = C.getPredecessor()->getLocationContext();
2357330f729Sjoerg
2367330f729Sjoerg // An inlined function could conceivably also be analyzed as a top-level
2377330f729Sjoerg // function. We ignore this case and only emit a message (TRUE or FALSE)
2387330f729Sjoerg // when we are analyzing it as an inlined function. This means that
2397330f729Sjoerg // clang_analyzer_checkInlined(true) should always print TRUE, but
2407330f729Sjoerg // clang_analyzer_checkInlined(false) should never actually print anything.
2417330f729Sjoerg if (LC->getStackFrame()->getParent() == nullptr)
2427330f729Sjoerg return;
2437330f729Sjoerg
2447330f729Sjoerg reportBug(getArgumentValueString(CE, C), C);
2457330f729Sjoerg }
2467330f729Sjoerg
analyzerExplain(const CallExpr * CE,CheckerContext & C) const2477330f729Sjoerg void ExprInspectionChecker::analyzerExplain(const CallExpr *CE,
2487330f729Sjoerg CheckerContext &C) const {
249*e038c9c4Sjoerg const Expr *Arg = getArgExpr(CE, C);
250*e038c9c4Sjoerg if (!Arg)
2517330f729Sjoerg return;
2527330f729Sjoerg
253*e038c9c4Sjoerg SVal V = C.getSVal(Arg);
2547330f729Sjoerg SValExplainer Ex(C.getASTContext());
2557330f729Sjoerg reportBug(Ex.Visit(V), C);
2567330f729Sjoerg }
2577330f729Sjoerg
analyzerDump(const CallExpr * CE,CheckerContext & C) const2587330f729Sjoerg void ExprInspectionChecker::analyzerDump(const CallExpr *CE,
2597330f729Sjoerg CheckerContext &C) const {
260*e038c9c4Sjoerg const Expr *Arg = getArgExpr(CE, C);
261*e038c9c4Sjoerg if (!Arg)
2627330f729Sjoerg return;
2637330f729Sjoerg
264*e038c9c4Sjoerg SVal V = C.getSVal(Arg);
2657330f729Sjoerg
2667330f729Sjoerg llvm::SmallString<32> Str;
2677330f729Sjoerg llvm::raw_svector_ostream OS(Str);
2687330f729Sjoerg V.dumpToStream(OS);
2697330f729Sjoerg reportBug(OS.str(), C);
2707330f729Sjoerg }
2717330f729Sjoerg
analyzerGetExtent(const CallExpr * CE,CheckerContext & C) const2727330f729Sjoerg void ExprInspectionChecker::analyzerGetExtent(const CallExpr *CE,
2737330f729Sjoerg CheckerContext &C) const {
274*e038c9c4Sjoerg const MemRegion *MR = getArgRegion(CE, C);
275*e038c9c4Sjoerg if (!MR)
2767330f729Sjoerg return;
2777330f729Sjoerg
2787330f729Sjoerg ProgramStateRef State = C.getState();
279*e038c9c4Sjoerg DefinedOrUnknownSVal Size = getDynamicExtent(State, MR, C.getSValBuilder());
280*e038c9c4Sjoerg
281*e038c9c4Sjoerg State = State->BindExpr(CE, C.getLocationContext(), Size);
2827330f729Sjoerg C.addTransition(State);
2837330f729Sjoerg }
2847330f729Sjoerg
analyzerDumpExtent(const CallExpr * CE,CheckerContext & C) const285*e038c9c4Sjoerg void ExprInspectionChecker::analyzerDumpExtent(const CallExpr *CE,
286*e038c9c4Sjoerg CheckerContext &C) const {
287*e038c9c4Sjoerg const MemRegion *MR = getArgRegion(CE, C);
288*e038c9c4Sjoerg if (!MR)
289*e038c9c4Sjoerg return;
290*e038c9c4Sjoerg
291*e038c9c4Sjoerg DefinedOrUnknownSVal Size =
292*e038c9c4Sjoerg getDynamicExtent(C.getState(), MR, C.getSValBuilder());
293*e038c9c4Sjoerg
294*e038c9c4Sjoerg SmallString<64> Msg;
295*e038c9c4Sjoerg llvm::raw_svector_ostream Out(Msg);
296*e038c9c4Sjoerg Out << Size;
297*e038c9c4Sjoerg reportBug(Out.str(), C);
298*e038c9c4Sjoerg }
299*e038c9c4Sjoerg
analyzerDumpElementCount(const CallExpr * CE,CheckerContext & C) const300*e038c9c4Sjoerg void ExprInspectionChecker::analyzerDumpElementCount(const CallExpr *CE,
301*e038c9c4Sjoerg CheckerContext &C) const {
302*e038c9c4Sjoerg const MemRegion *MR = getArgRegion(CE, C);
303*e038c9c4Sjoerg if (!MR)
304*e038c9c4Sjoerg return;
305*e038c9c4Sjoerg
306*e038c9c4Sjoerg QualType ElementTy;
307*e038c9c4Sjoerg if (const auto *TVR = MR->getAs<TypedValueRegion>()) {
308*e038c9c4Sjoerg ElementTy = TVR->getValueType();
309*e038c9c4Sjoerg } else {
310*e038c9c4Sjoerg ElementTy =
311*e038c9c4Sjoerg MR->castAs<SymbolicRegion>()->getSymbol()->getType()->getPointeeType();
312*e038c9c4Sjoerg }
313*e038c9c4Sjoerg
314*e038c9c4Sjoerg assert(!ElementTy->isPointerType());
315*e038c9c4Sjoerg
316*e038c9c4Sjoerg DefinedOrUnknownSVal ElementCount =
317*e038c9c4Sjoerg getDynamicElementCount(C.getState(), MR, C.getSValBuilder(), ElementTy);
318*e038c9c4Sjoerg
319*e038c9c4Sjoerg SmallString<128> Msg;
320*e038c9c4Sjoerg llvm::raw_svector_ostream Out(Msg);
321*e038c9c4Sjoerg Out << ElementCount;
322*e038c9c4Sjoerg reportBug(Out.str(), C);
323*e038c9c4Sjoerg }
324*e038c9c4Sjoerg
analyzerPrintState(const CallExpr * CE,CheckerContext & C) const3257330f729Sjoerg void ExprInspectionChecker::analyzerPrintState(const CallExpr *CE,
3267330f729Sjoerg CheckerContext &C) const {
3277330f729Sjoerg C.getState()->dump();
3287330f729Sjoerg }
3297330f729Sjoerg
analyzerWarnOnDeadSymbol(const CallExpr * CE,CheckerContext & C) const3307330f729Sjoerg void ExprInspectionChecker::analyzerWarnOnDeadSymbol(const CallExpr *CE,
3317330f729Sjoerg CheckerContext &C) const {
332*e038c9c4Sjoerg const Expr *Arg = getArgExpr(CE, C);
333*e038c9c4Sjoerg if (!Arg)
3347330f729Sjoerg return;
335*e038c9c4Sjoerg
336*e038c9c4Sjoerg SVal Val = C.getSVal(Arg);
3377330f729Sjoerg SymbolRef Sym = Val.getAsSymbol();
3387330f729Sjoerg if (!Sym)
3397330f729Sjoerg return;
3407330f729Sjoerg
3417330f729Sjoerg ProgramStateRef State = C.getState();
3427330f729Sjoerg State = State->add<MarkedSymbols>(Sym);
3437330f729Sjoerg C.addTransition(State);
3447330f729Sjoerg }
3457330f729Sjoerg
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const3467330f729Sjoerg void ExprInspectionChecker::checkDeadSymbols(SymbolReaper &SymReaper,
3477330f729Sjoerg CheckerContext &C) const {
3487330f729Sjoerg ProgramStateRef State = C.getState();
3497330f729Sjoerg const MarkedSymbolsTy &Syms = State->get<MarkedSymbols>();
3507330f729Sjoerg ExplodedNode *N = C.getPredecessor();
3517330f729Sjoerg for (auto I = Syms.begin(), E = Syms.end(); I != E; ++I) {
3527330f729Sjoerg SymbolRef Sym = *I;
3537330f729Sjoerg if (!SymReaper.isDead(Sym))
3547330f729Sjoerg continue;
3557330f729Sjoerg
3567330f729Sjoerg // The non-fatal error node should be the same for all reports.
3577330f729Sjoerg if (ExplodedNode *BugNode = reportBug("SYMBOL DEAD", C))
3587330f729Sjoerg N = BugNode;
3597330f729Sjoerg State = State->remove<MarkedSymbols>(Sym);
3607330f729Sjoerg }
3617330f729Sjoerg
3627330f729Sjoerg for (auto I : State->get<DenotedSymbols>()) {
3637330f729Sjoerg SymbolRef Sym = I.first;
3647330f729Sjoerg if (!SymReaper.isLive(Sym))
3657330f729Sjoerg State = State->remove<DenotedSymbols>(Sym);
3667330f729Sjoerg }
3677330f729Sjoerg
3687330f729Sjoerg C.addTransition(State, N);
3697330f729Sjoerg }
3707330f729Sjoerg
checkEndAnalysis(ExplodedGraph & G,BugReporter & BR,ExprEngine & Eng) const3717330f729Sjoerg void ExprInspectionChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
3727330f729Sjoerg ExprEngine &Eng) const {
3737330f729Sjoerg for (auto Item : ReachedStats) {
3747330f729Sjoerg unsigned NumTimesReached = Item.second.NumTimesReached;
3757330f729Sjoerg ExplodedNode *N = Item.second.ExampleNode;
3767330f729Sjoerg
3777330f729Sjoerg reportBug(llvm::to_string(NumTimesReached), BR, N);
3787330f729Sjoerg }
3797330f729Sjoerg ReachedStats.clear();
3807330f729Sjoerg }
3817330f729Sjoerg
analyzerCrash(const CallExpr * CE,CheckerContext & C) const3827330f729Sjoerg void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
3837330f729Sjoerg CheckerContext &C) const {
3847330f729Sjoerg LLVM_BUILTIN_TRAP;
3857330f729Sjoerg }
3867330f729Sjoerg
analyzerHashDump(const CallExpr * CE,CheckerContext & C) const3877330f729Sjoerg void ExprInspectionChecker::analyzerHashDump(const CallExpr *CE,
3887330f729Sjoerg CheckerContext &C) const {
3897330f729Sjoerg const LangOptions &Opts = C.getLangOpts();
3907330f729Sjoerg const SourceManager &SM = C.getSourceManager();
3917330f729Sjoerg FullSourceLoc FL(CE->getArg(0)->getBeginLoc(), SM);
3927330f729Sjoerg std::string HashContent =
393*e038c9c4Sjoerg getIssueString(FL, getCheckerName().getName(), "Category",
3947330f729Sjoerg C.getLocationContext()->getDecl(), Opts);
3957330f729Sjoerg
3967330f729Sjoerg reportBug(HashContent, C);
3977330f729Sjoerg }
3987330f729Sjoerg
analyzerDenote(const CallExpr * CE,CheckerContext & C) const3997330f729Sjoerg void ExprInspectionChecker::analyzerDenote(const CallExpr *CE,
4007330f729Sjoerg CheckerContext &C) const {
4017330f729Sjoerg if (CE->getNumArgs() < 2) {
4027330f729Sjoerg reportBug("clang_analyzer_denote() requires a symbol and a string literal",
4037330f729Sjoerg C);
4047330f729Sjoerg return;
4057330f729Sjoerg }
4067330f729Sjoerg
4077330f729Sjoerg SymbolRef Sym = C.getSVal(CE->getArg(0)).getAsSymbol();
4087330f729Sjoerg if (!Sym) {
4097330f729Sjoerg reportBug("Not a symbol", C);
4107330f729Sjoerg return;
4117330f729Sjoerg }
4127330f729Sjoerg
4137330f729Sjoerg const auto *E = dyn_cast<StringLiteral>(CE->getArg(1)->IgnoreParenCasts());
4147330f729Sjoerg if (!E) {
4157330f729Sjoerg reportBug("Not a string literal", C);
4167330f729Sjoerg return;
4177330f729Sjoerg }
4187330f729Sjoerg
4197330f729Sjoerg ProgramStateRef State = C.getState();
4207330f729Sjoerg
4217330f729Sjoerg C.addTransition(C.getState()->set<DenotedSymbols>(Sym, E));
4227330f729Sjoerg }
4237330f729Sjoerg
4247330f729Sjoerg namespace {
4257330f729Sjoerg class SymbolExpressor
4267330f729Sjoerg : public SymExprVisitor<SymbolExpressor, Optional<std::string>> {
4277330f729Sjoerg ProgramStateRef State;
4287330f729Sjoerg
4297330f729Sjoerg public:
SymbolExpressor(ProgramStateRef State)4307330f729Sjoerg SymbolExpressor(ProgramStateRef State) : State(State) {}
4317330f729Sjoerg
lookup(const SymExpr * S)4327330f729Sjoerg Optional<std::string> lookup(const SymExpr *S) {
4337330f729Sjoerg if (const StringLiteral *const *SLPtr = State->get<DenotedSymbols>(S)) {
4347330f729Sjoerg const StringLiteral *SL = *SLPtr;
4357330f729Sjoerg return std::string(SL->getBytes());
4367330f729Sjoerg }
4377330f729Sjoerg return None;
4387330f729Sjoerg }
4397330f729Sjoerg
VisitSymExpr(const SymExpr * S)440*e038c9c4Sjoerg Optional<std::string> VisitSymExpr(const SymExpr *S) { return lookup(S); }
4417330f729Sjoerg
VisitSymIntExpr(const SymIntExpr * S)4427330f729Sjoerg Optional<std::string> VisitSymIntExpr(const SymIntExpr *S) {
4437330f729Sjoerg if (Optional<std::string> Str = lookup(S))
4447330f729Sjoerg return Str;
4457330f729Sjoerg if (Optional<std::string> Str = Visit(S->getLHS()))
4467330f729Sjoerg return (*Str + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) + " " +
4477330f729Sjoerg std::to_string(S->getRHS().getLimitedValue()) +
4487330f729Sjoerg (S->getRHS().isUnsigned() ? "U" : ""))
4497330f729Sjoerg .str();
4507330f729Sjoerg return None;
4517330f729Sjoerg }
4527330f729Sjoerg
VisitSymSymExpr(const SymSymExpr * S)4537330f729Sjoerg Optional<std::string> VisitSymSymExpr(const SymSymExpr *S) {
4547330f729Sjoerg if (Optional<std::string> Str = lookup(S))
4557330f729Sjoerg return Str;
4567330f729Sjoerg if (Optional<std::string> Str1 = Visit(S->getLHS()))
4577330f729Sjoerg if (Optional<std::string> Str2 = Visit(S->getRHS()))
4587330f729Sjoerg return (*Str1 + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) +
459*e038c9c4Sjoerg " " + *Str2)
460*e038c9c4Sjoerg .str();
4617330f729Sjoerg return None;
4627330f729Sjoerg }
4637330f729Sjoerg
VisitSymbolCast(const SymbolCast * S)4647330f729Sjoerg Optional<std::string> VisitSymbolCast(const SymbolCast *S) {
4657330f729Sjoerg if (Optional<std::string> Str = lookup(S))
4667330f729Sjoerg return Str;
4677330f729Sjoerg if (Optional<std::string> Str = Visit(S->getOperand()))
4687330f729Sjoerg return (Twine("(") + S->getType().getAsString() + ")" + *Str).str();
4697330f729Sjoerg return None;
4707330f729Sjoerg }
4717330f729Sjoerg };
4727330f729Sjoerg } // namespace
4737330f729Sjoerg
analyzerExpress(const CallExpr * CE,CheckerContext & C) const4747330f729Sjoerg void ExprInspectionChecker::analyzerExpress(const CallExpr *CE,
4757330f729Sjoerg CheckerContext &C) const {
476*e038c9c4Sjoerg const Expr *Arg = getArgExpr(CE, C);
477*e038c9c4Sjoerg if (!Arg)
4787330f729Sjoerg return;
4797330f729Sjoerg
480*e038c9c4Sjoerg SVal ArgVal = C.getSVal(CE->getArg(0));
481*e038c9c4Sjoerg SymbolRef Sym = ArgVal.getAsSymbol();
4827330f729Sjoerg if (!Sym) {
4837330f729Sjoerg reportBug("Not a symbol", C);
4847330f729Sjoerg return;
4857330f729Sjoerg }
4867330f729Sjoerg
4877330f729Sjoerg SymbolExpressor V(C.getState());
4887330f729Sjoerg auto Str = V.Visit(Sym);
4897330f729Sjoerg if (!Str) {
4907330f729Sjoerg reportBug("Unable to express", C);
4917330f729Sjoerg return;
4927330f729Sjoerg }
4937330f729Sjoerg
494*e038c9c4Sjoerg reportBug(*Str, C, ArgVal);
495*e038c9c4Sjoerg }
496*e038c9c4Sjoerg
analyzerIsTainted(const CallExpr * CE,CheckerContext & C) const497*e038c9c4Sjoerg void ExprInspectionChecker::analyzerIsTainted(const CallExpr *CE,
498*e038c9c4Sjoerg CheckerContext &C) const {
499*e038c9c4Sjoerg if (CE->getNumArgs() != 1) {
500*e038c9c4Sjoerg reportBug("clang_analyzer_isTainted() requires exactly one argument", C);
501*e038c9c4Sjoerg return;
502*e038c9c4Sjoerg }
503*e038c9c4Sjoerg const bool IsTainted =
504*e038c9c4Sjoerg taint::isTainted(C.getState(), CE->getArg(0), C.getLocationContext());
505*e038c9c4Sjoerg reportBug(IsTainted ? "YES" : "NO", C);
5067330f729Sjoerg }
5077330f729Sjoerg
registerExprInspectionChecker(CheckerManager & Mgr)5087330f729Sjoerg void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
5097330f729Sjoerg Mgr.registerChecker<ExprInspectionChecker>();
5107330f729Sjoerg }
5117330f729Sjoerg
shouldRegisterExprInspectionChecker(const CheckerManager & mgr)512*e038c9c4Sjoerg bool ento::shouldRegisterExprInspectionChecker(const CheckerManager &mgr) {
5137330f729Sjoerg return true;
5147330f729Sjoerg }
515