xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
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