10b57cec5SDimitry Andric //===- BugReporterVisitors.cpp - Helpers for reporting bugs ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file defines a set of BugReporter "visitors" which can be used to
100b57cec5SDimitry Andric //  enhance the diagnostics reported for a bug.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
150b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
160b57cec5SDimitry Andric #include "clang/AST/Decl.h"
170b57cec5SDimitry Andric #include "clang/AST/DeclBase.h"
180b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h"
190b57cec5SDimitry Andric #include "clang/AST/Expr.h"
200b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h"
210b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h"
220b57cec5SDimitry Andric #include "clang/AST/Stmt.h"
230b57cec5SDimitry Andric #include "clang/AST/Type.h"
240b57cec5SDimitry Andric #include "clang/ASTMatchers/ASTMatchFinder.h"
250b57cec5SDimitry Andric #include "clang/Analysis/Analyses/Dominators.h"
260b57cec5SDimitry Andric #include "clang/Analysis/AnalysisDeclContext.h"
270b57cec5SDimitry Andric #include "clang/Analysis/CFG.h"
280b57cec5SDimitry Andric #include "clang/Analysis/CFGStmtMap.h"
29a7dea167SDimitry Andric #include "clang/Analysis/PathDiagnostic.h"
300b57cec5SDimitry Andric #include "clang/Analysis/ProgramPoint.h"
310b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h"
320b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
330b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h"
340b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
350b57cec5SDimitry Andric #include "clang/Lex/Lexer.h"
360b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
370b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
380b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
390b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
400b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
410b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
420b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
430b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
440b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
450b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h"
460b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
470b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
480b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
490b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
500b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
510b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
520b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
530b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
540b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
550b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
560b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
570b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
580b57cec5SDimitry Andric #include <cassert>
590b57cec5SDimitry Andric #include <deque>
600b57cec5SDimitry Andric #include <memory>
61bdd1243dSDimitry Andric #include <optional>
620b57cec5SDimitry Andric #include <string>
630b57cec5SDimitry Andric #include <utility>
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric using namespace clang;
660b57cec5SDimitry Andric using namespace ento;
67fe6060f1SDimitry Andric using namespace bugreporter;
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
700b57cec5SDimitry Andric // Utility functions.
710b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
720b57cec5SDimitry Andric 
peelOffPointerArithmetic(const BinaryOperator * B)730b57cec5SDimitry Andric static const Expr *peelOffPointerArithmetic(const BinaryOperator *B) {
740b57cec5SDimitry Andric   if (B->isAdditiveOp() && B->getType()->isPointerType()) {
750b57cec5SDimitry Andric     if (B->getLHS()->getType()->isPointerType()) {
760b57cec5SDimitry Andric       return B->getLHS();
770b57cec5SDimitry Andric     } else if (B->getRHS()->getType()->isPointerType()) {
780b57cec5SDimitry Andric       return B->getRHS();
790b57cec5SDimitry Andric     }
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric   return nullptr;
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
8481ad6265SDimitry Andric /// \return A subexpression of @c Ex which represents the
8581ad6265SDimitry Andric /// expression-of-interest.
8681ad6265SDimitry Andric static const Expr *peelOffOuterExpr(const Expr *Ex, const ExplodedNode *N);
8781ad6265SDimitry Andric 
880b57cec5SDimitry Andric /// Given that expression S represents a pointer that would be dereferenced,
890b57cec5SDimitry Andric /// try to find a sub-expression from which the pointer came from.
900b57cec5SDimitry Andric /// This is used for tracking down origins of a null or undefined value:
910b57cec5SDimitry Andric /// "this is null because that is null because that is null" etc.
920b57cec5SDimitry Andric /// We wipe away field and element offsets because they merely add offsets.
930b57cec5SDimitry Andric /// We also wipe away all casts except lvalue-to-rvalue casts, because the
940b57cec5SDimitry Andric /// latter represent an actual pointer dereference; however, we remove
950b57cec5SDimitry Andric /// the final lvalue-to-rvalue cast before returning from this function
960b57cec5SDimitry Andric /// because it demonstrates more clearly from where the pointer rvalue was
970b57cec5SDimitry Andric /// loaded. Examples:
980b57cec5SDimitry Andric ///   x->y.z      ==>  x (lvalue)
990b57cec5SDimitry Andric ///   foo()->y.z  ==>  foo() (rvalue)
getDerefExpr(const Stmt * S)1000b57cec5SDimitry Andric const Expr *bugreporter::getDerefExpr(const Stmt *S) {
1010b57cec5SDimitry Andric   const auto *E = dyn_cast<Expr>(S);
1020b57cec5SDimitry Andric   if (!E)
1030b57cec5SDimitry Andric     return nullptr;
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   while (true) {
1060b57cec5SDimitry Andric     if (const auto *CE = dyn_cast<CastExpr>(E)) {
1070b57cec5SDimitry Andric       if (CE->getCastKind() == CK_LValueToRValue) {
1080b57cec5SDimitry Andric         // This cast represents the load we're looking for.
1090b57cec5SDimitry Andric         break;
1100b57cec5SDimitry Andric       }
1110b57cec5SDimitry Andric       E = CE->getSubExpr();
1120b57cec5SDimitry Andric     } else if (const auto *B = dyn_cast<BinaryOperator>(E)) {
1130b57cec5SDimitry Andric       // Pointer arithmetic: '*(x + 2)' -> 'x') etc.
1140b57cec5SDimitry Andric       if (const Expr *Inner = peelOffPointerArithmetic(B)) {
1150b57cec5SDimitry Andric         E = Inner;
1160b57cec5SDimitry Andric       } else {
1170b57cec5SDimitry Andric         // Probably more arithmetic can be pattern-matched here,
1180b57cec5SDimitry Andric         // but for now give up.
1190b57cec5SDimitry Andric         break;
1200b57cec5SDimitry Andric       }
1210b57cec5SDimitry Andric     } else if (const auto *U = dyn_cast<UnaryOperator>(E)) {
1220b57cec5SDimitry Andric       if (U->getOpcode() == UO_Deref || U->getOpcode() == UO_AddrOf ||
1230b57cec5SDimitry Andric           (U->isIncrementDecrementOp() && U->getType()->isPointerType())) {
1240b57cec5SDimitry Andric         // Operators '*' and '&' don't actually mean anything.
1250b57cec5SDimitry Andric         // We look at casts instead.
1260b57cec5SDimitry Andric         E = U->getSubExpr();
1270b57cec5SDimitry Andric       } else {
1280b57cec5SDimitry Andric         // Probably more arithmetic can be pattern-matched here,
1290b57cec5SDimitry Andric         // but for now give up.
1300b57cec5SDimitry Andric         break;
1310b57cec5SDimitry Andric       }
1320b57cec5SDimitry Andric     }
1330b57cec5SDimitry Andric     // Pattern match for a few useful cases: a[0], p->f, *p etc.
1340b57cec5SDimitry Andric     else if (const auto *ME = dyn_cast<MemberExpr>(E)) {
1355f757f3fSDimitry Andric       // This handles the case when the dereferencing of a member reference
1365f757f3fSDimitry Andric       // happens. This is needed, because the AST for dereferencing a
1375f757f3fSDimitry Andric       // member reference looks like the following:
1385f757f3fSDimitry Andric       // |-MemberExpr
1395f757f3fSDimitry Andric       //  `-DeclRefExpr
1405f757f3fSDimitry Andric       // Without this special case the notes would refer to the whole object
1415f757f3fSDimitry Andric       // (struct, class or union variable) instead of just the relevant member.
1425f757f3fSDimitry Andric 
1435f757f3fSDimitry Andric       if (ME->getMemberDecl()->getType()->isReferenceType())
1445f757f3fSDimitry Andric         break;
1450b57cec5SDimitry Andric       E = ME->getBase();
1460b57cec5SDimitry Andric     } else if (const auto *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
1470b57cec5SDimitry Andric       E = IvarRef->getBase();
1480b57cec5SDimitry Andric     } else if (const auto *AE = dyn_cast<ArraySubscriptExpr>(E)) {
1490b57cec5SDimitry Andric       E = AE->getBase();
1500b57cec5SDimitry Andric     } else if (const auto *PE = dyn_cast<ParenExpr>(E)) {
1510b57cec5SDimitry Andric       E = PE->getSubExpr();
1520b57cec5SDimitry Andric     } else if (const auto *FE = dyn_cast<FullExpr>(E)) {
1530b57cec5SDimitry Andric       E = FE->getSubExpr();
1540b57cec5SDimitry Andric     } else {
1550b57cec5SDimitry Andric       // Other arbitrary stuff.
1560b57cec5SDimitry Andric       break;
1570b57cec5SDimitry Andric     }
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   // Special case: remove the final lvalue-to-rvalue cast, but do not recurse
1610b57cec5SDimitry Andric   // deeper into the sub-expression. This way we return the lvalue from which
1620b57cec5SDimitry Andric   // our pointer rvalue was loaded.
1630b57cec5SDimitry Andric   if (const auto *CE = dyn_cast<ImplicitCastExpr>(E))
1640b57cec5SDimitry Andric     if (CE->getCastKind() == CK_LValueToRValue)
1650b57cec5SDimitry Andric       E = CE->getSubExpr();
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric   return E;
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
getVarDeclForExpression(const Expr * E)1705f757f3fSDimitry Andric static const VarDecl *getVarDeclForExpression(const Expr *E) {
1715f757f3fSDimitry Andric   if (const auto *DR = dyn_cast<DeclRefExpr>(E))
1725f757f3fSDimitry Andric     return dyn_cast<VarDecl>(DR->getDecl());
1735f757f3fSDimitry Andric   return nullptr;
1745f757f3fSDimitry Andric }
1755f757f3fSDimitry Andric 
176fe6060f1SDimitry Andric static const MemRegion *
getLocationRegionIfReference(const Expr * E,const ExplodedNode * N,bool LookingForReference=true)177fe6060f1SDimitry Andric getLocationRegionIfReference(const Expr *E, const ExplodedNode *N,
178fe6060f1SDimitry Andric                              bool LookingForReference = true) {
1795f757f3fSDimitry Andric   if (const auto *ME = dyn_cast<MemberExpr>(E)) {
1805f757f3fSDimitry Andric     // This handles null references from FieldRegions, for example:
181fe6060f1SDimitry Andric     //   struct Wrapper { int &ref; };
182fe6060f1SDimitry Andric     //   Wrapper w = { *(int *)0 };
183fe6060f1SDimitry Andric     //   w.ref = 1;
1845f757f3fSDimitry Andric     const Expr *Base = ME->getBase();
1855f757f3fSDimitry Andric     const VarDecl *VD = getVarDeclForExpression(Base);
1865f757f3fSDimitry Andric     if (!VD)
187fe6060f1SDimitry Andric       return nullptr;
1885f757f3fSDimitry Andric 
1895f757f3fSDimitry Andric     const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
1905f757f3fSDimitry Andric     if (!FD)
1915f757f3fSDimitry Andric       return nullptr;
1925f757f3fSDimitry Andric 
1935f757f3fSDimitry Andric     if (FD->getType()->isReferenceType()) {
1945f757f3fSDimitry Andric       SVal StructSVal = N->getState()->getLValue(VD, N->getLocationContext());
1955f757f3fSDimitry Andric       return N->getState()->getLValue(FD, StructSVal).getAsRegion();
1965f757f3fSDimitry Andric     }
1975f757f3fSDimitry Andric     return nullptr;
1985f757f3fSDimitry Andric   }
1995f757f3fSDimitry Andric 
2005f757f3fSDimitry Andric   const VarDecl *VD = getVarDeclForExpression(E);
2015f757f3fSDimitry Andric   if (!VD)
2025f757f3fSDimitry Andric     return nullptr;
2035f757f3fSDimitry Andric   if (LookingForReference && !VD->getType()->isReferenceType())
2045f757f3fSDimitry Andric     return nullptr;
2055f757f3fSDimitry Andric   return N->getState()->getLValue(VD, N->getLocationContext()).getAsRegion();
206fe6060f1SDimitry Andric }
207fe6060f1SDimitry Andric 
2080b57cec5SDimitry Andric /// Comparing internal representations of symbolic values (via
2090b57cec5SDimitry Andric /// SVal::operator==()) is a valid way to check if the value was updated,
2100b57cec5SDimitry Andric /// unless it's a LazyCompoundVal that may have a different internal
2110b57cec5SDimitry Andric /// representation every time it is loaded from the state. In this function we
2120b57cec5SDimitry Andric /// do an approximate comparison for lazy compound values, checking that they
2130b57cec5SDimitry Andric /// are the immediate snapshots of the tracked region's bindings within the
2140b57cec5SDimitry Andric /// node's respective states but not really checking that these snapshots
2150b57cec5SDimitry Andric /// actually contain the same set of bindings.
hasVisibleUpdate(const ExplodedNode * LeftNode,SVal LeftVal,const ExplodedNode * RightNode,SVal RightVal)2160b57cec5SDimitry Andric static bool hasVisibleUpdate(const ExplodedNode *LeftNode, SVal LeftVal,
2170b57cec5SDimitry Andric                              const ExplodedNode *RightNode, SVal RightVal) {
2180b57cec5SDimitry Andric   if (LeftVal == RightVal)
2190b57cec5SDimitry Andric     return true;
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   const auto LLCV = LeftVal.getAs<nonloc::LazyCompoundVal>();
2220b57cec5SDimitry Andric   if (!LLCV)
2230b57cec5SDimitry Andric     return false;
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric   const auto RLCV = RightVal.getAs<nonloc::LazyCompoundVal>();
2260b57cec5SDimitry Andric   if (!RLCV)
2270b57cec5SDimitry Andric     return false;
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   return LLCV->getRegion() == RLCV->getRegion() &&
2300b57cec5SDimitry Andric     LLCV->getStore() == LeftNode->getState()->getStore() &&
2310b57cec5SDimitry Andric     RLCV->getStore() == RightNode->getState()->getStore();
2320b57cec5SDimitry Andric }
2330b57cec5SDimitry Andric 
getSValForVar(const Expr * CondVarExpr,const ExplodedNode * N)234bdd1243dSDimitry Andric static std::optional<SVal> getSValForVar(const Expr *CondVarExpr,
235a7dea167SDimitry Andric                                          const ExplodedNode *N) {
2360b57cec5SDimitry Andric   ProgramStateRef State = N->getState();
2370b57cec5SDimitry Andric   const LocationContext *LCtx = N->getLocationContext();
2380b57cec5SDimitry Andric 
239a7dea167SDimitry Andric   assert(CondVarExpr);
240a7dea167SDimitry Andric   CondVarExpr = CondVarExpr->IgnoreImpCasts();
241a7dea167SDimitry Andric 
2420b57cec5SDimitry Andric   // The declaration of the value may rely on a pointer so take its l-value.
243a7dea167SDimitry Andric   // FIXME: As seen in VisitCommonDeclRefExpr, sometimes DeclRefExpr may
244a7dea167SDimitry Andric   // evaluate to a FieldRegion when it refers to a declaration of a lambda
245a7dea167SDimitry Andric   // capture variable. We most likely need to duplicate that logic here.
246a7dea167SDimitry Andric   if (const auto *DRE = dyn_cast<DeclRefExpr>(CondVarExpr))
247a7dea167SDimitry Andric     if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
248a7dea167SDimitry Andric       return State->getSVal(State->getLValue(VD, LCtx));
249a7dea167SDimitry Andric 
250a7dea167SDimitry Andric   if (const auto *ME = dyn_cast<MemberExpr>(CondVarExpr))
251a7dea167SDimitry Andric     if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
252a7dea167SDimitry Andric       if (auto FieldL = State->getSVal(ME, LCtx).getAs<Loc>())
253a7dea167SDimitry Andric         return State->getRawSVal(*FieldL, FD->getType());
254a7dea167SDimitry Andric 
255bdd1243dSDimitry Andric   return std::nullopt;
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric 
258bdd1243dSDimitry Andric static std::optional<const llvm::APSInt *>
getConcreteIntegerValue(const Expr * CondVarExpr,const ExplodedNode * N)259a7dea167SDimitry Andric getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N) {
260a7dea167SDimitry Andric 
261bdd1243dSDimitry Andric   if (std::optional<SVal> V = getSValForVar(CondVarExpr, N))
262a7dea167SDimitry Andric     if (auto CI = V->getAs<nonloc::ConcreteInt>())
263a7dea167SDimitry Andric       return &CI->getValue();
264bdd1243dSDimitry Andric   return std::nullopt;
265a7dea167SDimitry Andric }
266a7dea167SDimitry Andric 
isVarAnInterestingCondition(const Expr * CondVarExpr,const ExplodedNode * N,const PathSensitiveBugReport * B)267a7dea167SDimitry Andric static bool isVarAnInterestingCondition(const Expr *CondVarExpr,
268a7dea167SDimitry Andric                                         const ExplodedNode *N,
269a7dea167SDimitry Andric                                         const PathSensitiveBugReport *B) {
270a7dea167SDimitry Andric   // Even if this condition is marked as interesting, it isn't *that*
271a7dea167SDimitry Andric   // interesting if it didn't happen in a nested stackframe, the user could just
272a7dea167SDimitry Andric   // follow the arrows.
273a7dea167SDimitry Andric   if (!B->getErrorNode()->getStackFrame()->isParentOf(N->getStackFrame()))
274a7dea167SDimitry Andric     return false;
275a7dea167SDimitry Andric 
276bdd1243dSDimitry Andric   if (std::optional<SVal> V = getSValForVar(CondVarExpr, N))
277bdd1243dSDimitry Andric     if (std::optional<bugreporter::TrackingKind> K =
278bdd1243dSDimitry Andric             B->getInterestingnessKind(*V))
279a7dea167SDimitry Andric       return *K == bugreporter::TrackingKind::Condition;
280a7dea167SDimitry Andric 
281a7dea167SDimitry Andric   return false;
282a7dea167SDimitry Andric }
283a7dea167SDimitry Andric 
isInterestingExpr(const Expr * E,const ExplodedNode * N,const PathSensitiveBugReport * B)284a7dea167SDimitry Andric static bool isInterestingExpr(const Expr *E, const ExplodedNode *N,
285a7dea167SDimitry Andric                               const PathSensitiveBugReport *B) {
286bdd1243dSDimitry Andric   if (std::optional<SVal> V = getSValForVar(E, N))
28781ad6265SDimitry Andric     return B->getInterestingnessKind(*V).has_value();
288a7dea167SDimitry Andric   return false;
2890b57cec5SDimitry Andric }
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric /// \return name of the macro inside the location \p Loc.
getMacroName(SourceLocation Loc,BugReporterContext & BRC)2920b57cec5SDimitry Andric static StringRef getMacroName(SourceLocation Loc,
2930b57cec5SDimitry Andric     BugReporterContext &BRC) {
2940b57cec5SDimitry Andric   return Lexer::getImmediateMacroName(
2950b57cec5SDimitry Andric       Loc,
2960b57cec5SDimitry Andric       BRC.getSourceManager(),
2970b57cec5SDimitry Andric       BRC.getASTContext().getLangOpts());
2980b57cec5SDimitry Andric }
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric /// \return Whether given spelling location corresponds to an expansion
3010b57cec5SDimitry Andric /// of a function-like macro.
isFunctionMacroExpansion(SourceLocation Loc,const SourceManager & SM)3020b57cec5SDimitry Andric static bool isFunctionMacroExpansion(SourceLocation Loc,
3030b57cec5SDimitry Andric                                 const SourceManager &SM) {
3040b57cec5SDimitry Andric   if (!Loc.isMacroID())
3050b57cec5SDimitry Andric     return false;
3060b57cec5SDimitry Andric   while (SM.isMacroArgExpansion(Loc))
3070b57cec5SDimitry Andric     Loc = SM.getImmediateExpansionRange(Loc).getBegin();
3080b57cec5SDimitry Andric   std::pair<FileID, unsigned> TLInfo = SM.getDecomposedLoc(Loc);
3090b57cec5SDimitry Andric   SrcMgr::SLocEntry SE = SM.getSLocEntry(TLInfo.first);
3100b57cec5SDimitry Andric   const SrcMgr::ExpansionInfo &EInfo = SE.getExpansion();
3110b57cec5SDimitry Andric   return EInfo.isFunctionMacroExpansion();
3120b57cec5SDimitry Andric }
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric /// \return Whether \c RegionOfInterest was modified at \p N,
3150b57cec5SDimitry Andric /// where \p ValueAfter is \c RegionOfInterest's value at the end of the
3160b57cec5SDimitry Andric /// stack frame.
wasRegionOfInterestModifiedAt(const SubRegion * RegionOfInterest,const ExplodedNode * N,SVal ValueAfter)3170b57cec5SDimitry Andric static bool wasRegionOfInterestModifiedAt(const SubRegion *RegionOfInterest,
3180b57cec5SDimitry Andric                                           const ExplodedNode *N,
3190b57cec5SDimitry Andric                                           SVal ValueAfter) {
3200b57cec5SDimitry Andric   ProgramStateRef State = N->getState();
3210b57cec5SDimitry Andric   ProgramStateManager &Mgr = N->getState()->getStateManager();
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   if (!N->getLocationAs<PostStore>() && !N->getLocationAs<PostInitializer>() &&
3240b57cec5SDimitry Andric       !N->getLocationAs<PostStmt>())
3250b57cec5SDimitry Andric     return false;
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric   // Writing into region of interest.
3280b57cec5SDimitry Andric   if (auto PS = N->getLocationAs<PostStmt>())
3290b57cec5SDimitry Andric     if (auto *BO = PS->getStmtAs<BinaryOperator>())
3300b57cec5SDimitry Andric       if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(
3310b57cec5SDimitry Andric                                       N->getSVal(BO->getLHS()).getAsRegion()))
3320b57cec5SDimitry Andric         return true;
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric   // SVal after the state is possibly different.
3350b57cec5SDimitry Andric   SVal ValueAtN = N->getState()->getSVal(RegionOfInterest);
3360b57cec5SDimitry Andric   if (!Mgr.getSValBuilder()
3370b57cec5SDimitry Andric            .areEqual(State, ValueAtN, ValueAfter)
3380b57cec5SDimitry Andric            .isConstrainedTrue() &&
3390b57cec5SDimitry Andric       (!ValueAtN.isUndef() || !ValueAfter.isUndef()))
3400b57cec5SDimitry Andric     return true;
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric   return false;
3430b57cec5SDimitry Andric }
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3460b57cec5SDimitry Andric // Implementation of BugReporterVisitor.
3470b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3480b57cec5SDimitry Andric 
getEndPath(BugReporterContext &,const ExplodedNode *,PathSensitiveBugReport &)349a7dea167SDimitry Andric PathDiagnosticPieceRef BugReporterVisitor::getEndPath(BugReporterContext &,
350a7dea167SDimitry Andric                                                       const ExplodedNode *,
351a7dea167SDimitry Andric                                                       PathSensitiveBugReport &) {
3520b57cec5SDimitry Andric   return nullptr;
3530b57cec5SDimitry Andric }
3540b57cec5SDimitry Andric 
finalizeVisitor(BugReporterContext &,const ExplodedNode *,PathSensitiveBugReport &)355a7dea167SDimitry Andric void BugReporterVisitor::finalizeVisitor(BugReporterContext &,
356a7dea167SDimitry Andric                                          const ExplodedNode *,
357a7dea167SDimitry Andric                                          PathSensitiveBugReport &) {}
3580b57cec5SDimitry Andric 
359a7dea167SDimitry Andric PathDiagnosticPieceRef
getDefaultEndPath(const BugReporterContext & BRC,const ExplodedNode * EndPathNode,const PathSensitiveBugReport & BR)360a7dea167SDimitry Andric BugReporterVisitor::getDefaultEndPath(const BugReporterContext &BRC,
361a7dea167SDimitry Andric                                       const ExplodedNode *EndPathNode,
362a7dea167SDimitry Andric                                       const PathSensitiveBugReport &BR) {
363a7dea167SDimitry Andric   PathDiagnosticLocation L = BR.getLocation();
3640b57cec5SDimitry Andric   const auto &Ranges = BR.getRanges();
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric   // Only add the statement itself as a range if we didn't specify any
3670b57cec5SDimitry Andric   // special ranges for this report.
3680b57cec5SDimitry Andric   auto P = std::make_shared<PathDiagnosticEventPiece>(
3690b57cec5SDimitry Andric       L, BR.getDescription(), Ranges.begin() == Ranges.end());
3700b57cec5SDimitry Andric   for (SourceRange Range : Ranges)
3710b57cec5SDimitry Andric     P->addRange(Range);
3720b57cec5SDimitry Andric 
3730b57cec5SDimitry Andric   return P;
3740b57cec5SDimitry Andric }
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
377349cc55cSDimitry Andric // Implementation of NoStateChangeFuncVisitor.
378349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
379349cc55cSDimitry Andric 
isModifiedInFrame(const ExplodedNode * N)380349cc55cSDimitry Andric bool NoStateChangeFuncVisitor::isModifiedInFrame(const ExplodedNode *N) {
381349cc55cSDimitry Andric   const LocationContext *Ctx = N->getLocationContext();
382349cc55cSDimitry Andric   const StackFrameContext *SCtx = Ctx->getStackFrame();
383349cc55cSDimitry Andric   if (!FramesModifyingCalculated.count(SCtx))
384349cc55cSDimitry Andric     findModifyingFrames(N);
385349cc55cSDimitry Andric   return FramesModifying.count(SCtx);
386349cc55cSDimitry Andric }
387349cc55cSDimitry Andric 
markFrameAsModifying(const StackFrameContext * SCtx)388349cc55cSDimitry Andric void NoStateChangeFuncVisitor::markFrameAsModifying(
389349cc55cSDimitry Andric     const StackFrameContext *SCtx) {
390349cc55cSDimitry Andric   while (!SCtx->inTopFrame()) {
391349cc55cSDimitry Andric     auto p = FramesModifying.insert(SCtx);
392349cc55cSDimitry Andric     if (!p.second)
393349cc55cSDimitry Andric       break; // Frame and all its parents already inserted.
394349cc55cSDimitry Andric 
395349cc55cSDimitry Andric     SCtx = SCtx->getParent()->getStackFrame();
396349cc55cSDimitry Andric   }
397349cc55cSDimitry Andric }
398349cc55cSDimitry Andric 
getMatchingCallExitEnd(const ExplodedNode * N)399349cc55cSDimitry Andric static const ExplodedNode *getMatchingCallExitEnd(const ExplodedNode *N) {
400349cc55cSDimitry Andric   assert(N->getLocationAs<CallEnter>());
401349cc55cSDimitry Andric   // The stackframe of the callee is only found in the nodes succeeding
402349cc55cSDimitry Andric   // the CallEnter node. CallEnter's stack frame refers to the caller.
403349cc55cSDimitry Andric   const StackFrameContext *OrigSCtx = N->getFirstSucc()->getStackFrame();
404349cc55cSDimitry Andric 
405349cc55cSDimitry Andric   // Similarly, the nodes preceding CallExitEnd refer to the callee's stack
406349cc55cSDimitry Andric   // frame.
407349cc55cSDimitry Andric   auto IsMatchingCallExitEnd = [OrigSCtx](const ExplodedNode *N) {
408349cc55cSDimitry Andric     return N->getLocationAs<CallExitEnd>() &&
409349cc55cSDimitry Andric            OrigSCtx == N->getFirstPred()->getStackFrame();
410349cc55cSDimitry Andric   };
411349cc55cSDimitry Andric   while (N && !IsMatchingCallExitEnd(N)) {
412349cc55cSDimitry Andric     assert(N->succ_size() <= 1 &&
413349cc55cSDimitry Andric            "This function is to be used on the trimmed ExplodedGraph!");
414349cc55cSDimitry Andric     N = N->getFirstSucc();
415349cc55cSDimitry Andric   }
416349cc55cSDimitry Andric   return N;
417349cc55cSDimitry Andric }
418349cc55cSDimitry Andric 
findModifyingFrames(const ExplodedNode * const CallExitBeginN)419349cc55cSDimitry Andric void NoStateChangeFuncVisitor::findModifyingFrames(
420349cc55cSDimitry Andric     const ExplodedNode *const CallExitBeginN) {
421349cc55cSDimitry Andric 
422349cc55cSDimitry Andric   assert(CallExitBeginN->getLocationAs<CallExitBegin>());
423349cc55cSDimitry Andric 
424349cc55cSDimitry Andric   const StackFrameContext *const OriginalSCtx =
425349cc55cSDimitry Andric       CallExitBeginN->getLocationContext()->getStackFrame();
426349cc55cSDimitry Andric 
427349cc55cSDimitry Andric   const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
428349cc55cSDimitry Andric   const StackFrameContext *CurrentSCtx = OriginalSCtx;
429349cc55cSDimitry Andric 
430349cc55cSDimitry Andric   for (const ExplodedNode *CurrN = CallExitBeginN; CurrN;
431349cc55cSDimitry Andric        CurrN = CurrN->getFirstPred()) {
432349cc55cSDimitry Andric     // Found a new inlined call.
433349cc55cSDimitry Andric     if (CurrN->getLocationAs<CallExitBegin>()) {
434349cc55cSDimitry Andric       CurrCallExitBeginN = CurrN;
435349cc55cSDimitry Andric       CurrentSCtx = CurrN->getStackFrame();
436349cc55cSDimitry Andric       FramesModifyingCalculated.insert(CurrentSCtx);
437349cc55cSDimitry Andric       // We won't see a change in between two identical exploded nodes: skip.
438349cc55cSDimitry Andric       continue;
439349cc55cSDimitry Andric     }
440349cc55cSDimitry Andric 
441349cc55cSDimitry Andric     if (auto CE = CurrN->getLocationAs<CallEnter>()) {
442349cc55cSDimitry Andric       if (const ExplodedNode *CallExitEndN = getMatchingCallExitEnd(CurrN))
443349cc55cSDimitry Andric         if (wasModifiedInFunction(CurrN, CallExitEndN))
444349cc55cSDimitry Andric           markFrameAsModifying(CurrentSCtx);
445349cc55cSDimitry Andric 
446349cc55cSDimitry Andric       // We exited this inlined call, lets actualize the stack frame.
447349cc55cSDimitry Andric       CurrentSCtx = CurrN->getStackFrame();
448349cc55cSDimitry Andric 
449349cc55cSDimitry Andric       // Stop calculating at the current function, but always regard it as
450349cc55cSDimitry Andric       // modifying, so we can avoid notes like this:
451349cc55cSDimitry Andric       //   void f(Foo &F) {
452349cc55cSDimitry Andric       //     F.field = 0; // note: 0 assigned to 'F.field'
453349cc55cSDimitry Andric       //                  // note: returning without writing to 'F.field'
454349cc55cSDimitry Andric       //   }
455349cc55cSDimitry Andric       if (CE->getCalleeContext() == OriginalSCtx) {
456349cc55cSDimitry Andric         markFrameAsModifying(CurrentSCtx);
457349cc55cSDimitry Andric         break;
458349cc55cSDimitry Andric       }
459349cc55cSDimitry Andric     }
460349cc55cSDimitry Andric 
461349cc55cSDimitry Andric     if (wasModifiedBeforeCallExit(CurrN, CurrCallExitBeginN))
462349cc55cSDimitry Andric       markFrameAsModifying(CurrentSCtx);
463349cc55cSDimitry Andric   }
464349cc55cSDimitry Andric }
465349cc55cSDimitry Andric 
VisitNode(const ExplodedNode * N,BugReporterContext & BR,PathSensitiveBugReport & R)466349cc55cSDimitry Andric PathDiagnosticPieceRef NoStateChangeFuncVisitor::VisitNode(
467349cc55cSDimitry Andric     const ExplodedNode *N, BugReporterContext &BR, PathSensitiveBugReport &R) {
468349cc55cSDimitry Andric 
469349cc55cSDimitry Andric   const LocationContext *Ctx = N->getLocationContext();
470349cc55cSDimitry Andric   const StackFrameContext *SCtx = Ctx->getStackFrame();
471349cc55cSDimitry Andric   ProgramStateRef State = N->getState();
472349cc55cSDimitry Andric   auto CallExitLoc = N->getLocationAs<CallExitBegin>();
473349cc55cSDimitry Andric 
474349cc55cSDimitry Andric   // No diagnostic if region was modified inside the frame.
475349cc55cSDimitry Andric   if (!CallExitLoc || isModifiedInFrame(N))
476349cc55cSDimitry Andric     return nullptr;
477349cc55cSDimitry Andric 
478349cc55cSDimitry Andric   CallEventRef<> Call =
479349cc55cSDimitry Andric       BR.getStateManager().getCallEventManager().getCaller(SCtx, State);
480349cc55cSDimitry Andric 
481349cc55cSDimitry Andric   // Optimistically suppress uninitialized value bugs that result
482349cc55cSDimitry Andric   // from system headers having a chance to initialize the value
483349cc55cSDimitry Andric   // but failing to do so. It's too unlikely a system header's fault.
484349cc55cSDimitry Andric   // It's much more likely a situation in which the function has a failure
485349cc55cSDimitry Andric   // mode that the user decided not to check. If we want to hunt such
486349cc55cSDimitry Andric   // omitted checks, we should provide an explicit function-specific note
487349cc55cSDimitry Andric   // describing the precondition under which the function isn't supposed to
488349cc55cSDimitry Andric   // initialize its out-parameter, and additionally check that such
489349cc55cSDimitry Andric   // precondition can actually be fulfilled on the current path.
490349cc55cSDimitry Andric   if (Call->isInSystemHeader()) {
491349cc55cSDimitry Andric     // We make an exception for system header functions that have no branches.
492349cc55cSDimitry Andric     // Such functions unconditionally fail to initialize the variable.
493349cc55cSDimitry Andric     // If they call other functions that have more paths within them,
494349cc55cSDimitry Andric     // this suppression would still apply when we visit these inner functions.
495349cc55cSDimitry Andric     // One common example of a standard function that doesn't ever initialize
496349cc55cSDimitry Andric     // its out parameter is operator placement new; it's up to the follow-up
497349cc55cSDimitry Andric     // constructor (if any) to initialize the memory.
498349cc55cSDimitry Andric     if (!N->getStackFrame()->getCFG()->isLinear()) {
499349cc55cSDimitry Andric       static int i = 0;
500349cc55cSDimitry Andric       R.markInvalid(&i, nullptr);
501349cc55cSDimitry Andric     }
502349cc55cSDimitry Andric     return nullptr;
503349cc55cSDimitry Andric   }
504349cc55cSDimitry Andric 
505349cc55cSDimitry Andric   if (const auto *MC = dyn_cast<ObjCMethodCall>(Call)) {
506349cc55cSDimitry Andric     // If we failed to construct a piece for self, we still want to check
507349cc55cSDimitry Andric     // whether the entity of interest is in a parameter.
508349cc55cSDimitry Andric     if (PathDiagnosticPieceRef Piece = maybeEmitNoteForObjCSelf(R, *MC, N))
509349cc55cSDimitry Andric       return Piece;
510349cc55cSDimitry Andric   }
511349cc55cSDimitry Andric 
512349cc55cSDimitry Andric   if (const auto *CCall = dyn_cast<CXXConstructorCall>(Call)) {
513349cc55cSDimitry Andric     // Do not generate diagnostics for not modified parameters in
514349cc55cSDimitry Andric     // constructors.
515349cc55cSDimitry Andric     return maybeEmitNoteForCXXThis(R, *CCall, N);
516349cc55cSDimitry Andric   }
517349cc55cSDimitry Andric 
518349cc55cSDimitry Andric   return maybeEmitNoteForParameters(R, *Call, N);
519349cc55cSDimitry Andric }
520349cc55cSDimitry Andric 
521349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
5220b57cec5SDimitry Andric // Implementation of NoStoreFuncVisitor.
5230b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5240b57cec5SDimitry Andric 
5250b57cec5SDimitry Andric namespace {
5260b57cec5SDimitry Andric /// Put a diagnostic on return statement of all inlined functions
5270b57cec5SDimitry Andric /// for which  the region of interest \p RegionOfInterest was passed into,
5280b57cec5SDimitry Andric /// but not written inside, and it has caused an undefined read or a null
5290b57cec5SDimitry Andric /// pointer dereference outside.
530349cc55cSDimitry Andric class NoStoreFuncVisitor final : public NoStateChangeFuncVisitor {
5310b57cec5SDimitry Andric   const SubRegion *RegionOfInterest;
5320b57cec5SDimitry Andric   MemRegionManager &MmrMgr;
5330b57cec5SDimitry Andric   const SourceManager &SM;
5340b57cec5SDimitry Andric   const PrintingPolicy &PP;
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric   /// Recursion limit for dereferencing fields when looking for the
5370b57cec5SDimitry Andric   /// region of interest.
5380b57cec5SDimitry Andric   /// The limit of two indicates that we will dereference fields only once.
5390b57cec5SDimitry Andric   static const unsigned DEREFERENCE_LIMIT = 2;
5400b57cec5SDimitry Andric 
5410b57cec5SDimitry Andric   using RegionVector = SmallVector<const MemRegion *, 5>;
5420b57cec5SDimitry Andric 
5430b57cec5SDimitry Andric public:
NoStoreFuncVisitor(const SubRegion * R,bugreporter::TrackingKind TKind)544a7dea167SDimitry Andric   NoStoreFuncVisitor(const SubRegion *R, bugreporter::TrackingKind TKind)
545349cc55cSDimitry Andric       : NoStateChangeFuncVisitor(TKind), RegionOfInterest(R),
546349cc55cSDimitry Andric         MmrMgr(R->getMemRegionManager()),
5470b57cec5SDimitry Andric         SM(MmrMgr.getContext().getSourceManager()),
548349cc55cSDimitry Andric         PP(MmrMgr.getContext().getPrintingPolicy()) {}
5490b57cec5SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const5500b57cec5SDimitry Andric   void Profile(llvm::FoldingSetNodeID &ID) const override {
5510b57cec5SDimitry Andric     static int Tag = 0;
5520b57cec5SDimitry Andric     ID.AddPointer(&Tag);
5530b57cec5SDimitry Andric     ID.AddPointer(RegionOfInterest);
5540b57cec5SDimitry Andric   }
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric private:
557349cc55cSDimitry Andric   /// \return Whether \c RegionOfInterest was modified at \p CurrN compared to
558349cc55cSDimitry Andric   /// the value it holds in \p CallExitBeginN.
559972a253aSDimitry Andric   bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
560349cc55cSDimitry Andric                                  const ExplodedNode *CallExitBeginN) override;
561349cc55cSDimitry Andric 
5620b57cec5SDimitry Andric   /// Attempts to find the region of interest in a given record decl,
5630b57cec5SDimitry Andric   /// by either following the base classes or fields.
5640b57cec5SDimitry Andric   /// Dereferences fields up to a given recursion limit.
5650b57cec5SDimitry Andric   /// Note that \p Vec is passed by value, leading to quadratic copying cost,
5660b57cec5SDimitry Andric   /// but it's OK in practice since its length is limited to DEREFERENCE_LIMIT.
567bdd1243dSDimitry Andric   /// \return A chain fields leading to the region of interest or std::nullopt.
568bdd1243dSDimitry Andric   const std::optional<RegionVector>
5690b57cec5SDimitry Andric   findRegionOfInterestInRecord(const RecordDecl *RD, ProgramStateRef State,
5700b57cec5SDimitry Andric                                const MemRegion *R, const RegionVector &Vec = {},
5710b57cec5SDimitry Andric                                int depth = 0);
5720b57cec5SDimitry Andric 
573349cc55cSDimitry Andric   // Region of interest corresponds to an IVar, exiting a method
574349cc55cSDimitry Andric   // which could have written into that IVar, but did not.
575972a253aSDimitry Andric   PathDiagnosticPieceRef maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
576349cc55cSDimitry Andric                                                   const ObjCMethodCall &Call,
577972a253aSDimitry Andric                                                   const ExplodedNode *N) final;
5780b57cec5SDimitry Andric 
579972a253aSDimitry Andric   PathDiagnosticPieceRef maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
580349cc55cSDimitry Andric                                                  const CXXConstructorCall &Call,
581972a253aSDimitry Andric                                                  const ExplodedNode *N) final;
582349cc55cSDimitry Andric 
583972a253aSDimitry Andric   PathDiagnosticPieceRef
584349cc55cSDimitry Andric   maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
585972a253aSDimitry Andric                              const ExplodedNode *N) final;
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric   /// Consume the information on the no-store stack frame in order to
5880b57cec5SDimitry Andric   /// either emit a note or suppress the report enirely.
5890b57cec5SDimitry Andric   /// \return Diagnostics piece for region not modified in the current function,
5900b57cec5SDimitry Andric   /// if it decides to emit one.
591a7dea167SDimitry Andric   PathDiagnosticPieceRef
592a7dea167SDimitry Andric   maybeEmitNote(PathSensitiveBugReport &R, const CallEvent &Call,
593a7dea167SDimitry Andric                 const ExplodedNode *N, const RegionVector &FieldChain,
594a7dea167SDimitry Andric                 const MemRegion *MatchedRegion, StringRef FirstElement,
595a7dea167SDimitry Andric                 bool FirstIsReferenceType, unsigned IndirectionLevel);
5960b57cec5SDimitry Andric 
597349cc55cSDimitry Andric   bool prettyPrintRegionName(const RegionVector &FieldChain,
5980b57cec5SDimitry Andric                              const MemRegion *MatchedRegion,
599349cc55cSDimitry Andric                              StringRef FirstElement, bool FirstIsReferenceType,
600349cc55cSDimitry Andric                              unsigned IndirectionLevel,
6010b57cec5SDimitry Andric                              llvm::raw_svector_ostream &os);
6020b57cec5SDimitry Andric 
603349cc55cSDimitry Andric   StringRef prettyPrintFirstElement(StringRef FirstElement,
6040b57cec5SDimitry Andric                                     bool MoreItemsExpected,
6050b57cec5SDimitry Andric                                     int IndirectionLevel,
6060b57cec5SDimitry Andric                                     llvm::raw_svector_ostream &os);
6070b57cec5SDimitry Andric };
608349cc55cSDimitry Andric } // namespace
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric /// \return Whether the method declaration \p Parent
6110b57cec5SDimitry Andric /// syntactically has a binary operation writing into the ivar \p Ivar.
potentiallyWritesIntoIvar(const Decl * Parent,const ObjCIvarDecl * Ivar)6120b57cec5SDimitry Andric static bool potentiallyWritesIntoIvar(const Decl *Parent,
6130b57cec5SDimitry Andric                                       const ObjCIvarDecl *Ivar) {
6140b57cec5SDimitry Andric   using namespace ast_matchers;
6150b57cec5SDimitry Andric   const char *IvarBind = "Ivar";
6160b57cec5SDimitry Andric   if (!Parent || !Parent->hasBody())
6170b57cec5SDimitry Andric     return false;
6180b57cec5SDimitry Andric   StatementMatcher WriteIntoIvarM = binaryOperator(
6190b57cec5SDimitry Andric       hasOperatorName("="),
6200b57cec5SDimitry Andric       hasLHS(ignoringParenImpCasts(
6210b57cec5SDimitry Andric           objcIvarRefExpr(hasDeclaration(equalsNode(Ivar))).bind(IvarBind))));
6220b57cec5SDimitry Andric   StatementMatcher ParentM = stmt(hasDescendant(WriteIntoIvarM));
6230b57cec5SDimitry Andric   auto Matches = match(ParentM, *Parent->getBody(), Parent->getASTContext());
6240b57cec5SDimitry Andric   for (BoundNodes &Match : Matches) {
6250b57cec5SDimitry Andric     auto IvarRef = Match.getNodeAs<ObjCIvarRefExpr>(IvarBind);
6260b57cec5SDimitry Andric     if (IvarRef->isFreeIvar())
6270b57cec5SDimitry Andric       return true;
6280b57cec5SDimitry Andric 
6290b57cec5SDimitry Andric     const Expr *Base = IvarRef->getBase();
6300b57cec5SDimitry Andric     if (const auto *ICE = dyn_cast<ImplicitCastExpr>(Base))
6310b57cec5SDimitry Andric       Base = ICE->getSubExpr();
6320b57cec5SDimitry Andric 
6330b57cec5SDimitry Andric     if (const auto *DRE = dyn_cast<DeclRefExpr>(Base))
6340b57cec5SDimitry Andric       if (const auto *ID = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
6355f757f3fSDimitry Andric         if (ID->getParameterKind() == ImplicitParamKind::ObjCSelf)
6360b57cec5SDimitry Andric           return true;
6370b57cec5SDimitry Andric 
6380b57cec5SDimitry Andric     return false;
6390b57cec5SDimitry Andric   }
6400b57cec5SDimitry Andric   return false;
6410b57cec5SDimitry Andric }
6420b57cec5SDimitry Andric 
6430b57cec5SDimitry Andric /// Attempts to find the region of interest in a given CXX decl,
6440b57cec5SDimitry Andric /// by either following the base classes or fields.
6450b57cec5SDimitry Andric /// Dereferences fields up to a given recursion limit.
6460b57cec5SDimitry Andric /// Note that \p Vec is passed by value, leading to quadratic copying cost,
6470b57cec5SDimitry Andric /// but it's OK in practice since its length is limited to DEREFERENCE_LIMIT.
648bdd1243dSDimitry Andric /// \return A chain fields leading to the region of interest or std::nullopt.
649bdd1243dSDimitry Andric const std::optional<NoStoreFuncVisitor::RegionVector>
findRegionOfInterestInRecord(const RecordDecl * RD,ProgramStateRef State,const MemRegion * R,const NoStoreFuncVisitor::RegionVector & Vec,int depth)6500b57cec5SDimitry Andric NoStoreFuncVisitor::findRegionOfInterestInRecord(
6510b57cec5SDimitry Andric     const RecordDecl *RD, ProgramStateRef State, const MemRegion *R,
6520b57cec5SDimitry Andric     const NoStoreFuncVisitor::RegionVector &Vec /* = {} */,
6530b57cec5SDimitry Andric     int depth /* = 0 */) {
6540b57cec5SDimitry Andric 
6550b57cec5SDimitry Andric   if (depth == DEREFERENCE_LIMIT) // Limit the recursion depth.
656bdd1243dSDimitry Andric     return std::nullopt;
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric   if (const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
6590b57cec5SDimitry Andric     if (!RDX->hasDefinition())
660bdd1243dSDimitry Andric       return std::nullopt;
6610b57cec5SDimitry Andric 
6620b57cec5SDimitry Andric   // Recursively examine the base classes.
6630b57cec5SDimitry Andric   // Note that following base classes does not increase the recursion depth.
6640b57cec5SDimitry Andric   if (const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
665480093f4SDimitry Andric     for (const auto &II : RDX->bases())
6660b57cec5SDimitry Andric       if (const RecordDecl *RRD = II.getType()->getAsRecordDecl())
667bdd1243dSDimitry Andric         if (std::optional<RegionVector> Out =
6680b57cec5SDimitry Andric                 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
6690b57cec5SDimitry Andric           return Out;
6700b57cec5SDimitry Andric 
6710b57cec5SDimitry Andric   for (const FieldDecl *I : RD->fields()) {
6720b57cec5SDimitry Andric     QualType FT = I->getType();
6730b57cec5SDimitry Andric     const FieldRegion *FR = MmrMgr.getFieldRegion(I, cast<SubRegion>(R));
6740b57cec5SDimitry Andric     const SVal V = State->getSVal(FR);
6750b57cec5SDimitry Andric     const MemRegion *VR = V.getAsRegion();
6760b57cec5SDimitry Andric 
6770b57cec5SDimitry Andric     RegionVector VecF = Vec;
6780b57cec5SDimitry Andric     VecF.push_back(FR);
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric     if (RegionOfInterest == VR)
6810b57cec5SDimitry Andric       return VecF;
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric     if (const RecordDecl *RRD = FT->getAsRecordDecl())
6840b57cec5SDimitry Andric       if (auto Out =
6850b57cec5SDimitry Andric               findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))
6860b57cec5SDimitry Andric         return Out;
6870b57cec5SDimitry Andric 
6880b57cec5SDimitry Andric     QualType PT = FT->getPointeeType();
6890b57cec5SDimitry Andric     if (PT.isNull() || PT->isVoidType() || !VR)
6900b57cec5SDimitry Andric       continue;
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric     if (const RecordDecl *RRD = PT->getAsRecordDecl())
693bdd1243dSDimitry Andric       if (std::optional<RegionVector> Out =
6940b57cec5SDimitry Andric               findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
6950b57cec5SDimitry Andric         return Out;
6960b57cec5SDimitry Andric   }
6970b57cec5SDimitry Andric 
698bdd1243dSDimitry Andric   return std::nullopt;
6990b57cec5SDimitry Andric }
7000b57cec5SDimitry Andric 
701a7dea167SDimitry Andric PathDiagnosticPieceRef
maybeEmitNoteForObjCSelf(PathSensitiveBugReport & R,const ObjCMethodCall & Call,const ExplodedNode * N)702349cc55cSDimitry Andric NoStoreFuncVisitor::maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
703349cc55cSDimitry Andric                                              const ObjCMethodCall &Call,
704349cc55cSDimitry Andric                                              const ExplodedNode *N) {
7050b57cec5SDimitry Andric   if (const auto *IvarR = dyn_cast<ObjCIvarRegion>(RegionOfInterest)) {
706349cc55cSDimitry Andric     const MemRegion *SelfRegion = Call.getReceiverSVal().getAsRegion();
7070b57cec5SDimitry Andric     if (RegionOfInterest->isSubRegionOf(SelfRegion) &&
708349cc55cSDimitry Andric         potentiallyWritesIntoIvar(Call.getRuntimeDefinition().getDecl(),
7090b57cec5SDimitry Andric                                   IvarR->getDecl()))
710349cc55cSDimitry Andric       return maybeEmitNote(R, Call, N, {}, SelfRegion, "self",
7110b57cec5SDimitry Andric                            /*FirstIsReferenceType=*/false, 1);
7120b57cec5SDimitry Andric   }
713349cc55cSDimitry Andric   return nullptr;
7140b57cec5SDimitry Andric }
7150b57cec5SDimitry Andric 
716349cc55cSDimitry Andric PathDiagnosticPieceRef
maybeEmitNoteForCXXThis(PathSensitiveBugReport & R,const CXXConstructorCall & Call,const ExplodedNode * N)717349cc55cSDimitry Andric NoStoreFuncVisitor::maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
718349cc55cSDimitry Andric                                             const CXXConstructorCall &Call,
719349cc55cSDimitry Andric                                             const ExplodedNode *N) {
720349cc55cSDimitry Andric   const MemRegion *ThisR = Call.getCXXThisVal().getAsRegion();
721349cc55cSDimitry Andric   if (RegionOfInterest->isSubRegionOf(ThisR) && !Call.getDecl()->isImplicit())
722349cc55cSDimitry Andric     return maybeEmitNote(R, Call, N, {}, ThisR, "this",
7230b57cec5SDimitry Andric                          /*FirstIsReferenceType=*/false, 1);
7240b57cec5SDimitry Andric 
7250b57cec5SDimitry Andric   // Do not generate diagnostics for not modified parameters in
7260b57cec5SDimitry Andric   // constructors.
7270b57cec5SDimitry Andric   return nullptr;
7280b57cec5SDimitry Andric }
7290b57cec5SDimitry Andric 
730349cc55cSDimitry Andric /// \return whether \p Ty points to a const type, or is a const reference.
isPointerToConst(QualType Ty)731349cc55cSDimitry Andric static bool isPointerToConst(QualType Ty) {
732349cc55cSDimitry Andric   return !Ty->getPointeeType().isNull() &&
733349cc55cSDimitry Andric          Ty->getPointeeType().getCanonicalType().isConstQualified();
734349cc55cSDimitry Andric }
735349cc55cSDimitry Andric 
maybeEmitNoteForParameters(PathSensitiveBugReport & R,const CallEvent & Call,const ExplodedNode * N)736349cc55cSDimitry Andric PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNoteForParameters(
737349cc55cSDimitry Andric     PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N) {
738349cc55cSDimitry Andric   ArrayRef<ParmVarDecl *> Parameters = Call.parameters();
739349cc55cSDimitry Andric   for (unsigned I = 0; I < Call.getNumArgs() && I < Parameters.size(); ++I) {
740349cc55cSDimitry Andric     const ParmVarDecl *PVD = Parameters[I];
741349cc55cSDimitry Andric     SVal V = Call.getArgSVal(I);
7420b57cec5SDimitry Andric     bool ParamIsReferenceType = PVD->getType()->isReferenceType();
7430b57cec5SDimitry Andric     std::string ParamName = PVD->getNameAsString();
7440b57cec5SDimitry Andric 
745349cc55cSDimitry Andric     unsigned IndirectionLevel = 1;
7460b57cec5SDimitry Andric     QualType T = PVD->getType();
7470b57cec5SDimitry Andric     while (const MemRegion *MR = V.getAsRegion()) {
7480b57cec5SDimitry Andric       if (RegionOfInterest->isSubRegionOf(MR) && !isPointerToConst(T))
749349cc55cSDimitry Andric         return maybeEmitNote(R, Call, N, {}, MR, ParamName,
7500b57cec5SDimitry Andric                              ParamIsReferenceType, IndirectionLevel);
7510b57cec5SDimitry Andric 
7520b57cec5SDimitry Andric       QualType PT = T->getPointeeType();
7530b57cec5SDimitry Andric       if (PT.isNull() || PT->isVoidType())
7540b57cec5SDimitry Andric         break;
7550b57cec5SDimitry Andric 
756349cc55cSDimitry Andric       ProgramStateRef State = N->getState();
757349cc55cSDimitry Andric 
7580b57cec5SDimitry Andric       if (const RecordDecl *RD = PT->getAsRecordDecl())
759bdd1243dSDimitry Andric         if (std::optional<RegionVector> P =
7600b57cec5SDimitry Andric                 findRegionOfInterestInRecord(RD, State, MR))
761349cc55cSDimitry Andric           return maybeEmitNote(R, Call, N, *P, RegionOfInterest, ParamName,
7620b57cec5SDimitry Andric                                ParamIsReferenceType, IndirectionLevel);
7630b57cec5SDimitry Andric 
7640b57cec5SDimitry Andric       V = State->getSVal(MR, PT);
7650b57cec5SDimitry Andric       T = PT;
7660b57cec5SDimitry Andric       IndirectionLevel++;
7670b57cec5SDimitry Andric     }
7680b57cec5SDimitry Andric   }
7690b57cec5SDimitry Andric 
7700b57cec5SDimitry Andric   return nullptr;
7710b57cec5SDimitry Andric }
7720b57cec5SDimitry Andric 
wasModifiedBeforeCallExit(const ExplodedNode * CurrN,const ExplodedNode * CallExitBeginN)773349cc55cSDimitry Andric bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
774349cc55cSDimitry Andric     const ExplodedNode *CurrN, const ExplodedNode *CallExitBeginN) {
775349cc55cSDimitry Andric   return ::wasRegionOfInterestModifiedAt(
776349cc55cSDimitry Andric       RegionOfInterest, CurrN,
777349cc55cSDimitry Andric       CallExitBeginN->getState()->getSVal(RegionOfInterest));
7780b57cec5SDimitry Andric }
7790b57cec5SDimitry Andric 
780a7dea167SDimitry Andric static llvm::StringLiteral WillBeUsedForACondition =
781a7dea167SDimitry Andric     ", which participates in a condition later";
782a7dea167SDimitry Andric 
maybeEmitNote(PathSensitiveBugReport & R,const CallEvent & Call,const ExplodedNode * N,const RegionVector & FieldChain,const MemRegion * MatchedRegion,StringRef FirstElement,bool FirstIsReferenceType,unsigned IndirectionLevel)783a7dea167SDimitry Andric PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNote(
784a7dea167SDimitry Andric     PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N,
7850b57cec5SDimitry Andric     const RegionVector &FieldChain, const MemRegion *MatchedRegion,
7860b57cec5SDimitry Andric     StringRef FirstElement, bool FirstIsReferenceType,
7870b57cec5SDimitry Andric     unsigned IndirectionLevel) {
7880b57cec5SDimitry Andric 
7890b57cec5SDimitry Andric   PathDiagnosticLocation L =
7900b57cec5SDimitry Andric       PathDiagnosticLocation::create(N->getLocation(), SM);
7910b57cec5SDimitry Andric 
7920b57cec5SDimitry Andric   // For now this shouldn't trigger, but once it does (as we add more
7930b57cec5SDimitry Andric   // functions to the body farm), we'll need to decide if these reports
7940b57cec5SDimitry Andric   // are worth suppressing as well.
7950b57cec5SDimitry Andric   if (!L.hasValidLocation())
7960b57cec5SDimitry Andric     return nullptr;
7970b57cec5SDimitry Andric 
7980b57cec5SDimitry Andric   SmallString<256> sbuf;
7990b57cec5SDimitry Andric   llvm::raw_svector_ostream os(sbuf);
8000b57cec5SDimitry Andric   os << "Returning without writing to '";
8010b57cec5SDimitry Andric 
8020b57cec5SDimitry Andric   // Do not generate the note if failed to pretty-print.
803349cc55cSDimitry Andric   if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,
804349cc55cSDimitry Andric                              FirstIsReferenceType, IndirectionLevel, os))
8050b57cec5SDimitry Andric     return nullptr;
8060b57cec5SDimitry Andric 
8070b57cec5SDimitry Andric   os << "'";
808a7dea167SDimitry Andric   if (TKind == bugreporter::TrackingKind::Condition)
809a7dea167SDimitry Andric     os << WillBeUsedForACondition;
8100b57cec5SDimitry Andric   return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
8110b57cec5SDimitry Andric }
8120b57cec5SDimitry Andric 
prettyPrintRegionName(const RegionVector & FieldChain,const MemRegion * MatchedRegion,StringRef FirstElement,bool FirstIsReferenceType,unsigned IndirectionLevel,llvm::raw_svector_ostream & os)813349cc55cSDimitry Andric bool NoStoreFuncVisitor::prettyPrintRegionName(const RegionVector &FieldChain,
8140b57cec5SDimitry Andric                                                const MemRegion *MatchedRegion,
815349cc55cSDimitry Andric                                                StringRef FirstElement,
816349cc55cSDimitry Andric                                                bool FirstIsReferenceType,
817349cc55cSDimitry Andric                                                unsigned IndirectionLevel,
8180b57cec5SDimitry Andric                                                llvm::raw_svector_ostream &os) {
8190b57cec5SDimitry Andric 
8200b57cec5SDimitry Andric   if (FirstIsReferenceType)
8210b57cec5SDimitry Andric     IndirectionLevel--;
8220b57cec5SDimitry Andric 
8230b57cec5SDimitry Andric   RegionVector RegionSequence;
8240b57cec5SDimitry Andric 
8250b57cec5SDimitry Andric   // Add the regions in the reverse order, then reverse the resulting array.
8260b57cec5SDimitry Andric   assert(RegionOfInterest->isSubRegionOf(MatchedRegion));
8270b57cec5SDimitry Andric   const MemRegion *R = RegionOfInterest;
8280b57cec5SDimitry Andric   while (R != MatchedRegion) {
8290b57cec5SDimitry Andric     RegionSequence.push_back(R);
8300b57cec5SDimitry Andric     R = cast<SubRegion>(R)->getSuperRegion();
8310b57cec5SDimitry Andric   }
8320b57cec5SDimitry Andric   std::reverse(RegionSequence.begin(), RegionSequence.end());
8330b57cec5SDimitry Andric   RegionSequence.append(FieldChain.begin(), FieldChain.end());
8340b57cec5SDimitry Andric 
8350b57cec5SDimitry Andric   StringRef Sep;
8360b57cec5SDimitry Andric   for (const MemRegion *R : RegionSequence) {
8370b57cec5SDimitry Andric 
8380b57cec5SDimitry Andric     // Just keep going up to the base region.
8390b57cec5SDimitry Andric     // Element regions may appear due to casts.
840349cc55cSDimitry Andric     if (isa<CXXBaseObjectRegion, CXXTempObjectRegion>(R))
8410b57cec5SDimitry Andric       continue;
8420b57cec5SDimitry Andric 
8430b57cec5SDimitry Andric     if (Sep.empty())
8440b57cec5SDimitry Andric       Sep = prettyPrintFirstElement(FirstElement,
8450b57cec5SDimitry Andric                                     /*MoreItemsExpected=*/true,
8460b57cec5SDimitry Andric                                     IndirectionLevel, os);
8470b57cec5SDimitry Andric 
8480b57cec5SDimitry Andric     os << Sep;
8490b57cec5SDimitry Andric 
8500b57cec5SDimitry Andric     // Can only reasonably pretty-print DeclRegions.
8510b57cec5SDimitry Andric     if (!isa<DeclRegion>(R))
8520b57cec5SDimitry Andric       return false;
8530b57cec5SDimitry Andric 
8540b57cec5SDimitry Andric     const auto *DR = cast<DeclRegion>(R);
8550b57cec5SDimitry Andric     Sep = DR->getValueType()->isAnyPointerType() ? "->" : ".";
8560b57cec5SDimitry Andric     DR->getDecl()->getDeclName().print(os, PP);
8570b57cec5SDimitry Andric   }
8580b57cec5SDimitry Andric 
8590b57cec5SDimitry Andric   if (Sep.empty())
8600b57cec5SDimitry Andric     prettyPrintFirstElement(FirstElement,
8610b57cec5SDimitry Andric                             /*MoreItemsExpected=*/false, IndirectionLevel, os);
8620b57cec5SDimitry Andric   return true;
8630b57cec5SDimitry Andric }
8640b57cec5SDimitry Andric 
prettyPrintFirstElement(StringRef FirstElement,bool MoreItemsExpected,int IndirectionLevel,llvm::raw_svector_ostream & os)8650b57cec5SDimitry Andric StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
8660b57cec5SDimitry Andric     StringRef FirstElement, bool MoreItemsExpected, int IndirectionLevel,
8670b57cec5SDimitry Andric     llvm::raw_svector_ostream &os) {
8680b57cec5SDimitry Andric   StringRef Out = ".";
8690b57cec5SDimitry Andric 
8700b57cec5SDimitry Andric   if (IndirectionLevel > 0 && MoreItemsExpected) {
8710b57cec5SDimitry Andric     IndirectionLevel--;
8720b57cec5SDimitry Andric     Out = "->";
8730b57cec5SDimitry Andric   }
8740b57cec5SDimitry Andric 
8750b57cec5SDimitry Andric   if (IndirectionLevel > 0 && MoreItemsExpected)
8760b57cec5SDimitry Andric     os << "(";
8770b57cec5SDimitry Andric 
8780b57cec5SDimitry Andric   for (int i = 0; i < IndirectionLevel; i++)
8790b57cec5SDimitry Andric     os << "*";
8800b57cec5SDimitry Andric   os << FirstElement;
8810b57cec5SDimitry Andric 
8820b57cec5SDimitry Andric   if (IndirectionLevel > 0 && MoreItemsExpected)
8830b57cec5SDimitry Andric     os << ")";
8840b57cec5SDimitry Andric 
8850b57cec5SDimitry Andric   return Out;
8860b57cec5SDimitry Andric }
8870b57cec5SDimitry Andric 
8880b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8890b57cec5SDimitry Andric // Implementation of MacroNullReturnSuppressionVisitor.
8900b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8910b57cec5SDimitry Andric 
8920b57cec5SDimitry Andric namespace {
8930b57cec5SDimitry Andric 
8940b57cec5SDimitry Andric /// Suppress null-pointer-dereference bugs where dereferenced null was returned
8950b57cec5SDimitry Andric /// the macro.
8960b57cec5SDimitry Andric class MacroNullReturnSuppressionVisitor final : public BugReporterVisitor {
8970b57cec5SDimitry Andric   const SubRegion *RegionOfInterest;
8980b57cec5SDimitry Andric   const SVal ValueAtDereference;
8990b57cec5SDimitry Andric 
9000b57cec5SDimitry Andric   // Do not invalidate the reports where the value was modified
9010b57cec5SDimitry Andric   // after it got assigned to from the macro.
9020b57cec5SDimitry Andric   bool WasModified = false;
9030b57cec5SDimitry Andric 
9040b57cec5SDimitry Andric public:
MacroNullReturnSuppressionVisitor(const SubRegion * R,const SVal V)905a7dea167SDimitry Andric   MacroNullReturnSuppressionVisitor(const SubRegion *R, const SVal V)
906a7dea167SDimitry Andric       : RegionOfInterest(R), ValueAtDereference(V) {}
9070b57cec5SDimitry Andric 
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)908a7dea167SDimitry Andric   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
9090b57cec5SDimitry Andric                                    BugReporterContext &BRC,
910a7dea167SDimitry Andric                                    PathSensitiveBugReport &BR) override {
9110b57cec5SDimitry Andric     if (WasModified)
9120b57cec5SDimitry Andric       return nullptr;
9130b57cec5SDimitry Andric 
9140b57cec5SDimitry Andric     auto BugPoint = BR.getErrorNode()->getLocation().getAs<StmtPoint>();
9150b57cec5SDimitry Andric     if (!BugPoint)
9160b57cec5SDimitry Andric       return nullptr;
9170b57cec5SDimitry Andric 
9180b57cec5SDimitry Andric     const SourceManager &SMgr = BRC.getSourceManager();
9190b57cec5SDimitry Andric     if (auto Loc = matchAssignment(N)) {
9200b57cec5SDimitry Andric       if (isFunctionMacroExpansion(*Loc, SMgr)) {
9215ffd83dbSDimitry Andric         std::string MacroName = std::string(getMacroName(*Loc, BRC));
9220b57cec5SDimitry Andric         SourceLocation BugLoc = BugPoint->getStmt()->getBeginLoc();
9230b57cec5SDimitry Andric         if (!BugLoc.isMacroID() || getMacroName(BugLoc, BRC) != MacroName)
9240b57cec5SDimitry Andric           BR.markInvalid(getTag(), MacroName.c_str());
9250b57cec5SDimitry Andric       }
9260b57cec5SDimitry Andric     }
9270b57cec5SDimitry Andric 
9280b57cec5SDimitry Andric     if (wasRegionOfInterestModifiedAt(RegionOfInterest, N, ValueAtDereference))
9290b57cec5SDimitry Andric       WasModified = true;
9300b57cec5SDimitry Andric 
9310b57cec5SDimitry Andric     return nullptr;
9320b57cec5SDimitry Andric   }
9330b57cec5SDimitry Andric 
addMacroVisitorIfNecessary(const ExplodedNode * N,const MemRegion * R,bool EnableNullFPSuppression,PathSensitiveBugReport & BR,const SVal V)9340b57cec5SDimitry Andric   static void addMacroVisitorIfNecessary(
9350b57cec5SDimitry Andric         const ExplodedNode *N, const MemRegion *R,
936a7dea167SDimitry Andric         bool EnableNullFPSuppression, PathSensitiveBugReport &BR,
9370b57cec5SDimitry Andric         const SVal V) {
9380b57cec5SDimitry Andric     AnalyzerOptions &Options = N->getState()->getAnalysisManager().options;
939fe6060f1SDimitry Andric     if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&
94081ad6265SDimitry Andric         isa<Loc>(V))
941fe6060f1SDimitry Andric       BR.addVisitor<MacroNullReturnSuppressionVisitor>(R->getAs<SubRegion>(),
942fe6060f1SDimitry Andric                                                        V);
9430b57cec5SDimitry Andric   }
9440b57cec5SDimitry Andric 
getTag() const9450b57cec5SDimitry Andric   void* getTag() const {
9460b57cec5SDimitry Andric     static int Tag = 0;
9470b57cec5SDimitry Andric     return static_cast<void *>(&Tag);
9480b57cec5SDimitry Andric   }
9490b57cec5SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const9500b57cec5SDimitry Andric   void Profile(llvm::FoldingSetNodeID &ID) const override {
9510b57cec5SDimitry Andric     ID.AddPointer(getTag());
9520b57cec5SDimitry Andric   }
9530b57cec5SDimitry Andric 
9540b57cec5SDimitry Andric private:
9550b57cec5SDimitry Andric   /// \return Source location of right hand side of an assignment
9560b57cec5SDimitry Andric   /// into \c RegionOfInterest, empty optional if none found.
matchAssignment(const ExplodedNode * N)957bdd1243dSDimitry Andric   std::optional<SourceLocation> matchAssignment(const ExplodedNode *N) {
958a7dea167SDimitry Andric     const Stmt *S = N->getStmtForDiagnostics();
9590b57cec5SDimitry Andric     ProgramStateRef State = N->getState();
9600b57cec5SDimitry Andric     auto *LCtx = N->getLocationContext();
9610b57cec5SDimitry Andric     if (!S)
962bdd1243dSDimitry Andric       return std::nullopt;
9630b57cec5SDimitry Andric 
9640b57cec5SDimitry Andric     if (const auto *DS = dyn_cast<DeclStmt>(S)) {
9650b57cec5SDimitry Andric       if (const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
9660b57cec5SDimitry Andric         if (const Expr *RHS = VD->getInit())
9670b57cec5SDimitry Andric           if (RegionOfInterest->isSubRegionOf(
9680b57cec5SDimitry Andric                   State->getLValue(VD, LCtx).getAsRegion()))
9690b57cec5SDimitry Andric             return RHS->getBeginLoc();
9700b57cec5SDimitry Andric     } else if (const auto *BO = dyn_cast<BinaryOperator>(S)) {
9710b57cec5SDimitry Andric       const MemRegion *R = N->getSVal(BO->getLHS()).getAsRegion();
9720b57cec5SDimitry Andric       const Expr *RHS = BO->getRHS();
9730b57cec5SDimitry Andric       if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {
9740b57cec5SDimitry Andric         return RHS->getBeginLoc();
9750b57cec5SDimitry Andric       }
9760b57cec5SDimitry Andric     }
977bdd1243dSDimitry Andric     return std::nullopt;
9780b57cec5SDimitry Andric   }
9790b57cec5SDimitry Andric };
9800b57cec5SDimitry Andric 
9810b57cec5SDimitry Andric } // end of anonymous namespace
9820b57cec5SDimitry Andric 
9830b57cec5SDimitry Andric namespace {
9840b57cec5SDimitry Andric 
9850b57cec5SDimitry Andric /// Emits an extra note at the return statement of an interesting stack frame.
9860b57cec5SDimitry Andric ///
9870b57cec5SDimitry Andric /// The returned value is marked as an interesting value, and if it's null,
9880b57cec5SDimitry Andric /// adds a visitor to track where it became null.
9890b57cec5SDimitry Andric ///
9900b57cec5SDimitry Andric /// This visitor is intended to be used when another visitor discovers that an
9910b57cec5SDimitry Andric /// interesting value comes from an inlined function call.
992fe6060f1SDimitry Andric class ReturnVisitor : public TrackingBugReporterVisitor {
993a7dea167SDimitry Andric   const StackFrameContext *CalleeSFC;
9940b57cec5SDimitry Andric   enum {
9950b57cec5SDimitry Andric     Initial,
9960b57cec5SDimitry Andric     MaybeUnsuppress,
9970b57cec5SDimitry Andric     Satisfied
9980b57cec5SDimitry Andric   } Mode = Initial;
9990b57cec5SDimitry Andric 
10000b57cec5SDimitry Andric   bool EnableNullFPSuppression;
10010b57cec5SDimitry Andric   bool ShouldInvalidate = true;
10020b57cec5SDimitry Andric   AnalyzerOptions& Options;
1003a7dea167SDimitry Andric   bugreporter::TrackingKind TKind;
10040b57cec5SDimitry Andric 
10050b57cec5SDimitry Andric public:
ReturnVisitor(TrackerRef ParentTracker,const StackFrameContext * Frame,bool Suppressed,AnalyzerOptions & Options,bugreporter::TrackingKind TKind)1006fe6060f1SDimitry Andric   ReturnVisitor(TrackerRef ParentTracker, const StackFrameContext *Frame,
1007fe6060f1SDimitry Andric                 bool Suppressed, AnalyzerOptions &Options,
1008fe6060f1SDimitry Andric                 bugreporter::TrackingKind TKind)
1009fe6060f1SDimitry Andric       : TrackingBugReporterVisitor(ParentTracker), CalleeSFC(Frame),
1010fe6060f1SDimitry Andric         EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
10110b57cec5SDimitry Andric 
getTag()10120b57cec5SDimitry Andric   static void *getTag() {
10130b57cec5SDimitry Andric     static int Tag = 0;
10140b57cec5SDimitry Andric     return static_cast<void *>(&Tag);
10150b57cec5SDimitry Andric   }
10160b57cec5SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const10170b57cec5SDimitry Andric   void Profile(llvm::FoldingSetNodeID &ID) const override {
10180b57cec5SDimitry Andric     ID.AddPointer(ReturnVisitor::getTag());
1019a7dea167SDimitry Andric     ID.AddPointer(CalleeSFC);
10200b57cec5SDimitry Andric     ID.AddBoolean(EnableNullFPSuppression);
10210b57cec5SDimitry Andric   }
10220b57cec5SDimitry Andric 
visitNodeInitial(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)1023a7dea167SDimitry Andric   PathDiagnosticPieceRef visitNodeInitial(const ExplodedNode *N,
1024a7dea167SDimitry Andric                                           BugReporterContext &BRC,
1025a7dea167SDimitry Andric                                           PathSensitiveBugReport &BR) {
10260b57cec5SDimitry Andric     // Only print a message at the interesting return statement.
1027a7dea167SDimitry Andric     if (N->getLocationContext() != CalleeSFC)
10280b57cec5SDimitry Andric       return nullptr;
10290b57cec5SDimitry Andric 
1030bdd1243dSDimitry Andric     std::optional<StmtPoint> SP = N->getLocationAs<StmtPoint>();
10310b57cec5SDimitry Andric     if (!SP)
10320b57cec5SDimitry Andric       return nullptr;
10330b57cec5SDimitry Andric 
10340b57cec5SDimitry Andric     const auto *Ret = dyn_cast<ReturnStmt>(SP->getStmt());
10350b57cec5SDimitry Andric     if (!Ret)
10360b57cec5SDimitry Andric       return nullptr;
10370b57cec5SDimitry Andric 
10380b57cec5SDimitry Andric     // Okay, we're at the right return statement, but do we have the return
10390b57cec5SDimitry Andric     // value available?
10400b57cec5SDimitry Andric     ProgramStateRef State = N->getState();
1041a7dea167SDimitry Andric     SVal V = State->getSVal(Ret, CalleeSFC);
10420b57cec5SDimitry Andric     if (V.isUnknownOrUndef())
10430b57cec5SDimitry Andric       return nullptr;
10440b57cec5SDimitry Andric 
10450b57cec5SDimitry Andric     // Don't print any more notes after this one.
10460b57cec5SDimitry Andric     Mode = Satisfied;
10470b57cec5SDimitry Andric 
10480b57cec5SDimitry Andric     const Expr *RetE = Ret->getRetValue();
10490b57cec5SDimitry Andric     assert(RetE && "Tracking a return value for a void function");
10500b57cec5SDimitry Andric 
10510b57cec5SDimitry Andric     // Handle cases where a reference is returned and then immediately used.
1052bdd1243dSDimitry Andric     std::optional<Loc> LValue;
10530b57cec5SDimitry Andric     if (RetE->isGLValue()) {
10540b57cec5SDimitry Andric       if ((LValue = V.getAs<Loc>())) {
10550b57cec5SDimitry Andric         SVal RValue = State->getRawSVal(*LValue, RetE->getType());
105681ad6265SDimitry Andric         if (isa<DefinedSVal>(RValue))
10570b57cec5SDimitry Andric           V = RValue;
10580b57cec5SDimitry Andric       }
10590b57cec5SDimitry Andric     }
10600b57cec5SDimitry Andric 
10610b57cec5SDimitry Andric     // Ignore aggregate rvalues.
106281ad6265SDimitry Andric     if (isa<nonloc::LazyCompoundVal, nonloc::CompoundVal>(V))
10630b57cec5SDimitry Andric       return nullptr;
10640b57cec5SDimitry Andric 
10650b57cec5SDimitry Andric     RetE = RetE->IgnoreParenCasts();
10660b57cec5SDimitry Andric 
1067a7dea167SDimitry Andric     // Let's track the return value.
1068fe6060f1SDimitry Andric     getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
10690b57cec5SDimitry Andric 
10700b57cec5SDimitry Andric     // Build an appropriate message based on the return value.
10710b57cec5SDimitry Andric     SmallString<64> Msg;
10720b57cec5SDimitry Andric     llvm::raw_svector_ostream Out(Msg);
10730b57cec5SDimitry Andric 
1074a7dea167SDimitry Andric     bool WouldEventBeMeaningless = false;
1075a7dea167SDimitry Andric 
10760b57cec5SDimitry Andric     if (State->isNull(V).isConstrainedTrue()) {
107781ad6265SDimitry Andric       if (isa<Loc>(V)) {
10780b57cec5SDimitry Andric 
10790b57cec5SDimitry Andric         // If we have counter-suppression enabled, make sure we keep visiting
10800b57cec5SDimitry Andric         // future nodes. We want to emit a path note as well, in case
10810b57cec5SDimitry Andric         // the report is resurrected as valid later on.
10820b57cec5SDimitry Andric         if (EnableNullFPSuppression &&
10830b57cec5SDimitry Andric             Options.ShouldAvoidSuppressingNullArgumentPaths)
10840b57cec5SDimitry Andric           Mode = MaybeUnsuppress;
10850b57cec5SDimitry Andric 
10860b57cec5SDimitry Andric         if (RetE->getType()->isObjCObjectPointerType()) {
10870b57cec5SDimitry Andric           Out << "Returning nil";
10880b57cec5SDimitry Andric         } else {
10890b57cec5SDimitry Andric           Out << "Returning null pointer";
10900b57cec5SDimitry Andric         }
10910b57cec5SDimitry Andric       } else {
10920b57cec5SDimitry Andric         Out << "Returning zero";
10930b57cec5SDimitry Andric       }
10940b57cec5SDimitry Andric 
10950b57cec5SDimitry Andric     } else {
10960b57cec5SDimitry Andric       if (auto CI = V.getAs<nonloc::ConcreteInt>()) {
10970b57cec5SDimitry Andric         Out << "Returning the value " << CI->getValue();
10980b57cec5SDimitry Andric       } else {
1099a7dea167SDimitry Andric         // There is nothing interesting about returning a value, when it is
1100a7dea167SDimitry Andric         // plain value without any constraints, and the function is guaranteed
1101a7dea167SDimitry Andric         // to return that every time. We could use CFG::isLinear() here, but
1102a7dea167SDimitry Andric         // constexpr branches are obvious to the compiler, not necesserily to
1103a7dea167SDimitry Andric         // the programmer.
1104a7dea167SDimitry Andric         if (N->getCFG().size() == 3)
1105a7dea167SDimitry Andric           WouldEventBeMeaningless = true;
1106a7dea167SDimitry Andric 
110781ad6265SDimitry Andric         Out << (isa<Loc>(V) ? "Returning pointer" : "Returning value");
11080b57cec5SDimitry Andric       }
11090b57cec5SDimitry Andric     }
11100b57cec5SDimitry Andric 
11110b57cec5SDimitry Andric     if (LValue) {
11120b57cec5SDimitry Andric       if (const MemRegion *MR = LValue->getAsRegion()) {
11130b57cec5SDimitry Andric         if (MR->canPrintPretty()) {
11140b57cec5SDimitry Andric           Out << " (reference to ";
11150b57cec5SDimitry Andric           MR->printPretty(Out);
11160b57cec5SDimitry Andric           Out << ")";
11170b57cec5SDimitry Andric         }
11180b57cec5SDimitry Andric       }
11190b57cec5SDimitry Andric     } else {
11200b57cec5SDimitry Andric       // FIXME: We should have a more generalized location printing mechanism.
11210b57cec5SDimitry Andric       if (const auto *DR = dyn_cast<DeclRefExpr>(RetE))
11220b57cec5SDimitry Andric         if (const auto *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
11230b57cec5SDimitry Andric           Out << " (loaded from '" << *DD << "')";
11240b57cec5SDimitry Andric     }
11250b57cec5SDimitry Andric 
1126a7dea167SDimitry Andric     PathDiagnosticLocation L(Ret, BRC.getSourceManager(), CalleeSFC);
11270b57cec5SDimitry Andric     if (!L.isValid() || !L.asLocation().isValid())
11280b57cec5SDimitry Andric       return nullptr;
11290b57cec5SDimitry Andric 
1130a7dea167SDimitry Andric     if (TKind == bugreporter::TrackingKind::Condition)
1131a7dea167SDimitry Andric       Out << WillBeUsedForACondition;
1132a7dea167SDimitry Andric 
1133a7dea167SDimitry Andric     auto EventPiece = std::make_shared<PathDiagnosticEventPiece>(L, Out.str());
1134a7dea167SDimitry Andric 
1135a7dea167SDimitry Andric     // If we determined that the note is meaningless, make it prunable, and
1136a7dea167SDimitry Andric     // don't mark the stackframe interesting.
1137a7dea167SDimitry Andric     if (WouldEventBeMeaningless)
1138a7dea167SDimitry Andric       EventPiece->setPrunable(true);
1139a7dea167SDimitry Andric     else
1140a7dea167SDimitry Andric       BR.markInteresting(CalleeSFC);
1141a7dea167SDimitry Andric 
1142a7dea167SDimitry Andric     return EventPiece;
11430b57cec5SDimitry Andric   }
11440b57cec5SDimitry Andric 
visitNodeMaybeUnsuppress(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)1145a7dea167SDimitry Andric   PathDiagnosticPieceRef visitNodeMaybeUnsuppress(const ExplodedNode *N,
1146a7dea167SDimitry Andric                                                   BugReporterContext &BRC,
1147a7dea167SDimitry Andric                                                   PathSensitiveBugReport &BR) {
11480b57cec5SDimitry Andric     assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric     // Are we at the entry node for this call?
1151bdd1243dSDimitry Andric     std::optional<CallEnter> CE = N->getLocationAs<CallEnter>();
11520b57cec5SDimitry Andric     if (!CE)
11530b57cec5SDimitry Andric       return nullptr;
11540b57cec5SDimitry Andric 
1155a7dea167SDimitry Andric     if (CE->getCalleeContext() != CalleeSFC)
11560b57cec5SDimitry Andric       return nullptr;
11570b57cec5SDimitry Andric 
11580b57cec5SDimitry Andric     Mode = Satisfied;
11590b57cec5SDimitry Andric 
11600b57cec5SDimitry Andric     // Don't automatically suppress a report if one of the arguments is
11610b57cec5SDimitry Andric     // known to be a null pointer. Instead, start tracking /that/ null
11620b57cec5SDimitry Andric     // value back to its origin.
11630b57cec5SDimitry Andric     ProgramStateManager &StateMgr = BRC.getStateManager();
11640b57cec5SDimitry Andric     CallEventManager &CallMgr = StateMgr.getCallEventManager();
11650b57cec5SDimitry Andric 
11660b57cec5SDimitry Andric     ProgramStateRef State = N->getState();
1167a7dea167SDimitry Andric     CallEventRef<> Call = CallMgr.getCaller(CalleeSFC, State);
11680b57cec5SDimitry Andric     for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
1169bdd1243dSDimitry Andric       std::optional<Loc> ArgV = Call->getArgSVal(I).getAs<Loc>();
11700b57cec5SDimitry Andric       if (!ArgV)
11710b57cec5SDimitry Andric         continue;
11720b57cec5SDimitry Andric 
11730b57cec5SDimitry Andric       const Expr *ArgE = Call->getArgExpr(I);
11740b57cec5SDimitry Andric       if (!ArgE)
11750b57cec5SDimitry Andric         continue;
11760b57cec5SDimitry Andric 
11770b57cec5SDimitry Andric       // Is it possible for this argument to be non-null?
11780b57cec5SDimitry Andric       if (!State->isNull(*ArgV).isConstrainedTrue())
11790b57cec5SDimitry Andric         continue;
11800b57cec5SDimitry Andric 
1181fe6060f1SDimitry Andric       if (getParentTracker()
1182fe6060f1SDimitry Andric               .track(ArgE, N, {TKind, EnableNullFPSuppression})
1183fe6060f1SDimitry Andric               .FoundSomethingToTrack)
11840b57cec5SDimitry Andric         ShouldInvalidate = false;
11850b57cec5SDimitry Andric 
11860b57cec5SDimitry Andric       // If we /can't/ track the null pointer, we should err on the side of
11870b57cec5SDimitry Andric       // false negatives, and continue towards marking this report invalid.
11880b57cec5SDimitry Andric       // (We will still look at the other arguments, though.)
11890b57cec5SDimitry Andric     }
11900b57cec5SDimitry Andric 
11910b57cec5SDimitry Andric     return nullptr;
11920b57cec5SDimitry Andric   }
11930b57cec5SDimitry Andric 
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)1194a7dea167SDimitry Andric   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
11950b57cec5SDimitry Andric                                    BugReporterContext &BRC,
1196a7dea167SDimitry Andric                                    PathSensitiveBugReport &BR) override {
11970b57cec5SDimitry Andric     switch (Mode) {
11980b57cec5SDimitry Andric     case Initial:
11990b57cec5SDimitry Andric       return visitNodeInitial(N, BRC, BR);
12000b57cec5SDimitry Andric     case MaybeUnsuppress:
12010b57cec5SDimitry Andric       return visitNodeMaybeUnsuppress(N, BRC, BR);
12020b57cec5SDimitry Andric     case Satisfied:
12030b57cec5SDimitry Andric       return nullptr;
12040b57cec5SDimitry Andric     }
12050b57cec5SDimitry Andric 
12060b57cec5SDimitry Andric     llvm_unreachable("Invalid visit mode!");
12070b57cec5SDimitry Andric   }
12080b57cec5SDimitry Andric 
finalizeVisitor(BugReporterContext &,const ExplodedNode *,PathSensitiveBugReport & BR)12090b57cec5SDimitry Andric   void finalizeVisitor(BugReporterContext &, const ExplodedNode *,
1210a7dea167SDimitry Andric                        PathSensitiveBugReport &BR) override {
12110b57cec5SDimitry Andric     if (EnableNullFPSuppression && ShouldInvalidate)
1212a7dea167SDimitry Andric       BR.markInvalid(ReturnVisitor::getTag(), CalleeSFC);
12130b57cec5SDimitry Andric   }
12140b57cec5SDimitry Andric };
12150b57cec5SDimitry Andric 
12160b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1217fe6060f1SDimitry Andric //                               StoreSiteFinder
12180b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12190b57cec5SDimitry Andric 
1220fe6060f1SDimitry Andric /// Finds last store into the given region,
1221fe6060f1SDimitry Andric /// which is different from a given symbolic value.
1222fe6060f1SDimitry Andric class StoreSiteFinder final : public TrackingBugReporterVisitor {
1223fe6060f1SDimitry Andric   const MemRegion *R;
1224fe6060f1SDimitry Andric   SVal V;
1225fe6060f1SDimitry Andric   bool Satisfied = false;
1226fe6060f1SDimitry Andric 
1227fe6060f1SDimitry Andric   TrackingOptions Options;
1228fe6060f1SDimitry Andric   const StackFrameContext *OriginSFC;
1229fe6060f1SDimitry Andric 
1230fe6060f1SDimitry Andric public:
1231fe6060f1SDimitry Andric   /// \param V We're searching for the store where \c R received this value.
1232fe6060f1SDimitry Andric   /// \param R The region we're tracking.
1233349cc55cSDimitry Andric   /// \param Options Tracking behavior options.
1234fe6060f1SDimitry Andric   /// \param OriginSFC Only adds notes when the last store happened in a
1235fe6060f1SDimitry Andric   ///        different stackframe to this one. Disregarded if the tracking kind
1236fe6060f1SDimitry Andric   ///        is thorough.
1237fe6060f1SDimitry Andric   ///        This is useful, because for non-tracked regions, notes about
1238fe6060f1SDimitry Andric   ///        changes to its value in a nested stackframe could be pruned, and
1239fe6060f1SDimitry Andric   ///        this visitor can prevent that without polluting the bugpath too
1240fe6060f1SDimitry Andric   ///        much.
StoreSiteFinder(bugreporter::TrackerRef ParentTracker,KnownSVal V,const MemRegion * R,TrackingOptions Options,const StackFrameContext * OriginSFC=nullptr)1241fe6060f1SDimitry Andric   StoreSiteFinder(bugreporter::TrackerRef ParentTracker, KnownSVal V,
1242fe6060f1SDimitry Andric                   const MemRegion *R, TrackingOptions Options,
1243fe6060f1SDimitry Andric                   const StackFrameContext *OriginSFC = nullptr)
1244fe6060f1SDimitry Andric       : TrackingBugReporterVisitor(ParentTracker), R(R), V(V), Options(Options),
1245fe6060f1SDimitry Andric         OriginSFC(OriginSFC) {
1246fe6060f1SDimitry Andric     assert(R);
1247fe6060f1SDimitry Andric   }
1248fe6060f1SDimitry Andric 
1249fe6060f1SDimitry Andric   void Profile(llvm::FoldingSetNodeID &ID) const override;
1250fe6060f1SDimitry Andric 
1251fe6060f1SDimitry Andric   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
1252fe6060f1SDimitry Andric                                    BugReporterContext &BRC,
1253fe6060f1SDimitry Andric                                    PathSensitiveBugReport &BR) override;
1254fe6060f1SDimitry Andric };
1255bdd1243dSDimitry Andric } // namespace
1256fe6060f1SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const1257fe6060f1SDimitry Andric void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID) const {
12580b57cec5SDimitry Andric   static int tag = 0;
12590b57cec5SDimitry Andric   ID.AddPointer(&tag);
12600b57cec5SDimitry Andric   ID.AddPointer(R);
12610b57cec5SDimitry Andric   ID.Add(V);
1262fe6060f1SDimitry Andric   ID.AddInteger(static_cast<int>(Options.Kind));
1263fe6060f1SDimitry Andric   ID.AddBoolean(Options.EnableNullFPSuppression);
12640b57cec5SDimitry Andric }
12650b57cec5SDimitry Andric 
12660b57cec5SDimitry Andric /// Returns true if \p N represents the DeclStmt declaring and initializing
12670b57cec5SDimitry Andric /// \p VR.
isInitializationOfVar(const ExplodedNode * N,const VarRegion * VR)12680b57cec5SDimitry Andric static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
1269bdd1243dSDimitry Andric   std::optional<PostStmt> P = N->getLocationAs<PostStmt>();
12700b57cec5SDimitry Andric   if (!P)
12710b57cec5SDimitry Andric     return false;
12720b57cec5SDimitry Andric 
12730b57cec5SDimitry Andric   const DeclStmt *DS = P->getStmtAs<DeclStmt>();
12740b57cec5SDimitry Andric   if (!DS)
12750b57cec5SDimitry Andric     return false;
12760b57cec5SDimitry Andric 
12770b57cec5SDimitry Andric   if (DS->getSingleDecl() != VR->getDecl())
12780b57cec5SDimitry Andric     return false;
12790b57cec5SDimitry Andric 
12800b57cec5SDimitry Andric   const MemSpaceRegion *VarSpace = VR->getMemorySpace();
12810b57cec5SDimitry Andric   const auto *FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
12820b57cec5SDimitry Andric   if (!FrameSpace) {
12830b57cec5SDimitry Andric     // If we ever directly evaluate global DeclStmts, this assertion will be
12840b57cec5SDimitry Andric     // invalid, but this still seems preferable to silently accepting an
12850b57cec5SDimitry Andric     // initialization that may be for a path-sensitive variable.
12860b57cec5SDimitry Andric     assert(VR->getDecl()->isStaticLocal() && "non-static stackless VarRegion");
12870b57cec5SDimitry Andric     return true;
12880b57cec5SDimitry Andric   }
12890b57cec5SDimitry Andric 
12900b57cec5SDimitry Andric   assert(VR->getDecl()->hasLocalStorage());
12910b57cec5SDimitry Andric   const LocationContext *LCtx = N->getLocationContext();
12920b57cec5SDimitry Andric   return FrameSpace->getStackFrame() == LCtx->getStackFrame();
12930b57cec5SDimitry Andric }
12940b57cec5SDimitry Andric 
isObjCPointer(const MemRegion * R)1295fe6060f1SDimitry Andric static bool isObjCPointer(const MemRegion *R) {
1296fe6060f1SDimitry Andric   if (R->isBoundable())
1297fe6060f1SDimitry Andric     if (const auto *TR = dyn_cast<TypedValueRegion>(R))
1298fe6060f1SDimitry Andric       return TR->getValueType()->isObjCObjectPointerType();
1299fe6060f1SDimitry Andric 
1300fe6060f1SDimitry Andric   return false;
1301fe6060f1SDimitry Andric }
1302fe6060f1SDimitry Andric 
isObjCPointer(const ValueDecl * D)1303fe6060f1SDimitry Andric static bool isObjCPointer(const ValueDecl *D) {
1304fe6060f1SDimitry Andric   return D->getType()->isObjCObjectPointerType();
1305fe6060f1SDimitry Andric }
1306fe6060f1SDimitry Andric 
13070b57cec5SDimitry Andric /// Show diagnostics for initializing or declaring a region \p R with a bad value.
showBRDiagnostics(llvm::raw_svector_ostream & OS,StoreInfo SI)1308fe6060f1SDimitry Andric static void showBRDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI) {
1309fe6060f1SDimitry Andric   const bool HasPrefix = SI.Dest->canPrintPretty();
1310fe6060f1SDimitry Andric 
1311fe6060f1SDimitry Andric   if (HasPrefix) {
1312fe6060f1SDimitry Andric     SI.Dest->printPretty(OS);
1313fe6060f1SDimitry Andric     OS << " ";
13140b57cec5SDimitry Andric   }
13150b57cec5SDimitry Andric 
1316fe6060f1SDimitry Andric   const char *Action = nullptr;
13170b57cec5SDimitry Andric 
1318fe6060f1SDimitry Andric   switch (SI.StoreKind) {
1319fe6060f1SDimitry Andric   case StoreInfo::Initialization:
1320fe6060f1SDimitry Andric     Action = HasPrefix ? "initialized to " : "Initializing to ";
1321fe6060f1SDimitry Andric     break;
1322fe6060f1SDimitry Andric   case StoreInfo::BlockCapture:
1323fe6060f1SDimitry Andric     Action = HasPrefix ? "captured by block as " : "Captured by block as ";
1324fe6060f1SDimitry Andric     break;
1325fe6060f1SDimitry Andric   default:
1326fe6060f1SDimitry Andric     llvm_unreachable("Unexpected store kind");
1327fe6060f1SDimitry Andric   }
1328fe6060f1SDimitry Andric 
132981ad6265SDimitry Andric   if (isa<loc::ConcreteInt>(SI.Value)) {
1330fe6060f1SDimitry Andric     OS << Action << (isObjCPointer(SI.Dest) ? "nil" : "a null pointer value");
1331fe6060f1SDimitry Andric 
1332fe6060f1SDimitry Andric   } else if (auto CVal = SI.Value.getAs<nonloc::ConcreteInt>()) {
1333fe6060f1SDimitry Andric     OS << Action << CVal->getValue();
1334fe6060f1SDimitry Andric 
1335fe6060f1SDimitry Andric   } else if (SI.Origin && SI.Origin->canPrintPretty()) {
1336fe6060f1SDimitry Andric     OS << Action << "the value of ";
1337fe6060f1SDimitry Andric     SI.Origin->printPretty(OS);
1338fe6060f1SDimitry Andric 
1339fe6060f1SDimitry Andric   } else if (SI.StoreKind == StoreInfo::Initialization) {
1340fe6060f1SDimitry Andric     // We don't need to check here, all these conditions were
1341fe6060f1SDimitry Andric     // checked by StoreSiteFinder, when it figured out that it is
1342fe6060f1SDimitry Andric     // initialization.
1343fe6060f1SDimitry Andric     const auto *DS =
1344fe6060f1SDimitry Andric         cast<DeclStmt>(SI.StoreSite->getLocationAs<PostStmt>()->getStmt());
1345fe6060f1SDimitry Andric 
1346fe6060f1SDimitry Andric     if (SI.Value.isUndef()) {
1347fe6060f1SDimitry Andric       if (isa<VarRegion>(SI.Dest)) {
13480b57cec5SDimitry Andric         const auto *VD = cast<VarDecl>(DS->getSingleDecl());
1349fe6060f1SDimitry Andric 
13500b57cec5SDimitry Andric         if (VD->getInit()) {
1351fe6060f1SDimitry Andric           OS << (HasPrefix ? "initialized" : "Initializing")
13520b57cec5SDimitry Andric              << " to a garbage value";
13530b57cec5SDimitry Andric         } else {
1354fe6060f1SDimitry Andric           OS << (HasPrefix ? "declared" : "Declaring")
13550b57cec5SDimitry Andric              << " without an initial value";
13560b57cec5SDimitry Andric         }
13570b57cec5SDimitry Andric       }
13580b57cec5SDimitry Andric     } else {
1359fe6060f1SDimitry Andric       OS << (HasPrefix ? "initialized" : "Initialized") << " here";
13600b57cec5SDimitry Andric     }
13610b57cec5SDimitry Andric   }
13620b57cec5SDimitry Andric }
13630b57cec5SDimitry Andric 
13640b57cec5SDimitry Andric /// Display diagnostics for passing bad region as a parameter.
showBRParamDiagnostics(llvm::raw_svector_ostream & OS,StoreInfo SI)1365fe6060f1SDimitry Andric static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS,
1366fe6060f1SDimitry Andric                                    StoreInfo SI) {
1367fe6060f1SDimitry Andric   const auto *VR = cast<VarRegion>(SI.Dest);
1368bdd1243dSDimitry Andric   const auto *D = VR->getDecl();
13690b57cec5SDimitry Andric 
1370fe6060f1SDimitry Andric   OS << "Passing ";
13710b57cec5SDimitry Andric 
137281ad6265SDimitry Andric   if (isa<loc::ConcreteInt>(SI.Value)) {
1373bdd1243dSDimitry Andric     OS << (isObjCPointer(D) ? "nil object reference" : "null pointer value");
1374fe6060f1SDimitry Andric 
1375fe6060f1SDimitry Andric   } else if (SI.Value.isUndef()) {
1376fe6060f1SDimitry Andric     OS << "uninitialized value";
1377fe6060f1SDimitry Andric 
1378fe6060f1SDimitry Andric   } else if (auto CI = SI.Value.getAs<nonloc::ConcreteInt>()) {
1379fe6060f1SDimitry Andric     OS << "the value " << CI->getValue();
1380fe6060f1SDimitry Andric 
1381fe6060f1SDimitry Andric   } else if (SI.Origin && SI.Origin->canPrintPretty()) {
1382fe6060f1SDimitry Andric     SI.Origin->printPretty(OS);
1383fe6060f1SDimitry Andric 
13840b57cec5SDimitry Andric   } else {
1385fe6060f1SDimitry Andric     OS << "value";
13860b57cec5SDimitry Andric   }
13870b57cec5SDimitry Andric 
1388bdd1243dSDimitry Andric   if (const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
13890b57cec5SDimitry Andric     // Printed parameter indexes are 1-based, not 0-based.
13900b57cec5SDimitry Andric     unsigned Idx = Param->getFunctionScopeIndex() + 1;
1391fe6060f1SDimitry Andric     OS << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter";
13920b57cec5SDimitry Andric     if (VR->canPrintPretty()) {
1393fe6060f1SDimitry Andric       OS << " ";
1394fe6060f1SDimitry Andric       VR->printPretty(OS);
13950b57cec5SDimitry Andric     }
1396bdd1243dSDimitry Andric   } else if (const auto *ImplParam = dyn_cast<ImplicitParamDecl>(D)) {
13975f757f3fSDimitry Andric     if (ImplParam->getParameterKind() == ImplicitParamKind::ObjCSelf) {
1398bdd1243dSDimitry Andric       OS << " via implicit parameter 'self'";
1399bdd1243dSDimitry Andric     }
1400bdd1243dSDimitry Andric   }
14010b57cec5SDimitry Andric }
14020b57cec5SDimitry Andric 
14030b57cec5SDimitry Andric /// Show default diagnostics for storing bad region.
showBRDefaultDiagnostics(llvm::raw_svector_ostream & OS,StoreInfo SI)1404fe6060f1SDimitry Andric static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &OS,
1405fe6060f1SDimitry Andric                                      StoreInfo SI) {
1406fe6060f1SDimitry Andric   const bool HasSuffix = SI.Dest->canPrintPretty();
14070b57cec5SDimitry Andric 
140881ad6265SDimitry Andric   if (isa<loc::ConcreteInt>(SI.Value)) {
1409fe6060f1SDimitry Andric     OS << (isObjCPointer(SI.Dest) ? "nil object reference stored"
1410fe6060f1SDimitry Andric                                   : (HasSuffix ? "Null pointer value stored"
1411fe6060f1SDimitry Andric                                                : "Storing null pointer value"));
14120b57cec5SDimitry Andric 
1413fe6060f1SDimitry Andric   } else if (SI.Value.isUndef()) {
1414fe6060f1SDimitry Andric     OS << (HasSuffix ? "Uninitialized value stored"
1415fe6060f1SDimitry Andric                      : "Storing uninitialized value");
1416fe6060f1SDimitry Andric 
1417fe6060f1SDimitry Andric   } else if (auto CV = SI.Value.getAs<nonloc::ConcreteInt>()) {
1418fe6060f1SDimitry Andric     if (HasSuffix)
1419fe6060f1SDimitry Andric       OS << "The value " << CV->getValue() << " is assigned";
14200b57cec5SDimitry Andric     else
1421fe6060f1SDimitry Andric       OS << "Assigning " << CV->getValue();
1422fe6060f1SDimitry Andric 
1423fe6060f1SDimitry Andric   } else if (SI.Origin && SI.Origin->canPrintPretty()) {
1424fe6060f1SDimitry Andric     if (HasSuffix) {
1425fe6060f1SDimitry Andric       OS << "The value of ";
1426fe6060f1SDimitry Andric       SI.Origin->printPretty(OS);
1427fe6060f1SDimitry Andric       OS << " is assigned";
1428fe6060f1SDimitry Andric     } else {
1429fe6060f1SDimitry Andric       OS << "Assigning the value of ";
1430fe6060f1SDimitry Andric       SI.Origin->printPretty(OS);
1431fe6060f1SDimitry Andric     }
14320b57cec5SDimitry Andric 
14330b57cec5SDimitry Andric   } else {
1434fe6060f1SDimitry Andric     OS << (HasSuffix ? "Value assigned" : "Assigning value");
14350b57cec5SDimitry Andric   }
14360b57cec5SDimitry Andric 
1437fe6060f1SDimitry Andric   if (HasSuffix) {
1438fe6060f1SDimitry Andric     OS << " to ";
1439fe6060f1SDimitry Andric     SI.Dest->printPretty(OS);
14400b57cec5SDimitry Andric   }
14410b57cec5SDimitry Andric }
14420b57cec5SDimitry Andric 
isTrivialCopyOrMoveCtor(const CXXConstructExpr * CE)1443bdd1243dSDimitry Andric static bool isTrivialCopyOrMoveCtor(const CXXConstructExpr *CE) {
1444bdd1243dSDimitry Andric   if (!CE)
1445bdd1243dSDimitry Andric     return false;
1446bdd1243dSDimitry Andric 
1447bdd1243dSDimitry Andric   const auto *CtorDecl = CE->getConstructor();
1448bdd1243dSDimitry Andric 
1449bdd1243dSDimitry Andric   return CtorDecl->isCopyOrMoveConstructor() && CtorDecl->isTrivial();
1450bdd1243dSDimitry Andric }
1451bdd1243dSDimitry Andric 
tryExtractInitializerFromList(const InitListExpr * ILE,const MemRegion * R)1452bdd1243dSDimitry Andric static const Expr *tryExtractInitializerFromList(const InitListExpr *ILE,
1453bdd1243dSDimitry Andric                                                  const MemRegion *R) {
1454bdd1243dSDimitry Andric 
1455bdd1243dSDimitry Andric   const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
1456bdd1243dSDimitry Andric 
1457bdd1243dSDimitry Andric   if (!TVR)
1458bdd1243dSDimitry Andric     return nullptr;
1459bdd1243dSDimitry Andric 
1460bdd1243dSDimitry Andric   const auto ITy = ILE->getType().getCanonicalType();
1461bdd1243dSDimitry Andric 
1462bdd1243dSDimitry Andric   // Push each sub-region onto the stack.
1463bdd1243dSDimitry Andric   std::stack<const TypedValueRegion *> TVRStack;
1464bdd1243dSDimitry Andric   while (isa<FieldRegion>(TVR) || isa<ElementRegion>(TVR)) {
1465bdd1243dSDimitry Andric     // We found a region that matches the type of the init list,
1466bdd1243dSDimitry Andric     // so we assume this is the outer-most region. This can happen
1467bdd1243dSDimitry Andric     // if the initializer list is inside a class. If our assumption
1468bdd1243dSDimitry Andric     // is wrong, we return a nullptr in the end.
1469bdd1243dSDimitry Andric     if (ITy == TVR->getValueType().getCanonicalType())
1470bdd1243dSDimitry Andric       break;
1471bdd1243dSDimitry Andric 
1472bdd1243dSDimitry Andric     TVRStack.push(TVR);
1473bdd1243dSDimitry Andric     TVR = cast<TypedValueRegion>(TVR->getSuperRegion());
1474bdd1243dSDimitry Andric   }
1475bdd1243dSDimitry Andric 
1476bdd1243dSDimitry Andric   // If the type of the outer most region doesn't match the type
1477bdd1243dSDimitry Andric   // of the ILE, we can't match the ILE and the region.
1478bdd1243dSDimitry Andric   if (ITy != TVR->getValueType().getCanonicalType())
1479bdd1243dSDimitry Andric     return nullptr;
1480bdd1243dSDimitry Andric 
1481bdd1243dSDimitry Andric   const Expr *Init = ILE;
1482bdd1243dSDimitry Andric   while (!TVRStack.empty()) {
1483bdd1243dSDimitry Andric     TVR = TVRStack.top();
1484bdd1243dSDimitry Andric     TVRStack.pop();
1485bdd1243dSDimitry Andric 
1486bdd1243dSDimitry Andric     // We hit something that's not an init list before
1487bdd1243dSDimitry Andric     // running out of regions, so we most likely failed.
1488bdd1243dSDimitry Andric     if (!isa<InitListExpr>(Init))
1489bdd1243dSDimitry Andric       return nullptr;
1490bdd1243dSDimitry Andric 
1491bdd1243dSDimitry Andric     ILE = cast<InitListExpr>(Init);
1492bdd1243dSDimitry Andric     auto NumInits = ILE->getNumInits();
1493bdd1243dSDimitry Andric 
1494bdd1243dSDimitry Andric     if (const auto *FR = dyn_cast<FieldRegion>(TVR)) {
1495bdd1243dSDimitry Andric       const auto *FD = FR->getDecl();
1496bdd1243dSDimitry Andric 
1497bdd1243dSDimitry Andric       if (FD->getFieldIndex() >= NumInits)
1498bdd1243dSDimitry Andric         return nullptr;
1499bdd1243dSDimitry Andric 
1500bdd1243dSDimitry Andric       Init = ILE->getInit(FD->getFieldIndex());
1501bdd1243dSDimitry Andric     } else if (const auto *ER = dyn_cast<ElementRegion>(TVR)) {
1502bdd1243dSDimitry Andric       const auto Ind = ER->getIndex();
1503bdd1243dSDimitry Andric 
1504bdd1243dSDimitry Andric       // If index is symbolic, we can't figure out which expression
1505bdd1243dSDimitry Andric       // belongs to the region.
1506bdd1243dSDimitry Andric       if (!Ind.isConstant())
1507bdd1243dSDimitry Andric         return nullptr;
1508bdd1243dSDimitry Andric 
1509bdd1243dSDimitry Andric       const auto IndVal = Ind.getAsInteger()->getLimitedValue();
1510bdd1243dSDimitry Andric       if (IndVal >= NumInits)
1511bdd1243dSDimitry Andric         return nullptr;
1512bdd1243dSDimitry Andric 
1513bdd1243dSDimitry Andric       Init = ILE->getInit(IndVal);
1514bdd1243dSDimitry Andric     }
1515bdd1243dSDimitry Andric   }
1516bdd1243dSDimitry Andric 
1517bdd1243dSDimitry Andric   return Init;
1518bdd1243dSDimitry Andric }
1519bdd1243dSDimitry Andric 
VisitNode(const ExplodedNode * Succ,BugReporterContext & BRC,PathSensitiveBugReport & BR)1520fe6060f1SDimitry Andric PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
1521a7dea167SDimitry Andric                                                   BugReporterContext &BRC,
1522a7dea167SDimitry Andric                                                   PathSensitiveBugReport &BR) {
15230b57cec5SDimitry Andric   if (Satisfied)
15240b57cec5SDimitry Andric     return nullptr;
15250b57cec5SDimitry Andric 
15260b57cec5SDimitry Andric   const ExplodedNode *StoreSite = nullptr;
15270b57cec5SDimitry Andric   const ExplodedNode *Pred = Succ->getFirstPred();
15280b57cec5SDimitry Andric   const Expr *InitE = nullptr;
15290b57cec5SDimitry Andric   bool IsParam = false;
15300b57cec5SDimitry Andric 
15310b57cec5SDimitry Andric   // First see if we reached the declaration of the region.
15320b57cec5SDimitry Andric   if (const auto *VR = dyn_cast<VarRegion>(R)) {
15330b57cec5SDimitry Andric     if (isInitializationOfVar(Pred, VR)) {
15340b57cec5SDimitry Andric       StoreSite = Pred;
15350b57cec5SDimitry Andric       InitE = VR->getDecl()->getInit();
15360b57cec5SDimitry Andric     }
15370b57cec5SDimitry Andric   }
15380b57cec5SDimitry Andric 
15390b57cec5SDimitry Andric   // If this is a post initializer expression, initializing the region, we
15400b57cec5SDimitry Andric   // should track the initializer expression.
1541bdd1243dSDimitry Andric   if (std::optional<PostInitializer> PIP =
1542bdd1243dSDimitry Andric           Pred->getLocationAs<PostInitializer>()) {
15430b57cec5SDimitry Andric     const MemRegion *FieldReg = (const MemRegion *)PIP->getLocationValue();
1544a7dea167SDimitry Andric     if (FieldReg == R) {
15450b57cec5SDimitry Andric       StoreSite = Pred;
15460b57cec5SDimitry Andric       InitE = PIP->getInitializer()->getInit();
15470b57cec5SDimitry Andric     }
15480b57cec5SDimitry Andric   }
15490b57cec5SDimitry Andric 
15500b57cec5SDimitry Andric   // Otherwise, see if this is the store site:
15510b57cec5SDimitry Andric   // (1) Succ has this binding and Pred does not, i.e. this is
15520b57cec5SDimitry Andric   //     where the binding first occurred.
15530b57cec5SDimitry Andric   // (2) Succ has this binding and is a PostStore node for this region, i.e.
15540b57cec5SDimitry Andric   //     the same binding was re-assigned here.
15550b57cec5SDimitry Andric   if (!StoreSite) {
15560b57cec5SDimitry Andric     if (Succ->getState()->getSVal(R) != V)
15570b57cec5SDimitry Andric       return nullptr;
15580b57cec5SDimitry Andric 
15590b57cec5SDimitry Andric     if (hasVisibleUpdate(Pred, Pred->getState()->getSVal(R), Succ, V)) {
1560bdd1243dSDimitry Andric       std::optional<PostStore> PS = Succ->getLocationAs<PostStore>();
15610b57cec5SDimitry Andric       if (!PS || PS->getLocationValue() != R)
15620b57cec5SDimitry Andric         return nullptr;
15630b57cec5SDimitry Andric     }
15640b57cec5SDimitry Andric 
15650b57cec5SDimitry Andric     StoreSite = Succ;
15660b57cec5SDimitry Andric 
1567bdd1243dSDimitry Andric     if (std::optional<PostStmt> P = Succ->getLocationAs<PostStmt>()) {
15680b57cec5SDimitry Andric       // If this is an assignment expression, we can track the value
15690b57cec5SDimitry Andric       // being assigned.
1570bdd1243dSDimitry Andric       if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
15710b57cec5SDimitry Andric         if (BO->isAssignmentOp())
15720b57cec5SDimitry Andric           InitE = BO->getRHS();
1573bdd1243dSDimitry Andric       }
1574bdd1243dSDimitry Andric       // If we have a declaration like 'S s{1,2}' that needs special
1575bdd1243dSDimitry Andric       // handling, we handle it here.
1576bdd1243dSDimitry Andric       else if (const auto *DS = P->getStmtAs<DeclStmt>()) {
1577bdd1243dSDimitry Andric         const auto *Decl = DS->getSingleDecl();
1578bdd1243dSDimitry Andric         if (isa<VarDecl>(Decl)) {
1579bdd1243dSDimitry Andric           const auto *VD = cast<VarDecl>(Decl);
1580bdd1243dSDimitry Andric 
1581bdd1243dSDimitry Andric           // FIXME: Here we only track the inner most region, so we lose
1582bdd1243dSDimitry Andric           // information, but it's still better than a crash or no information
1583bdd1243dSDimitry Andric           // at all.
1584bdd1243dSDimitry Andric           //
1585bdd1243dSDimitry Andric           // E.g.: The region we have is 's.s2.s3.s4.y' and we only track 'y',
1586bdd1243dSDimitry Andric           // and throw away the rest.
1587bdd1243dSDimitry Andric           if (const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
1588bdd1243dSDimitry Andric             InitE = tryExtractInitializerFromList(ILE, R);
1589bdd1243dSDimitry Andric         }
1590bdd1243dSDimitry Andric       } else if (const auto *CE = P->getStmtAs<CXXConstructExpr>()) {
1591bdd1243dSDimitry Andric 
1592bdd1243dSDimitry Andric         const auto State = Succ->getState();
1593bdd1243dSDimitry Andric 
1594bdd1243dSDimitry Andric         if (isTrivialCopyOrMoveCtor(CE) && isa<SubRegion>(R)) {
1595bdd1243dSDimitry Andric           // Migrate the field regions from the current object to
1596bdd1243dSDimitry Andric           // the parent object. If we track 'a.y.e' and encounter
1597bdd1243dSDimitry Andric           // 'S a = b' then we need to track 'b.y.e'.
1598bdd1243dSDimitry Andric 
1599bdd1243dSDimitry Andric           // Push the regions to a stack, from last to first, so
1600bdd1243dSDimitry Andric           // considering the example above the stack will look like
1601bdd1243dSDimitry Andric           // (bottom) 'e' -> 'y' (top).
1602bdd1243dSDimitry Andric 
1603bdd1243dSDimitry Andric           std::stack<const SubRegion *> SRStack;
1604bdd1243dSDimitry Andric           const SubRegion *SR = cast<SubRegion>(R);
1605bdd1243dSDimitry Andric           while (isa<FieldRegion>(SR) || isa<ElementRegion>(SR)) {
1606bdd1243dSDimitry Andric             SRStack.push(SR);
1607bdd1243dSDimitry Andric             SR = cast<SubRegion>(SR->getSuperRegion());
1608bdd1243dSDimitry Andric           }
1609bdd1243dSDimitry Andric 
1610bdd1243dSDimitry Andric           // Get the region for the object we copied/moved from.
1611bdd1243dSDimitry Andric           const auto *OriginEx = CE->getArg(0);
1612bdd1243dSDimitry Andric           const auto OriginVal =
1613bdd1243dSDimitry Andric               State->getSVal(OriginEx, Succ->getLocationContext());
1614bdd1243dSDimitry Andric 
1615bdd1243dSDimitry Andric           // Pop the stored field regions and apply them to the origin
1616bdd1243dSDimitry Andric           // object in the same order we had them on the copy.
1617bdd1243dSDimitry Andric           // OriginField will evolve like 'b' -> 'b.y' -> 'b.y.e'.
1618bdd1243dSDimitry Andric           SVal OriginField = OriginVal;
1619bdd1243dSDimitry Andric           while (!SRStack.empty()) {
1620bdd1243dSDimitry Andric             const auto *TopR = SRStack.top();
1621bdd1243dSDimitry Andric             SRStack.pop();
1622bdd1243dSDimitry Andric 
1623bdd1243dSDimitry Andric             if (const auto *FR = dyn_cast<FieldRegion>(TopR)) {
1624bdd1243dSDimitry Andric               OriginField = State->getLValue(FR->getDecl(), OriginField);
1625bdd1243dSDimitry Andric             } else if (const auto *ER = dyn_cast<ElementRegion>(TopR)) {
1626bdd1243dSDimitry Andric               OriginField = State->getLValue(ER->getElementType(),
1627bdd1243dSDimitry Andric                                              ER->getIndex(), OriginField);
1628bdd1243dSDimitry Andric             } else {
1629bdd1243dSDimitry Andric               // FIXME: handle other region type
1630bdd1243dSDimitry Andric             }
1631bdd1243dSDimitry Andric           }
1632bdd1243dSDimitry Andric 
1633bdd1243dSDimitry Andric           // Track 'b.y.e'.
1634bdd1243dSDimitry Andric           getParentTracker().track(V, OriginField.getAsRegion(), Options);
1635bdd1243dSDimitry Andric           InitE = OriginEx;
1636bdd1243dSDimitry Andric         }
1637bdd1243dSDimitry Andric       }
1638bdd1243dSDimitry Andric       // This branch can occur in cases like `Ctor() : field{ x, y } {}'.
1639bdd1243dSDimitry Andric       else if (const auto *ILE = P->getStmtAs<InitListExpr>()) {
1640bdd1243dSDimitry Andric         // FIXME: Here we only track the top level region, so we lose
1641bdd1243dSDimitry Andric         // information, but it's still better than a crash or no information
1642bdd1243dSDimitry Andric         // at all.
1643bdd1243dSDimitry Andric         //
1644bdd1243dSDimitry Andric         // E.g.: The region we have is 's.s2.s3.s4.y' and we only track 'y', and
1645bdd1243dSDimitry Andric         // throw away the rest.
1646bdd1243dSDimitry Andric         InitE = tryExtractInitializerFromList(ILE, R);
1647bdd1243dSDimitry Andric       }
1648bdd1243dSDimitry Andric     }
16490b57cec5SDimitry Andric 
16500b57cec5SDimitry Andric     // If this is a call entry, the variable should be a parameter.
16510b57cec5SDimitry Andric     // FIXME: Handle CXXThisRegion as well. (This is not a priority because
16520b57cec5SDimitry Andric     // 'this' should never be NULL, but this visitor isn't just for NULL and
16530b57cec5SDimitry Andric     // UndefinedVal.)
1654bdd1243dSDimitry Andric     if (std::optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) {
16550b57cec5SDimitry Andric       if (const auto *VR = dyn_cast<VarRegion>(R)) {
16560b57cec5SDimitry Andric 
1657a7dea167SDimitry Andric         if (const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
16580b57cec5SDimitry Andric           ProgramStateManager &StateMgr = BRC.getStateManager();
16590b57cec5SDimitry Andric           CallEventManager &CallMgr = StateMgr.getCallEventManager();
16600b57cec5SDimitry Andric 
16610b57cec5SDimitry Andric           CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(),
16620b57cec5SDimitry Andric                                                   Succ->getState());
16630b57cec5SDimitry Andric           InitE = Call->getArgExpr(Param->getFunctionScopeIndex());
1664a7dea167SDimitry Andric         } else {
1665a7dea167SDimitry Andric           // Handle Objective-C 'self'.
1666a7dea167SDimitry Andric           assert(isa<ImplicitParamDecl>(VR->getDecl()));
1667a7dea167SDimitry Andric           InitE = cast<ObjCMessageExpr>(CE->getCalleeContext()->getCallSite())
1668a7dea167SDimitry Andric                       ->getInstanceReceiver()->IgnoreParenCasts();
1669a7dea167SDimitry Andric         }
16700b57cec5SDimitry Andric         IsParam = true;
16710b57cec5SDimitry Andric       }
16720b57cec5SDimitry Andric     }
16730b57cec5SDimitry Andric 
16740b57cec5SDimitry Andric     // If this is a CXXTempObjectRegion, the Expr responsible for its creation
16750b57cec5SDimitry Andric     // is wrapped inside of it.
16760b57cec5SDimitry Andric     if (const auto *TmpR = dyn_cast<CXXTempObjectRegion>(R))
16770b57cec5SDimitry Andric       InitE = TmpR->getExpr();
16780b57cec5SDimitry Andric   }
16790b57cec5SDimitry Andric 
16800b57cec5SDimitry Andric   if (!StoreSite)
16810b57cec5SDimitry Andric     return nullptr;
1682a7dea167SDimitry Andric 
16830b57cec5SDimitry Andric   Satisfied = true;
16840b57cec5SDimitry Andric 
16850b57cec5SDimitry Andric   // If we have an expression that provided the value, try to track where it
16860b57cec5SDimitry Andric   // came from.
16870b57cec5SDimitry Andric   if (InitE) {
16880b57cec5SDimitry Andric     if (!IsParam)
16890b57cec5SDimitry Andric       InitE = InitE->IgnoreParenCasts();
1690a7dea167SDimitry Andric 
1691fe6060f1SDimitry Andric     getParentTracker().track(InitE, StoreSite, Options);
16920b57cec5SDimitry Andric   }
1693a7dea167SDimitry Andric 
1694fe6060f1SDimitry Andric   // Let's try to find the region where the value came from.
1695fe6060f1SDimitry Andric   const MemRegion *OldRegion = nullptr;
1696fe6060f1SDimitry Andric 
1697fe6060f1SDimitry Andric   // If we have init expression, it might be simply a reference
1698fe6060f1SDimitry Andric   // to a variable, so we can use it.
1699fe6060f1SDimitry Andric   if (InitE) {
1700fe6060f1SDimitry Andric     // That region might still be not exactly what we are looking for.
1701fe6060f1SDimitry Andric     // In situations like `int &ref = val;`, we can't say that
1702fe6060f1SDimitry Andric     // `ref` is initialized with `val`, rather refers to `val`.
1703fe6060f1SDimitry Andric     //
1704fe6060f1SDimitry Andric     // In order, to mitigate situations like this, we check if the last
1705fe6060f1SDimitry Andric     // stored value in that region is the value that we track.
1706fe6060f1SDimitry Andric     //
1707fe6060f1SDimitry Andric     // TODO: support other situations better.
1708fe6060f1SDimitry Andric     if (const MemRegion *Candidate =
1709fe6060f1SDimitry Andric             getLocationRegionIfReference(InitE, Succ, false)) {
1710fe6060f1SDimitry Andric       const StoreManager &SM = BRC.getStateManager().getStoreManager();
1711fe6060f1SDimitry Andric 
1712fe6060f1SDimitry Andric       // Here we traverse the graph up to find the last node where the
1713fe6060f1SDimitry Andric       // candidate region is still in the store.
1714fe6060f1SDimitry Andric       for (const ExplodedNode *N = StoreSite; N; N = N->getFirstPred()) {
1715fe6060f1SDimitry Andric         if (SM.includedInBindings(N->getState()->getStore(), Candidate)) {
1716fe6060f1SDimitry Andric           // And if it was bound to the target value, we can use it.
1717fe6060f1SDimitry Andric           if (N->getState()->getSVal(Candidate) == V) {
1718fe6060f1SDimitry Andric             OldRegion = Candidate;
1719fe6060f1SDimitry Andric           }
1720fe6060f1SDimitry Andric           break;
1721fe6060f1SDimitry Andric         }
1722fe6060f1SDimitry Andric       }
1723fe6060f1SDimitry Andric     }
1724fe6060f1SDimitry Andric   }
1725fe6060f1SDimitry Andric 
1726fe6060f1SDimitry Andric   // Otherwise, if the current region does indeed contain the value
1727fe6060f1SDimitry Andric   // we are looking for, we can look for a region where this value
1728fe6060f1SDimitry Andric   // was before.
1729fe6060f1SDimitry Andric   //
1730fe6060f1SDimitry Andric   // It can be useful for situations like:
1731fe6060f1SDimitry Andric   //     new = identity(old)
1732fe6060f1SDimitry Andric   // where the analyzer knows that 'identity' returns the value of its
1733fe6060f1SDimitry Andric   // first argument.
1734fe6060f1SDimitry Andric   //
1735fe6060f1SDimitry Andric   // NOTE: If the region R is not a simple var region, it can contain
1736fe6060f1SDimitry Andric   //       V in one of its subregions.
1737fe6060f1SDimitry Andric   if (!OldRegion && StoreSite->getState()->getSVal(R) == V) {
1738fe6060f1SDimitry Andric     // Let's go up the graph to find the node where the region is
1739fe6060f1SDimitry Andric     // bound to V.
1740fe6060f1SDimitry Andric     const ExplodedNode *NodeWithoutBinding = StoreSite->getFirstPred();
1741fe6060f1SDimitry Andric     for (;
1742fe6060f1SDimitry Andric          NodeWithoutBinding && NodeWithoutBinding->getState()->getSVal(R) == V;
1743fe6060f1SDimitry Andric          NodeWithoutBinding = NodeWithoutBinding->getFirstPred()) {
1744fe6060f1SDimitry Andric     }
1745fe6060f1SDimitry Andric 
1746fe6060f1SDimitry Andric     if (NodeWithoutBinding) {
1747fe6060f1SDimitry Andric       // Let's try to find a unique binding for the value in that node.
1748fe6060f1SDimitry Andric       // We want to use this to find unique bindings because of the following
1749fe6060f1SDimitry Andric       // situations:
1750fe6060f1SDimitry Andric       //     b = a;
1751fe6060f1SDimitry Andric       //     c = identity(b);
1752fe6060f1SDimitry Andric       //
1753fe6060f1SDimitry Andric       // Telling the user that the value of 'a' is assigned to 'c', while
1754fe6060f1SDimitry Andric       // correct, can be confusing.
1755fe6060f1SDimitry Andric       StoreManager::FindUniqueBinding FB(V.getAsLocSymbol());
1756fe6060f1SDimitry Andric       BRC.getStateManager().iterBindings(NodeWithoutBinding->getState(), FB);
1757fe6060f1SDimitry Andric       if (FB)
1758fe6060f1SDimitry Andric         OldRegion = FB.getRegion();
1759fe6060f1SDimitry Andric     }
1760fe6060f1SDimitry Andric   }
1761fe6060f1SDimitry Andric 
1762fe6060f1SDimitry Andric   if (Options.Kind == TrackingKind::Condition && OriginSFC &&
1763a7dea167SDimitry Andric       !OriginSFC->isParentOf(StoreSite->getStackFrame()))
1764a7dea167SDimitry Andric     return nullptr;
17650b57cec5SDimitry Andric 
17660b57cec5SDimitry Andric   // Okay, we've found the binding. Emit an appropriate message.
17670b57cec5SDimitry Andric   SmallString<256> sbuf;
17680b57cec5SDimitry Andric   llvm::raw_svector_ostream os(sbuf);
17690b57cec5SDimitry Andric 
1770fe6060f1SDimitry Andric   StoreInfo SI = {StoreInfo::Assignment, // default kind
1771fe6060f1SDimitry Andric                   StoreSite,
1772fe6060f1SDimitry Andric                   InitE,
1773fe6060f1SDimitry Andric                   V,
1774fe6060f1SDimitry Andric                   R,
1775fe6060f1SDimitry Andric                   OldRegion};
1776fe6060f1SDimitry Andric 
1777bdd1243dSDimitry Andric   if (std::optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) {
17780b57cec5SDimitry Andric     const Stmt *S = PS->getStmt();
17790b57cec5SDimitry Andric     const auto *DS = dyn_cast<DeclStmt>(S);
17800b57cec5SDimitry Andric     const auto *VR = dyn_cast<VarRegion>(R);
17810b57cec5SDimitry Andric 
17820b57cec5SDimitry Andric     if (DS) {
1783fe6060f1SDimitry Andric       SI.StoreKind = StoreInfo::Initialization;
17840b57cec5SDimitry Andric     } else if (isa<BlockExpr>(S)) {
1785fe6060f1SDimitry Andric       SI.StoreKind = StoreInfo::BlockCapture;
17860b57cec5SDimitry Andric       if (VR) {
17870b57cec5SDimitry Andric         // See if we can get the BlockVarRegion.
17880b57cec5SDimitry Andric         ProgramStateRef State = StoreSite->getState();
17890b57cec5SDimitry Andric         SVal V = StoreSite->getSVal(S);
17900b57cec5SDimitry Andric         if (const auto *BDR =
17910b57cec5SDimitry Andric                 dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
17920b57cec5SDimitry Andric           if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
1793fe6060f1SDimitry Andric             getParentTracker().track(State->getSVal(OriginalR), OriginalR,
1794fe6060f1SDimitry Andric                                      Options, OriginSFC);
17950b57cec5SDimitry Andric           }
17960b57cec5SDimitry Andric         }
17970b57cec5SDimitry Andric       }
17980b57cec5SDimitry Andric     }
1799fe6060f1SDimitry Andric   } else if (SI.StoreSite->getLocation().getAs<CallEnter>() &&
1800fe6060f1SDimitry Andric              isa<VarRegion>(SI.Dest)) {
1801fe6060f1SDimitry Andric     SI.StoreKind = StoreInfo::CallArgument;
18020b57cec5SDimitry Andric   }
18030b57cec5SDimitry Andric 
1804fe6060f1SDimitry Andric   return getParentTracker().handle(SI, BRC, Options);
18050b57cec5SDimitry Andric }
18060b57cec5SDimitry Andric 
18070b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
18080b57cec5SDimitry Andric // Implementation of TrackConstraintBRVisitor.
18090b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
18100b57cec5SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const18110b57cec5SDimitry Andric void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const {
18120b57cec5SDimitry Andric   static int tag = 0;
18130b57cec5SDimitry Andric   ID.AddPointer(&tag);
181406c3fb27SDimitry Andric   ID.AddString(Message);
18150b57cec5SDimitry Andric   ID.AddBoolean(Assumption);
18160b57cec5SDimitry Andric   ID.Add(Constraint);
18170b57cec5SDimitry Andric }
18180b57cec5SDimitry Andric 
18190b57cec5SDimitry Andric /// Return the tag associated with this visitor.  This tag will be used
18200b57cec5SDimitry Andric /// to make all PathDiagnosticPieces created by this visitor.
getTag()18210b57cec5SDimitry Andric const char *TrackConstraintBRVisitor::getTag() {
18220b57cec5SDimitry Andric   return "TrackConstraintBRVisitor";
18230b57cec5SDimitry Andric }
18240b57cec5SDimitry Andric 
isZeroCheck() const182506c3fb27SDimitry Andric bool TrackConstraintBRVisitor::isZeroCheck() const {
182606c3fb27SDimitry Andric   return !Assumption && Constraint.getAs<Loc>();
182706c3fb27SDimitry Andric }
182806c3fb27SDimitry Andric 
isUnderconstrained(const ExplodedNode * N) const18290b57cec5SDimitry Andric bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const {
183006c3fb27SDimitry Andric   if (isZeroCheck())
18310b57cec5SDimitry Andric     return N->getState()->isNull(Constraint).isUnderconstrained();
18320b57cec5SDimitry Andric   return (bool)N->getState()->assume(Constraint, !Assumption);
18330b57cec5SDimitry Andric }
18340b57cec5SDimitry Andric 
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport &)1835a7dea167SDimitry Andric PathDiagnosticPieceRef TrackConstraintBRVisitor::VisitNode(
1836a7dea167SDimitry Andric     const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &) {
18370b57cec5SDimitry Andric   const ExplodedNode *PrevN = N->getFirstPred();
18380b57cec5SDimitry Andric   if (IsSatisfied)
18390b57cec5SDimitry Andric     return nullptr;
18400b57cec5SDimitry Andric 
18410b57cec5SDimitry Andric   // Start tracking after we see the first state in which the value is
18420b57cec5SDimitry Andric   // constrained.
18430b57cec5SDimitry Andric   if (!IsTrackingTurnedOn)
18440b57cec5SDimitry Andric     if (!isUnderconstrained(N))
18450b57cec5SDimitry Andric       IsTrackingTurnedOn = true;
18460b57cec5SDimitry Andric   if (!IsTrackingTurnedOn)
18470b57cec5SDimitry Andric     return nullptr;
18480b57cec5SDimitry Andric 
18490b57cec5SDimitry Andric   // Check if in the previous state it was feasible for this constraint
18500b57cec5SDimitry Andric   // to *not* be true.
18510b57cec5SDimitry Andric   if (isUnderconstrained(PrevN)) {
18520b57cec5SDimitry Andric     IsSatisfied = true;
18530b57cec5SDimitry Andric 
18545e801ac6SDimitry Andric     // At this point, the negation of the constraint should be infeasible. If it
18555e801ac6SDimitry Andric     // is feasible, make sure that the negation of the constrainti was
18565e801ac6SDimitry Andric     // infeasible in the current state.  If it is feasible, we somehow missed
18575e801ac6SDimitry Andric     // the transition point.
18580b57cec5SDimitry Andric     assert(!isUnderconstrained(N));
18590b57cec5SDimitry Andric 
18600b57cec5SDimitry Andric     // Construct a new PathDiagnosticPiece.
18610b57cec5SDimitry Andric     ProgramPoint P = N->getLocation();
186281ad6265SDimitry Andric 
186381ad6265SDimitry Andric     // If this node already have a specialized note, it's probably better
186481ad6265SDimitry Andric     // than our generic note.
186581ad6265SDimitry Andric     // FIXME: This only looks for note tags, not for other ways to add a note.
186681ad6265SDimitry Andric     if (isa_and_nonnull<NoteTag>(P.getTag()))
186781ad6265SDimitry Andric       return nullptr;
186881ad6265SDimitry Andric 
18690b57cec5SDimitry Andric     PathDiagnosticLocation L =
18700b57cec5SDimitry Andric       PathDiagnosticLocation::create(P, BRC.getSourceManager());
18710b57cec5SDimitry Andric     if (!L.isValid())
18720b57cec5SDimitry Andric       return nullptr;
18730b57cec5SDimitry Andric 
187406c3fb27SDimitry Andric     auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message);
18750b57cec5SDimitry Andric     X->setTag(getTag());
18760b57cec5SDimitry Andric     return std::move(X);
18770b57cec5SDimitry Andric   }
18780b57cec5SDimitry Andric 
18790b57cec5SDimitry Andric   return nullptr;
18800b57cec5SDimitry Andric }
18810b57cec5SDimitry Andric 
18820b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
18830b57cec5SDimitry Andric // Implementation of SuppressInlineDefensiveChecksVisitor.
18840b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
18850b57cec5SDimitry Andric 
18860b57cec5SDimitry Andric SuppressInlineDefensiveChecksVisitor::
SuppressInlineDefensiveChecksVisitor(DefinedSVal Value,const ExplodedNode * N)18870b57cec5SDimitry Andric SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N)
18880b57cec5SDimitry Andric     : V(Value) {
18890b57cec5SDimitry Andric   // Check if the visitor is disabled.
18900b57cec5SDimitry Andric   AnalyzerOptions &Options = N->getState()->getAnalysisManager().options;
18910b57cec5SDimitry Andric   if (!Options.ShouldSuppressInlinedDefensiveChecks)
18920b57cec5SDimitry Andric     IsSatisfied = true;
18930b57cec5SDimitry Andric }
18940b57cec5SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const18950b57cec5SDimitry Andric void SuppressInlineDefensiveChecksVisitor::Profile(
18960b57cec5SDimitry Andric     llvm::FoldingSetNodeID &ID) const {
18970b57cec5SDimitry Andric   static int id = 0;
18980b57cec5SDimitry Andric   ID.AddPointer(&id);
18990b57cec5SDimitry Andric   ID.Add(V);
19000b57cec5SDimitry Andric }
19010b57cec5SDimitry Andric 
getTag()19020b57cec5SDimitry Andric const char *SuppressInlineDefensiveChecksVisitor::getTag() {
19030b57cec5SDimitry Andric   return "IDCVisitor";
19040b57cec5SDimitry Andric }
19050b57cec5SDimitry Andric 
1906a7dea167SDimitry Andric PathDiagnosticPieceRef
VisitNode(const ExplodedNode * Succ,BugReporterContext & BRC,PathSensitiveBugReport & BR)19070b57cec5SDimitry Andric SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
19080b57cec5SDimitry Andric                                                 BugReporterContext &BRC,
1909a7dea167SDimitry Andric                                                 PathSensitiveBugReport &BR) {
19100b57cec5SDimitry Andric   const ExplodedNode *Pred = Succ->getFirstPred();
19110b57cec5SDimitry Andric   if (IsSatisfied)
19120b57cec5SDimitry Andric     return nullptr;
19130b57cec5SDimitry Andric 
19140b57cec5SDimitry Andric   // Start tracking after we see the first state in which the value is null.
19150b57cec5SDimitry Andric   if (!IsTrackingTurnedOn)
19160b57cec5SDimitry Andric     if (Succ->getState()->isNull(V).isConstrainedTrue())
19170b57cec5SDimitry Andric       IsTrackingTurnedOn = true;
19180b57cec5SDimitry Andric   if (!IsTrackingTurnedOn)
19190b57cec5SDimitry Andric     return nullptr;
19200b57cec5SDimitry Andric 
19210b57cec5SDimitry Andric   // Check if in the previous state it was feasible for this value
19220b57cec5SDimitry Andric   // to *not* be null.
1923480093f4SDimitry Andric   if (!Pred->getState()->isNull(V).isConstrainedTrue() &&
1924480093f4SDimitry Andric       Succ->getState()->isNull(V).isConstrainedTrue()) {
19250b57cec5SDimitry Andric     IsSatisfied = true;
19260b57cec5SDimitry Andric 
19270b57cec5SDimitry Andric     // Check if this is inlined defensive checks.
19280b57cec5SDimitry Andric     const LocationContext *CurLC = Succ->getLocationContext();
19290b57cec5SDimitry Andric     const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext();
19300b57cec5SDimitry Andric     if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) {
19310b57cec5SDimitry Andric       BR.markInvalid("Suppress IDC", CurLC);
19320b57cec5SDimitry Andric       return nullptr;
19330b57cec5SDimitry Andric     }
19340b57cec5SDimitry Andric 
19350b57cec5SDimitry Andric     // Treat defensive checks in function-like macros as if they were an inlined
19360b57cec5SDimitry Andric     // defensive check. If the bug location is not in a macro and the
19370b57cec5SDimitry Andric     // terminator for the current location is in a macro then suppress the
19380b57cec5SDimitry Andric     // warning.
19390b57cec5SDimitry Andric     auto BugPoint = BR.getErrorNode()->getLocation().getAs<StmtPoint>();
19400b57cec5SDimitry Andric 
19410b57cec5SDimitry Andric     if (!BugPoint)
19420b57cec5SDimitry Andric       return nullptr;
19430b57cec5SDimitry Andric 
19440b57cec5SDimitry Andric     ProgramPoint CurPoint = Succ->getLocation();
19450b57cec5SDimitry Andric     const Stmt *CurTerminatorStmt = nullptr;
19460b57cec5SDimitry Andric     if (auto BE = CurPoint.getAs<BlockEdge>()) {
19470b57cec5SDimitry Andric       CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
19480b57cec5SDimitry Andric     } else if (auto SP = CurPoint.getAs<StmtPoint>()) {
19490b57cec5SDimitry Andric       const Stmt *CurStmt = SP->getStmt();
19500b57cec5SDimitry Andric       if (!CurStmt->getBeginLoc().isMacroID())
19510b57cec5SDimitry Andric         return nullptr;
19520b57cec5SDimitry Andric 
19530b57cec5SDimitry Andric       CFGStmtMap *Map = CurLC->getAnalysisDeclContext()->getCFGStmtMap();
19540b57cec5SDimitry Andric       CurTerminatorStmt = Map->getBlock(CurStmt)->getTerminatorStmt();
19550b57cec5SDimitry Andric     } else {
19560b57cec5SDimitry Andric       return nullptr;
19570b57cec5SDimitry Andric     }
19580b57cec5SDimitry Andric 
19590b57cec5SDimitry Andric     if (!CurTerminatorStmt)
19600b57cec5SDimitry Andric       return nullptr;
19610b57cec5SDimitry Andric 
19620b57cec5SDimitry Andric     SourceLocation TerminatorLoc = CurTerminatorStmt->getBeginLoc();
19630b57cec5SDimitry Andric     if (TerminatorLoc.isMacroID()) {
19640b57cec5SDimitry Andric       SourceLocation BugLoc = BugPoint->getStmt()->getBeginLoc();
19650b57cec5SDimitry Andric 
19660b57cec5SDimitry Andric       // Suppress reports unless we are in that same macro.
19670b57cec5SDimitry Andric       if (!BugLoc.isMacroID() ||
19680b57cec5SDimitry Andric           getMacroName(BugLoc, BRC) != getMacroName(TerminatorLoc, BRC)) {
19690b57cec5SDimitry Andric         BR.markInvalid("Suppress Macro IDC", CurLC);
19700b57cec5SDimitry Andric       }
19710b57cec5SDimitry Andric       return nullptr;
19720b57cec5SDimitry Andric     }
19730b57cec5SDimitry Andric   }
19740b57cec5SDimitry Andric   return nullptr;
19750b57cec5SDimitry Andric }
19760b57cec5SDimitry Andric 
19770b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
19780b57cec5SDimitry Andric // TrackControlDependencyCondBRVisitor.
19790b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
19800b57cec5SDimitry Andric 
19810b57cec5SDimitry Andric namespace {
19820b57cec5SDimitry Andric /// Tracks the expressions that are a control dependency of the node that was
19830b57cec5SDimitry Andric /// supplied to the constructor.
19840b57cec5SDimitry Andric /// For example:
19850b57cec5SDimitry Andric ///
19860b57cec5SDimitry Andric ///   cond = 1;
19870b57cec5SDimitry Andric ///   if (cond)
19880b57cec5SDimitry Andric ///     10 / 0;
19890b57cec5SDimitry Andric ///
19900b57cec5SDimitry Andric /// An error is emitted at line 3. This visitor realizes that the branch
19910b57cec5SDimitry Andric /// on line 2 is a control dependency of line 3, and tracks it's condition via
19920b57cec5SDimitry Andric /// trackExpressionValue().
1993fe6060f1SDimitry Andric class TrackControlDependencyCondBRVisitor final
1994fe6060f1SDimitry Andric     : public TrackingBugReporterVisitor {
19950b57cec5SDimitry Andric   const ExplodedNode *Origin;
19960b57cec5SDimitry Andric   ControlDependencyCalculator ControlDeps;
19970b57cec5SDimitry Andric   llvm::SmallSet<const CFGBlock *, 32> VisitedBlocks;
19980b57cec5SDimitry Andric 
19990b57cec5SDimitry Andric public:
TrackControlDependencyCondBRVisitor(TrackerRef ParentTracker,const ExplodedNode * O)2000fe6060f1SDimitry Andric   TrackControlDependencyCondBRVisitor(TrackerRef ParentTracker,
2001fe6060f1SDimitry Andric                                       const ExplodedNode *O)
2002fe6060f1SDimitry Andric       : TrackingBugReporterVisitor(ParentTracker), Origin(O),
2003fe6060f1SDimitry Andric         ControlDeps(&O->getCFG()) {}
20040b57cec5SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const20050b57cec5SDimitry Andric   void Profile(llvm::FoldingSetNodeID &ID) const override {
20060b57cec5SDimitry Andric     static int x = 0;
20070b57cec5SDimitry Andric     ID.AddPointer(&x);
20080b57cec5SDimitry Andric   }
20090b57cec5SDimitry Andric 
2010a7dea167SDimitry Andric   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
20110b57cec5SDimitry Andric                                    BugReporterContext &BRC,
2012a7dea167SDimitry Andric                                    PathSensitiveBugReport &BR) override;
20130b57cec5SDimitry Andric };
20140b57cec5SDimitry Andric } // end of anonymous namespace
20150b57cec5SDimitry Andric 
20160b57cec5SDimitry Andric static std::shared_ptr<PathDiagnosticEventPiece>
constructDebugPieceForTrackedCondition(const Expr * Cond,const ExplodedNode * N,BugReporterContext & BRC)20170b57cec5SDimitry Andric constructDebugPieceForTrackedCondition(const Expr *Cond,
20180b57cec5SDimitry Andric                                        const ExplodedNode *N,
20190b57cec5SDimitry Andric                                        BugReporterContext &BRC) {
20200b57cec5SDimitry Andric 
20210b57cec5SDimitry Andric   if (BRC.getAnalyzerOptions().AnalysisDiagOpt == PD_NONE ||
20220b57cec5SDimitry Andric       !BRC.getAnalyzerOptions().ShouldTrackConditionsDebug)
20230b57cec5SDimitry Andric     return nullptr;
20240b57cec5SDimitry Andric 
20255ffd83dbSDimitry Andric   std::string ConditionText = std::string(Lexer::getSourceText(
20260b57cec5SDimitry Andric       CharSourceRange::getTokenRange(Cond->getSourceRange()),
20275ffd83dbSDimitry Andric       BRC.getSourceManager(), BRC.getASTContext().getLangOpts()));
20280b57cec5SDimitry Andric 
20290b57cec5SDimitry Andric   return std::make_shared<PathDiagnosticEventPiece>(
20300b57cec5SDimitry Andric       PathDiagnosticLocation::createBegin(
20310b57cec5SDimitry Andric           Cond, BRC.getSourceManager(), N->getLocationContext()),
20320b57cec5SDimitry Andric           (Twine() + "Tracking condition '" + ConditionText + "'").str());
20330b57cec5SDimitry Andric }
20340b57cec5SDimitry Andric 
isAssertlikeBlock(const CFGBlock * B,ASTContext & Context)2035a7dea167SDimitry Andric static bool isAssertlikeBlock(const CFGBlock *B, ASTContext &Context) {
2036a7dea167SDimitry Andric   if (B->succ_size() != 2)
2037a7dea167SDimitry Andric     return false;
2038a7dea167SDimitry Andric 
2039a7dea167SDimitry Andric   const CFGBlock *Then = B->succ_begin()->getReachableBlock();
2040a7dea167SDimitry Andric   const CFGBlock *Else = (B->succ_begin() + 1)->getReachableBlock();
2041a7dea167SDimitry Andric 
2042a7dea167SDimitry Andric   if (!Then || !Else)
2043a7dea167SDimitry Andric     return false;
2044a7dea167SDimitry Andric 
2045a7dea167SDimitry Andric   if (Then->isInevitablySinking() != Else->isInevitablySinking())
2046a7dea167SDimitry Andric     return true;
2047a7dea167SDimitry Andric 
2048a7dea167SDimitry Andric   // For the following condition the following CFG would be built:
2049a7dea167SDimitry Andric   //
2050a7dea167SDimitry Andric   //                          ------------->
2051a7dea167SDimitry Andric   //                         /              \
2052a7dea167SDimitry Andric   //                       [B1] -> [B2] -> [B3] -> [sink]
2053a7dea167SDimitry Andric   // assert(A && B || C);            \       \
2054a7dea167SDimitry Andric   //                                  -----------> [go on with the execution]
2055a7dea167SDimitry Andric   //
2056a7dea167SDimitry Andric   // It so happens that CFGBlock::getTerminatorCondition returns 'A' for block
2057a7dea167SDimitry Andric   // B1, 'A && B' for B2, and 'A && B || C' for B3. Let's check whether we
2058a7dea167SDimitry Andric   // reached the end of the condition!
2059a7dea167SDimitry Andric   if (const Stmt *ElseCond = Else->getTerminatorCondition())
2060a7dea167SDimitry Andric     if (const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
2061a7dea167SDimitry Andric       if (BinOp->isLogicalOp())
2062a7dea167SDimitry Andric         return isAssertlikeBlock(Else, Context);
2063a7dea167SDimitry Andric 
2064a7dea167SDimitry Andric   return false;
2065a7dea167SDimitry Andric }
2066a7dea167SDimitry Andric 
2067a7dea167SDimitry Andric PathDiagnosticPieceRef
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)20680b57cec5SDimitry Andric TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N,
20690b57cec5SDimitry Andric                                                BugReporterContext &BRC,
2070a7dea167SDimitry Andric                                                PathSensitiveBugReport &BR) {
20710b57cec5SDimitry Andric   // We can only reason about control dependencies within the same stack frame.
20720b57cec5SDimitry Andric   if (Origin->getStackFrame() != N->getStackFrame())
20730b57cec5SDimitry Andric     return nullptr;
20740b57cec5SDimitry Andric 
2075a7dea167SDimitry Andric   CFGBlock *NB = const_cast<CFGBlock *>(N->getCFGBlock());
20760b57cec5SDimitry Andric 
20770b57cec5SDimitry Andric   // Skip if we already inspected this block.
20780b57cec5SDimitry Andric   if (!VisitedBlocks.insert(NB).second)
20790b57cec5SDimitry Andric     return nullptr;
20800b57cec5SDimitry Andric 
2081a7dea167SDimitry Andric   CFGBlock *OriginB = const_cast<CFGBlock *>(Origin->getCFGBlock());
20820b57cec5SDimitry Andric 
20830b57cec5SDimitry Andric   // TODO: Cache CFGBlocks for each ExplodedNode.
20840b57cec5SDimitry Andric   if (!OriginB || !NB)
20850b57cec5SDimitry Andric     return nullptr;
20860b57cec5SDimitry Andric 
2087a7dea167SDimitry Andric   if (isAssertlikeBlock(NB, BRC.getASTContext()))
2088a7dea167SDimitry Andric     return nullptr;
2089a7dea167SDimitry Andric 
20900b57cec5SDimitry Andric   if (ControlDeps.isControlDependent(OriginB, NB)) {
2091a7dea167SDimitry Andric     // We don't really want to explain for range loops. Evidence suggests that
2092a7dea167SDimitry Andric     // the only thing that leads to is the addition of calls to operator!=.
2093a7dea167SDimitry Andric     if (llvm::isa_and_nonnull<CXXForRangeStmt>(NB->getTerminatorStmt()))
2094a7dea167SDimitry Andric       return nullptr;
2095a7dea167SDimitry Andric 
20960b57cec5SDimitry Andric     if (const Expr *Condition = NB->getLastCondition()) {
209781ad6265SDimitry Andric 
209881ad6265SDimitry Andric       // If we can't retrieve a sensible condition, just bail out.
209981ad6265SDimitry Andric       const Expr *InnerExpr = peelOffOuterExpr(Condition, N);
210081ad6265SDimitry Andric       if (!InnerExpr)
210181ad6265SDimitry Andric         return nullptr;
210281ad6265SDimitry Andric 
210381ad6265SDimitry Andric       // If the condition was a function call, we likely won't gain much from
210481ad6265SDimitry Andric       // tracking it either. Evidence suggests that it will mostly trigger in
210581ad6265SDimitry Andric       // scenarios like this:
210681ad6265SDimitry Andric       //
210781ad6265SDimitry Andric       //   void f(int *x) {
210881ad6265SDimitry Andric       //     x = nullptr;
210981ad6265SDimitry Andric       //     if (alwaysTrue()) // We don't need a whole lot of explanation
211081ad6265SDimitry Andric       //                       // here, the function name is good enough.
211181ad6265SDimitry Andric       //       *x = 5;
211281ad6265SDimitry Andric       //   }
211381ad6265SDimitry Andric       //
211481ad6265SDimitry Andric       // Its easy to create a counterexample where this heuristic would make us
211581ad6265SDimitry Andric       // lose valuable information, but we've never really seen one in practice.
211681ad6265SDimitry Andric       if (isa<CallExpr>(InnerExpr))
211781ad6265SDimitry Andric         return nullptr;
211881ad6265SDimitry Andric 
21190b57cec5SDimitry Andric       // Keeping track of the already tracked conditions on a visitor level
21200b57cec5SDimitry Andric       // isn't sufficient, because a new visitor is created for each tracked
21210b57cec5SDimitry Andric       // expression, hence the BugReport level set.
21220b57cec5SDimitry Andric       if (BR.addTrackedCondition(N)) {
212381ad6265SDimitry Andric         getParentTracker().track(InnerExpr, N,
2124fe6060f1SDimitry Andric                                  {bugreporter::TrackingKind::Condition,
2125fe6060f1SDimitry Andric                                   /*EnableNullFPSuppression=*/false});
21260b57cec5SDimitry Andric         return constructDebugPieceForTrackedCondition(Condition, N, BRC);
21270b57cec5SDimitry Andric       }
21280b57cec5SDimitry Andric     }
21290b57cec5SDimitry Andric   }
21300b57cec5SDimitry Andric 
21310b57cec5SDimitry Andric   return nullptr;
21320b57cec5SDimitry Andric }
21330b57cec5SDimitry Andric 
21340b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
21350b57cec5SDimitry Andric // Implementation of trackExpressionValue.
21360b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
21370b57cec5SDimitry Andric 
peelOffOuterExpr(const Expr * Ex,const ExplodedNode * N)213881ad6265SDimitry Andric static const Expr *peelOffOuterExpr(const Expr *Ex, const ExplodedNode *N) {
213981ad6265SDimitry Andric 
21400b57cec5SDimitry Andric   Ex = Ex->IgnoreParenCasts();
21410b57cec5SDimitry Andric   if (const auto *FE = dyn_cast<FullExpr>(Ex))
21420b57cec5SDimitry Andric     return peelOffOuterExpr(FE->getSubExpr(), N);
21430b57cec5SDimitry Andric   if (const auto *OVE = dyn_cast<OpaqueValueExpr>(Ex))
21440b57cec5SDimitry Andric     return peelOffOuterExpr(OVE->getSourceExpr(), N);
21450b57cec5SDimitry Andric   if (const auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) {
21460b57cec5SDimitry Andric     const auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
21470b57cec5SDimitry Andric     if (PropRef && PropRef->isMessagingGetter()) {
21480b57cec5SDimitry Andric       const Expr *GetterMessageSend =
21490b57cec5SDimitry Andric           POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
21500b57cec5SDimitry Andric       assert(isa<ObjCMessageExpr>(GetterMessageSend->IgnoreParenCasts()));
21510b57cec5SDimitry Andric       return peelOffOuterExpr(GetterMessageSend, N);
21520b57cec5SDimitry Andric     }
21530b57cec5SDimitry Andric   }
21540b57cec5SDimitry Andric 
21550b57cec5SDimitry Andric   // Peel off the ternary operator.
21560b57cec5SDimitry Andric   if (const auto *CO = dyn_cast<ConditionalOperator>(Ex)) {
21570b57cec5SDimitry Andric     // Find a node where the branching occurred and find out which branch
21580b57cec5SDimitry Andric     // we took (true/false) by looking at the ExplodedGraph.
21590b57cec5SDimitry Andric     const ExplodedNode *NI = N;
21600b57cec5SDimitry Andric     do {
21610b57cec5SDimitry Andric       ProgramPoint ProgPoint = NI->getLocation();
2162bdd1243dSDimitry Andric       if (std::optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
21630b57cec5SDimitry Andric         const CFGBlock *srcBlk = BE->getSrc();
21640b57cec5SDimitry Andric         if (const Stmt *term = srcBlk->getTerminatorStmt()) {
21650b57cec5SDimitry Andric           if (term == CO) {
21660b57cec5SDimitry Andric             bool TookTrueBranch = (*(srcBlk->succ_begin()) == BE->getDst());
21670b57cec5SDimitry Andric             if (TookTrueBranch)
21680b57cec5SDimitry Andric               return peelOffOuterExpr(CO->getTrueExpr(), N);
21690b57cec5SDimitry Andric             else
21700b57cec5SDimitry Andric               return peelOffOuterExpr(CO->getFalseExpr(), N);
21710b57cec5SDimitry Andric           }
21720b57cec5SDimitry Andric         }
21730b57cec5SDimitry Andric       }
21740b57cec5SDimitry Andric       NI = NI->getFirstPred();
21750b57cec5SDimitry Andric     } while (NI);
21760b57cec5SDimitry Andric   }
21770b57cec5SDimitry Andric 
21780b57cec5SDimitry Andric   if (auto *BO = dyn_cast<BinaryOperator>(Ex))
21790b57cec5SDimitry Andric     if (const Expr *SubEx = peelOffPointerArithmetic(BO))
21800b57cec5SDimitry Andric       return peelOffOuterExpr(SubEx, N);
21810b57cec5SDimitry Andric 
21820b57cec5SDimitry Andric   if (auto *UO = dyn_cast<UnaryOperator>(Ex)) {
21830b57cec5SDimitry Andric     if (UO->getOpcode() == UO_LNot)
21840b57cec5SDimitry Andric       return peelOffOuterExpr(UO->getSubExpr(), N);
21850b57cec5SDimitry Andric 
21860b57cec5SDimitry Andric     // FIXME: There's a hack in our Store implementation that always computes
21870b57cec5SDimitry Andric     // field offsets around null pointers as if they are always equal to 0.
21880b57cec5SDimitry Andric     // The idea here is to report accesses to fields as null dereferences
21890b57cec5SDimitry Andric     // even though the pointer value that's being dereferenced is actually
21900b57cec5SDimitry Andric     // the offset of the field rather than exactly 0.
21910b57cec5SDimitry Andric     // See the FIXME in StoreManager's getLValueFieldOrIvar() method.
21920b57cec5SDimitry Andric     // This code interacts heavily with this hack; otherwise the value
21930b57cec5SDimitry Andric     // would not be null at all for most fields, so we'd be unable to track it.
21940b57cec5SDimitry Andric     if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
21950b57cec5SDimitry Andric       if (const Expr *DerefEx = bugreporter::getDerefExpr(UO->getSubExpr()))
21960b57cec5SDimitry Andric         return peelOffOuterExpr(DerefEx, N);
21970b57cec5SDimitry Andric   }
21980b57cec5SDimitry Andric 
21990b57cec5SDimitry Andric   return Ex;
22000b57cec5SDimitry Andric }
22010b57cec5SDimitry Andric 
22020b57cec5SDimitry Andric /// Find the ExplodedNode where the lvalue (the value of 'Ex')
22030b57cec5SDimitry Andric /// was computed.
findNodeForExpression(const ExplodedNode * N,const Expr * Inner)22040b57cec5SDimitry Andric static const ExplodedNode* findNodeForExpression(const ExplodedNode *N,
22050b57cec5SDimitry Andric                                                  const Expr *Inner) {
22060b57cec5SDimitry Andric   while (N) {
2207a7dea167SDimitry Andric     if (N->getStmtForDiagnostics() == Inner)
22080b57cec5SDimitry Andric       return N;
22090b57cec5SDimitry Andric     N = N->getFirstPred();
22100b57cec5SDimitry Andric   }
22110b57cec5SDimitry Andric   return N;
22120b57cec5SDimitry Andric }
22130b57cec5SDimitry Andric 
2214fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
2215fe6060f1SDimitry Andric //                            Tracker implementation
2216fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
2217a7dea167SDimitry Andric 
constructNote(StoreInfo SI,BugReporterContext & BRC,StringRef NodeText)2218fe6060f1SDimitry Andric PathDiagnosticPieceRef StoreHandler::constructNote(StoreInfo SI,
2219fe6060f1SDimitry Andric                                                    BugReporterContext &BRC,
2220fe6060f1SDimitry Andric                                                    StringRef NodeText) {
2221fe6060f1SDimitry Andric   // Construct a new PathDiagnosticPiece.
2222fe6060f1SDimitry Andric   ProgramPoint P = SI.StoreSite->getLocation();
2223fe6060f1SDimitry Andric   PathDiagnosticLocation L;
2224fe6060f1SDimitry Andric   if (P.getAs<CallEnter>() && SI.SourceOfTheValue)
2225fe6060f1SDimitry Andric     L = PathDiagnosticLocation(SI.SourceOfTheValue, BRC.getSourceManager(),
2226fe6060f1SDimitry Andric                                P.getLocationContext());
22270b57cec5SDimitry Andric 
2228fe6060f1SDimitry Andric   if (!L.isValid() || !L.asLocation().isValid())
2229fe6060f1SDimitry Andric     L = PathDiagnosticLocation::create(P, BRC.getSourceManager());
22300b57cec5SDimitry Andric 
2231fe6060f1SDimitry Andric   if (!L.isValid() || !L.asLocation().isValid())
2232fe6060f1SDimitry Andric     return nullptr;
2233fe6060f1SDimitry Andric 
2234fe6060f1SDimitry Andric   return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
2235fe6060f1SDimitry Andric }
2236fe6060f1SDimitry Andric 
2237bdd1243dSDimitry Andric namespace {
2238fe6060f1SDimitry Andric class DefaultStoreHandler final : public StoreHandler {
2239fe6060f1SDimitry Andric public:
2240fe6060f1SDimitry Andric   using StoreHandler::StoreHandler;
2241fe6060f1SDimitry Andric 
handle(StoreInfo SI,BugReporterContext & BRC,TrackingOptions Opts)2242fe6060f1SDimitry Andric   PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC,
2243fe6060f1SDimitry Andric                                 TrackingOptions Opts) override {
2244fe6060f1SDimitry Andric     // Okay, we've found the binding. Emit an appropriate message.
2245fe6060f1SDimitry Andric     SmallString<256> Buffer;
2246fe6060f1SDimitry Andric     llvm::raw_svector_ostream OS(Buffer);
2247fe6060f1SDimitry Andric 
2248fe6060f1SDimitry Andric     switch (SI.StoreKind) {
2249fe6060f1SDimitry Andric     case StoreInfo::Initialization:
2250fe6060f1SDimitry Andric     case StoreInfo::BlockCapture:
2251fe6060f1SDimitry Andric       showBRDiagnostics(OS, SI);
2252fe6060f1SDimitry Andric       break;
2253fe6060f1SDimitry Andric     case StoreInfo::CallArgument:
2254fe6060f1SDimitry Andric       showBRParamDiagnostics(OS, SI);
2255fe6060f1SDimitry Andric       break;
2256fe6060f1SDimitry Andric     case StoreInfo::Assignment:
2257fe6060f1SDimitry Andric       showBRDefaultDiagnostics(OS, SI);
2258fe6060f1SDimitry Andric       break;
2259fe6060f1SDimitry Andric     }
2260fe6060f1SDimitry Andric 
2261fe6060f1SDimitry Andric     if (Opts.Kind == bugreporter::TrackingKind::Condition)
2262fe6060f1SDimitry Andric       OS << WillBeUsedForACondition;
2263fe6060f1SDimitry Andric 
2264fe6060f1SDimitry Andric     return constructNote(SI, BRC, OS.str());
2265fe6060f1SDimitry Andric   }
2266fe6060f1SDimitry Andric };
2267fe6060f1SDimitry Andric 
2268fe6060f1SDimitry Andric class ControlDependencyHandler final : public ExpressionHandler {
2269fe6060f1SDimitry Andric public:
2270fe6060f1SDimitry Andric   using ExpressionHandler::ExpressionHandler;
2271fe6060f1SDimitry Andric 
handle(const Expr * Inner,const ExplodedNode * InputNode,const ExplodedNode * LVNode,TrackingOptions Opts)2272fe6060f1SDimitry Andric   Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
2273fe6060f1SDimitry Andric                          const ExplodedNode *LVNode,
2274fe6060f1SDimitry Andric                          TrackingOptions Opts) override {
2275fe6060f1SDimitry Andric     PathSensitiveBugReport &Report = getParentTracker().getReport();
22760b57cec5SDimitry Andric 
22770b57cec5SDimitry Andric     // We only track expressions if we believe that they are important. Chances
2278fe6060f1SDimitry Andric     // are good that control dependencies to the tracking point are also
2279fe6060f1SDimitry Andric     // important because of this, let's explain why we believe control reached
2280fe6060f1SDimitry Andric     // this point.
2281fe6060f1SDimitry Andric     // TODO: Shouldn't we track control dependencies of every bug location,
2282fe6060f1SDimitry Andric     // rather than only tracked expressions?
2283fe6060f1SDimitry Andric     if (LVNode->getState()
2284fe6060f1SDimitry Andric             ->getAnalysisManager()
2285fe6060f1SDimitry Andric             .getAnalyzerOptions()
2286fe6060f1SDimitry Andric             .ShouldTrackConditions) {
2287fe6060f1SDimitry Andric       Report.addVisitor<TrackControlDependencyCondBRVisitor>(
2288fe6060f1SDimitry Andric           &getParentTracker(), InputNode);
2289fe6060f1SDimitry Andric       return {/*FoundSomethingToTrack=*/true};
2290fe6060f1SDimitry Andric     }
22910b57cec5SDimitry Andric 
2292fe6060f1SDimitry Andric     return {};
2293fe6060f1SDimitry Andric   }
2294fe6060f1SDimitry Andric };
2295fe6060f1SDimitry Andric 
2296fe6060f1SDimitry Andric class NilReceiverHandler final : public ExpressionHandler {
2297fe6060f1SDimitry Andric public:
2298fe6060f1SDimitry Andric   using ExpressionHandler::ExpressionHandler;
2299fe6060f1SDimitry Andric 
handle(const Expr * Inner,const ExplodedNode * InputNode,const ExplodedNode * LVNode,TrackingOptions Opts)2300fe6060f1SDimitry Andric   Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
2301fe6060f1SDimitry Andric                          const ExplodedNode *LVNode,
2302fe6060f1SDimitry Andric                          TrackingOptions Opts) override {
23030b57cec5SDimitry Andric     // The message send could be nil due to the receiver being nil.
2304fe6060f1SDimitry Andric     // At this point in the path, the receiver should be live since we are at
2305fe6060f1SDimitry Andric     // the message send expr. If it is nil, start tracking it.
2306fe6060f1SDimitry Andric     if (const Expr *Receiver =
2307fe6060f1SDimitry Andric             NilReceiverBRVisitor::getNilReceiver(Inner, LVNode))
2308fe6060f1SDimitry Andric       return getParentTracker().track(Receiver, LVNode, Opts);
23090b57cec5SDimitry Andric 
2310fe6060f1SDimitry Andric     return {};
2311fe6060f1SDimitry Andric   }
2312fe6060f1SDimitry Andric };
2313fe6060f1SDimitry Andric 
2314fe6060f1SDimitry Andric class ArrayIndexHandler final : public ExpressionHandler {
2315fe6060f1SDimitry Andric public:
2316fe6060f1SDimitry Andric   using ExpressionHandler::ExpressionHandler;
2317fe6060f1SDimitry Andric 
handle(const Expr * Inner,const ExplodedNode * InputNode,const ExplodedNode * LVNode,TrackingOptions Opts)2318fe6060f1SDimitry Andric   Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
2319fe6060f1SDimitry Andric                          const ExplodedNode *LVNode,
2320fe6060f1SDimitry Andric                          TrackingOptions Opts) override {
23210b57cec5SDimitry Andric     // Track the index if this is an array subscript.
23220b57cec5SDimitry Andric     if (const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
2323fe6060f1SDimitry Andric       return getParentTracker().track(
2324fe6060f1SDimitry Andric           Arr->getIdx(), LVNode,
2325fe6060f1SDimitry Andric           {Opts.Kind, /*EnableNullFPSuppression*/ false});
2326fe6060f1SDimitry Andric 
2327fe6060f1SDimitry Andric     return {};
2328fe6060f1SDimitry Andric   }
2329fe6060f1SDimitry Andric };
2330fe6060f1SDimitry Andric 
2331fe6060f1SDimitry Andric // TODO: extract it into more handlers
2332fe6060f1SDimitry Andric class InterestingLValueHandler final : public ExpressionHandler {
2333fe6060f1SDimitry Andric public:
2334fe6060f1SDimitry Andric   using ExpressionHandler::ExpressionHandler;
2335fe6060f1SDimitry Andric 
handle(const Expr * Inner,const ExplodedNode * InputNode,const ExplodedNode * LVNode,TrackingOptions Opts)2336fe6060f1SDimitry Andric   Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
2337fe6060f1SDimitry Andric                          const ExplodedNode *LVNode,
2338fe6060f1SDimitry Andric                          TrackingOptions Opts) override {
2339fe6060f1SDimitry Andric     ProgramStateRef LVState = LVNode->getState();
2340fe6060f1SDimitry Andric     const StackFrameContext *SFC = LVNode->getStackFrame();
2341fe6060f1SDimitry Andric     PathSensitiveBugReport &Report = getParentTracker().getReport();
2342fe6060f1SDimitry Andric     Tracker::Result Result;
23430b57cec5SDimitry Andric 
23440b57cec5SDimitry Andric     // See if the expression we're interested refers to a variable.
23450b57cec5SDimitry Andric     // If so, we can track both its contents and constraints on its value.
23460b57cec5SDimitry Andric     if (ExplodedGraph::isInterestingLValueExpr(Inner)) {
23470b57cec5SDimitry Andric       SVal LVal = LVNode->getSVal(Inner);
23480b57cec5SDimitry Andric 
23490b57cec5SDimitry Andric       const MemRegion *RR = getLocationRegionIfReference(Inner, LVNode);
23500b57cec5SDimitry Andric       bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
23510b57cec5SDimitry Andric 
23520b57cec5SDimitry Andric       // If this is a C++ reference to a null pointer, we are tracking the
23530b57cec5SDimitry Andric       // pointer. In addition, we should find the store at which the reference
23540b57cec5SDimitry Andric       // got initialized.
23550b57cec5SDimitry Andric       if (RR && !LVIsNull)
2356fe6060f1SDimitry Andric         Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));
23570b57cec5SDimitry Andric 
23580b57cec5SDimitry Andric       // In case of C++ references, we want to differentiate between a null
23590b57cec5SDimitry Andric       // reference and reference to null pointer.
23600b57cec5SDimitry Andric       // If the LVal is null, check if we are dealing with null reference.
23610b57cec5SDimitry Andric       // For those, we want to track the location of the reference.
2362fe6060f1SDimitry Andric       const MemRegion *R =
2363fe6060f1SDimitry Andric           (RR && LVIsNull) ? RR : LVNode->getSVal(Inner).getAsRegion();
23640b57cec5SDimitry Andric 
23650b57cec5SDimitry Andric       if (R) {
23660b57cec5SDimitry Andric 
23670b57cec5SDimitry Andric         // Mark both the variable region and its contents as interesting.
23680b57cec5SDimitry Andric         SVal V = LVState->getRawSVal(loc::MemRegionVal(R));
2369fe6060f1SDimitry Andric         Report.addVisitor<NoStoreFuncVisitor>(cast<SubRegion>(R), Opts.Kind);
2370fe6060f1SDimitry Andric 
2371fe6060f1SDimitry Andric         // When we got here, we do have something to track, and we will
2372fe6060f1SDimitry Andric         // interrupt.
2373fe6060f1SDimitry Andric         Result.FoundSomethingToTrack = true;
2374fe6060f1SDimitry Andric         Result.WasInterrupted = true;
23750b57cec5SDimitry Andric 
23760b57cec5SDimitry Andric         MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2377fe6060f1SDimitry Andric             LVNode, R, Opts.EnableNullFPSuppression, Report, V);
23780b57cec5SDimitry Andric 
2379fe6060f1SDimitry Andric         Report.markInteresting(V, Opts.Kind);
2380fe6060f1SDimitry Andric         Report.addVisitor<UndefOrNullArgVisitor>(R);
23810b57cec5SDimitry Andric 
2382fe6060f1SDimitry Andric         // If the contents are symbolic and null, find out when they became
2383fe6060f1SDimitry Andric         // null.
2384a7dea167SDimitry Andric         if (V.getAsLocSymbol(/*IncludeBaseRegions=*/true))
2385a7dea167SDimitry Andric           if (LVState->isNull(V).isConstrainedTrue())
238606c3fb27SDimitry Andric             Report.addVisitor<TrackConstraintBRVisitor>(
238706c3fb27SDimitry Andric                 V.castAs<DefinedSVal>(),
238806c3fb27SDimitry Andric                 /*Assumption=*/false, "Assuming pointer value is null");
23890b57cec5SDimitry Andric 
23900b57cec5SDimitry Andric         // Add visitor, which will suppress inline defensive checks.
23910b57cec5SDimitry Andric         if (auto DV = V.getAs<DefinedSVal>())
2392fe6060f1SDimitry Andric           if (!DV->isZeroConstant() && Opts.EnableNullFPSuppression)
2393fe6060f1SDimitry Andric             // Note that LVNode may be too late (i.e., too far from the
2394fe6060f1SDimitry Andric             // InputNode) because the lvalue may have been computed before the
2395fe6060f1SDimitry Andric             // inlined call was evaluated. InputNode may as well be too early
2396fe6060f1SDimitry Andric             // here, because the symbol is already dead; this, however, is fine
2397fe6060f1SDimitry Andric             // because we can still find the node in which it collapsed to null
2398fe6060f1SDimitry Andric             // previously.
2399fe6060f1SDimitry Andric             Report.addVisitor<SuppressInlineDefensiveChecksVisitor>(*DV,
2400fe6060f1SDimitry Andric                                                                     InputNode);
2401fe6060f1SDimitry Andric         getParentTracker().track(V, R, Opts, SFC);
2402fe6060f1SDimitry Andric       }
2403480093f4SDimitry Andric     }
24040b57cec5SDimitry Andric 
2405fe6060f1SDimitry Andric     return Result;
24060b57cec5SDimitry Andric   }
2407fe6060f1SDimitry Andric };
2408fe6060f1SDimitry Andric 
2409fe6060f1SDimitry Andric /// Adds a ReturnVisitor if the given statement represents a call that was
2410fe6060f1SDimitry Andric /// inlined.
2411fe6060f1SDimitry Andric ///
2412fe6060f1SDimitry Andric /// This will search back through the ExplodedGraph, starting from the given
2413fe6060f1SDimitry Andric /// node, looking for when the given statement was processed. If it turns out
2414fe6060f1SDimitry Andric /// the statement is a call that was inlined, we add the visitor to the
2415fe6060f1SDimitry Andric /// bug report, so it can print a note later.
2416fe6060f1SDimitry Andric class InlinedFunctionCallHandler final : public ExpressionHandler {
2417fe6060f1SDimitry Andric   using ExpressionHandler::ExpressionHandler;
2418fe6060f1SDimitry Andric 
handle(const Expr * E,const ExplodedNode * InputNode,const ExplodedNode * ExprNode,TrackingOptions Opts)2419fe6060f1SDimitry Andric   Tracker::Result handle(const Expr *E, const ExplodedNode *InputNode,
2420fe6060f1SDimitry Andric                          const ExplodedNode *ExprNode,
2421fe6060f1SDimitry Andric                          TrackingOptions Opts) override {
2422fe6060f1SDimitry Andric     if (!CallEvent::isCallStmt(E))
2423fe6060f1SDimitry Andric       return {};
2424fe6060f1SDimitry Andric 
2425fe6060f1SDimitry Andric     // First, find when we processed the statement.
2426fe6060f1SDimitry Andric     // If we work with a 'CXXNewExpr' that is going to be purged away before
2427fe6060f1SDimitry Andric     // its call take place. We would catch that purge in the last condition
2428fe6060f1SDimitry Andric     // as a 'StmtPoint' so we have to bypass it.
2429fe6060f1SDimitry Andric     const bool BypassCXXNewExprEval = isa<CXXNewExpr>(E);
2430fe6060f1SDimitry Andric 
2431fe6060f1SDimitry Andric     // This is moving forward when we enter into another context.
2432fe6060f1SDimitry Andric     const StackFrameContext *CurrentSFC = ExprNode->getStackFrame();
2433fe6060f1SDimitry Andric 
2434fe6060f1SDimitry Andric     do {
2435fe6060f1SDimitry Andric       // If that is satisfied we found our statement as an inlined call.
2436bdd1243dSDimitry Andric       if (std::optional<CallExitEnd> CEE =
2437bdd1243dSDimitry Andric               ExprNode->getLocationAs<CallExitEnd>())
2438fe6060f1SDimitry Andric         if (CEE->getCalleeContext()->getCallSite() == E)
2439fe6060f1SDimitry Andric           break;
2440fe6060f1SDimitry Andric 
2441fe6060f1SDimitry Andric       // Try to move forward to the end of the call-chain.
2442fe6060f1SDimitry Andric       ExprNode = ExprNode->getFirstPred();
2443fe6060f1SDimitry Andric       if (!ExprNode)
2444fe6060f1SDimitry Andric         break;
2445fe6060f1SDimitry Andric 
2446fe6060f1SDimitry Andric       const StackFrameContext *PredSFC = ExprNode->getStackFrame();
2447fe6060f1SDimitry Andric 
2448fe6060f1SDimitry Andric       // If that is satisfied we found our statement.
2449fe6060f1SDimitry Andric       // FIXME: This code currently bypasses the call site for the
2450fe6060f1SDimitry Andric       //        conservatively evaluated allocator.
2451fe6060f1SDimitry Andric       if (!BypassCXXNewExprEval)
2452bdd1243dSDimitry Andric         if (std::optional<StmtPoint> SP = ExprNode->getLocationAs<StmtPoint>())
2453fe6060f1SDimitry Andric           // See if we do not enter into another context.
2454fe6060f1SDimitry Andric           if (SP->getStmt() == E && CurrentSFC == PredSFC)
2455fe6060f1SDimitry Andric             break;
2456fe6060f1SDimitry Andric 
2457fe6060f1SDimitry Andric       CurrentSFC = PredSFC;
2458fe6060f1SDimitry Andric     } while (ExprNode->getStackFrame() == CurrentSFC);
2459fe6060f1SDimitry Andric 
2460fe6060f1SDimitry Andric     // Next, step over any post-statement checks.
2461fe6060f1SDimitry Andric     while (ExprNode && ExprNode->getLocation().getAs<PostStmt>())
2462fe6060f1SDimitry Andric       ExprNode = ExprNode->getFirstPred();
2463fe6060f1SDimitry Andric     if (!ExprNode)
2464fe6060f1SDimitry Andric       return {};
2465fe6060f1SDimitry Andric 
2466fe6060f1SDimitry Andric     // Finally, see if we inlined the call.
2467bdd1243dSDimitry Andric     std::optional<CallExitEnd> CEE = ExprNode->getLocationAs<CallExitEnd>();
2468fe6060f1SDimitry Andric     if (!CEE)
2469fe6060f1SDimitry Andric       return {};
2470fe6060f1SDimitry Andric 
2471fe6060f1SDimitry Andric     const StackFrameContext *CalleeContext = CEE->getCalleeContext();
2472fe6060f1SDimitry Andric     if (CalleeContext->getCallSite() != E)
2473fe6060f1SDimitry Andric       return {};
2474fe6060f1SDimitry Andric 
2475fe6060f1SDimitry Andric     // Check the return value.
2476fe6060f1SDimitry Andric     ProgramStateRef State = ExprNode->getState();
2477fe6060f1SDimitry Andric     SVal RetVal = ExprNode->getSVal(E);
2478fe6060f1SDimitry Andric 
2479fe6060f1SDimitry Andric     // Handle cases where a reference is returned and then immediately used.
2480fe6060f1SDimitry Andric     if (cast<Expr>(E)->isGLValue())
2481bdd1243dSDimitry Andric       if (std::optional<Loc> LValue = RetVal.getAs<Loc>())
2482fe6060f1SDimitry Andric         RetVal = State->getSVal(*LValue);
2483fe6060f1SDimitry Andric 
2484fe6060f1SDimitry Andric     // See if the return value is NULL. If so, suppress the report.
2485fe6060f1SDimitry Andric     AnalyzerOptions &Options = State->getAnalysisManager().options;
2486fe6060f1SDimitry Andric 
2487fe6060f1SDimitry Andric     bool EnableNullFPSuppression = false;
2488fe6060f1SDimitry Andric     if (Opts.EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths)
2489bdd1243dSDimitry Andric       if (std::optional<Loc> RetLoc = RetVal.getAs<Loc>())
2490fe6060f1SDimitry Andric         EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2491fe6060f1SDimitry Andric 
2492fe6060f1SDimitry Andric     PathSensitiveBugReport &Report = getParentTracker().getReport();
2493fe6060f1SDimitry Andric     Report.addVisitor<ReturnVisitor>(&getParentTracker(), CalleeContext,
2494fe6060f1SDimitry Andric                                      EnableNullFPSuppression, Options,
2495fe6060f1SDimitry Andric                                      Opts.Kind);
2496fe6060f1SDimitry Andric     return {true};
24970b57cec5SDimitry Andric   }
2498fe6060f1SDimitry Andric };
2499fe6060f1SDimitry Andric 
2500fe6060f1SDimitry Andric class DefaultExpressionHandler final : public ExpressionHandler {
2501fe6060f1SDimitry Andric public:
2502fe6060f1SDimitry Andric   using ExpressionHandler::ExpressionHandler;
2503fe6060f1SDimitry Andric 
handle(const Expr * Inner,const ExplodedNode * InputNode,const ExplodedNode * LVNode,TrackingOptions Opts)2504fe6060f1SDimitry Andric   Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
2505fe6060f1SDimitry Andric                          const ExplodedNode *LVNode,
2506fe6060f1SDimitry Andric                          TrackingOptions Opts) override {
2507fe6060f1SDimitry Andric     ProgramStateRef LVState = LVNode->getState();
2508fe6060f1SDimitry Andric     const StackFrameContext *SFC = LVNode->getStackFrame();
2509fe6060f1SDimitry Andric     PathSensitiveBugReport &Report = getParentTracker().getReport();
2510fe6060f1SDimitry Andric     Tracker::Result Result;
25110b57cec5SDimitry Andric 
25120b57cec5SDimitry Andric     // If the expression is not an "lvalue expression", we can still
25130b57cec5SDimitry Andric     // track the constraints on its contents.
25140b57cec5SDimitry Andric     SVal V = LVState->getSValAsScalarOrLoc(Inner, LVNode->getLocationContext());
25150b57cec5SDimitry Andric 
25160b57cec5SDimitry Andric     // Is it a symbolic value?
25170b57cec5SDimitry Andric     if (auto L = V.getAs<loc::MemRegionVal>()) {
25180b57cec5SDimitry Andric       // FIXME: this is a hack for fixing a later crash when attempting to
25190b57cec5SDimitry Andric       // dereference a void* pointer.
25200b57cec5SDimitry Andric       // We should not try to dereference pointers at all when we don't care
25210b57cec5SDimitry Andric       // what is written inside the pointer.
25220b57cec5SDimitry Andric       bool CanDereference = true;
2523a7dea167SDimitry Andric       if (const auto *SR = L->getRegionAs<SymbolicRegion>()) {
2524bdd1243dSDimitry Andric         if (SR->getPointeeStaticType()->isVoidType())
25250b57cec5SDimitry Andric           CanDereference = false;
2526a7dea167SDimitry Andric       } else if (L->getRegionAs<AllocaRegion>())
2527a7dea167SDimitry Andric         CanDereference = false;
25280b57cec5SDimitry Andric 
25290b57cec5SDimitry Andric       // At this point we are dealing with the region's LValue.
2530fe6060f1SDimitry Andric       // However, if the rvalue is a symbolic region, we should track it as
2531fe6060f1SDimitry Andric       // well. Try to use the correct type when looking up the value.
25320b57cec5SDimitry Andric       SVal RVal;
2533a7dea167SDimitry Andric       if (ExplodedGraph::isInterestingLValueExpr(Inner))
253481ad6265SDimitry Andric         RVal = LVState->getRawSVal(*L, Inner->getType());
2535a7dea167SDimitry Andric       else if (CanDereference)
25360b57cec5SDimitry Andric         RVal = LVState->getSVal(L->getRegion());
25370b57cec5SDimitry Andric 
2538a7dea167SDimitry Andric       if (CanDereference) {
2539fe6060f1SDimitry Andric         Report.addVisitor<UndefOrNullArgVisitor>(L->getRegion());
2540fe6060f1SDimitry Andric         Result.FoundSomethingToTrack = true;
2541a7dea167SDimitry Andric 
25420b57cec5SDimitry Andric         if (auto KV = RVal.getAs<KnownSVal>())
2543fe6060f1SDimitry Andric           Result.combineWith(
2544fe6060f1SDimitry Andric               getParentTracker().track(*KV, L->getRegion(), Opts, SFC));
2545a7dea167SDimitry Andric       }
25460b57cec5SDimitry Andric 
25470b57cec5SDimitry Andric       const MemRegion *RegionRVal = RVal.getAsRegion();
2548fe6060f1SDimitry Andric       if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
2549fe6060f1SDimitry Andric         Report.markInteresting(RegionRVal, Opts.Kind);
2550fe6060f1SDimitry Andric         Report.addVisitor<TrackConstraintBRVisitor>(
2551fe6060f1SDimitry Andric             loc::MemRegionVal(RegionRVal),
255206c3fb27SDimitry Andric             /*Assumption=*/false, "Assuming pointer value is null");
2553fe6060f1SDimitry Andric         Result.FoundSomethingToTrack = true;
25540b57cec5SDimitry Andric       }
25550b57cec5SDimitry Andric     }
2556fe6060f1SDimitry Andric 
2557fe6060f1SDimitry Andric     return Result;
2558fe6060f1SDimitry Andric   }
2559fe6060f1SDimitry Andric };
2560fe6060f1SDimitry Andric 
2561fe6060f1SDimitry Andric /// Attempts to add visitors to track an RValue expression back to its point of
2562fe6060f1SDimitry Andric /// origin.
2563fe6060f1SDimitry Andric class PRValueHandler final : public ExpressionHandler {
2564fe6060f1SDimitry Andric public:
2565fe6060f1SDimitry Andric   using ExpressionHandler::ExpressionHandler;
2566fe6060f1SDimitry Andric 
handle(const Expr * E,const ExplodedNode * InputNode,const ExplodedNode * ExprNode,TrackingOptions Opts)2567fe6060f1SDimitry Andric   Tracker::Result handle(const Expr *E, const ExplodedNode *InputNode,
2568fe6060f1SDimitry Andric                          const ExplodedNode *ExprNode,
2569fe6060f1SDimitry Andric                          TrackingOptions Opts) override {
2570fe6060f1SDimitry Andric     if (!E->isPRValue())
2571fe6060f1SDimitry Andric       return {};
2572fe6060f1SDimitry Andric 
2573fe6060f1SDimitry Andric     const ExplodedNode *RVNode = findNodeForExpression(ExprNode, E);
2574fe6060f1SDimitry Andric     if (!RVNode)
2575fe6060f1SDimitry Andric       return {};
2576fe6060f1SDimitry Andric 
2577bdd1243dSDimitry Andric     Tracker::Result CombinedResult;
2578bdd1243dSDimitry Andric     Tracker &Parent = getParentTracker();
2579bdd1243dSDimitry Andric 
2580bdd1243dSDimitry Andric     const auto track = [&CombinedResult, &Parent, ExprNode,
2581bdd1243dSDimitry Andric                         Opts](const Expr *Inner) {
2582bdd1243dSDimitry Andric       CombinedResult.combineWith(Parent.track(Inner, ExprNode, Opts));
2583bdd1243dSDimitry Andric     };
2584bdd1243dSDimitry Andric 
2585bdd1243dSDimitry Andric     // FIXME: Initializer lists can appear in many different contexts
2586bdd1243dSDimitry Andric     // and most of them needs a special handling. For now let's handle
2587bdd1243dSDimitry Andric     // what we can. If the initializer list only has 1 element, we track
2588bdd1243dSDimitry Andric     // that.
2589bdd1243dSDimitry Andric     // This snippet even handles nesting, e.g.: int *x{{{{{y}}}}};
2590bdd1243dSDimitry Andric     if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
2591bdd1243dSDimitry Andric       if (ILE->getNumInits() == 1) {
2592bdd1243dSDimitry Andric         track(ILE->getInit(0));
2593bdd1243dSDimitry Andric 
2594bdd1243dSDimitry Andric         return CombinedResult;
2595bdd1243dSDimitry Andric       }
2596bdd1243dSDimitry Andric 
2597bdd1243dSDimitry Andric       return {};
2598bdd1243dSDimitry Andric     }
2599bdd1243dSDimitry Andric 
2600fe6060f1SDimitry Andric     ProgramStateRef RVState = RVNode->getState();
2601fe6060f1SDimitry Andric     SVal V = RVState->getSValAsScalarOrLoc(E, RVNode->getLocationContext());
2602fe6060f1SDimitry Andric     const auto *BO = dyn_cast<BinaryOperator>(E);
2603fe6060f1SDimitry Andric 
2604fe6060f1SDimitry Andric     if (!BO || !BO->isMultiplicativeOp() || !V.isZeroConstant())
2605fe6060f1SDimitry Andric       return {};
2606fe6060f1SDimitry Andric 
2607fe6060f1SDimitry Andric     SVal RHSV = RVState->getSVal(BO->getRHS(), RVNode->getLocationContext());
2608fe6060f1SDimitry Andric     SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->getLocationContext());
2609fe6060f1SDimitry Andric 
2610fe6060f1SDimitry Andric     // Track both LHS and RHS of a multiplication.
2611fe6060f1SDimitry Andric     if (BO->getOpcode() == BO_Mul) {
2612fe6060f1SDimitry Andric       if (LHSV.isZeroConstant())
2613fe6060f1SDimitry Andric         track(BO->getLHS());
2614fe6060f1SDimitry Andric       if (RHSV.isZeroConstant())
2615fe6060f1SDimitry Andric         track(BO->getRHS());
2616fe6060f1SDimitry Andric     } else { // Track only the LHS of a division or a modulo.
2617fe6060f1SDimitry Andric       if (LHSV.isZeroConstant())
2618fe6060f1SDimitry Andric         track(BO->getLHS());
2619fe6060f1SDimitry Andric     }
2620fe6060f1SDimitry Andric 
2621fe6060f1SDimitry Andric     return CombinedResult;
2622fe6060f1SDimitry Andric   }
2623fe6060f1SDimitry Andric };
2624bdd1243dSDimitry Andric } // namespace
2625fe6060f1SDimitry Andric 
Tracker(PathSensitiveBugReport & Report)2626fe6060f1SDimitry Andric Tracker::Tracker(PathSensitiveBugReport &Report) : Report(Report) {
2627fe6060f1SDimitry Andric   // Default expression handlers.
2628fe6060f1SDimitry Andric   addLowPriorityHandler<ControlDependencyHandler>();
2629fe6060f1SDimitry Andric   addLowPriorityHandler<NilReceiverHandler>();
2630fe6060f1SDimitry Andric   addLowPriorityHandler<ArrayIndexHandler>();
2631fe6060f1SDimitry Andric   addLowPriorityHandler<InterestingLValueHandler>();
2632fe6060f1SDimitry Andric   addLowPriorityHandler<InlinedFunctionCallHandler>();
2633fe6060f1SDimitry Andric   addLowPriorityHandler<DefaultExpressionHandler>();
2634fe6060f1SDimitry Andric   addLowPriorityHandler<PRValueHandler>();
2635fe6060f1SDimitry Andric   // Default store handlers.
2636fe6060f1SDimitry Andric   addHighPriorityHandler<DefaultStoreHandler>();
2637fe6060f1SDimitry Andric }
2638fe6060f1SDimitry Andric 
track(const Expr * E,const ExplodedNode * N,TrackingOptions Opts)2639fe6060f1SDimitry Andric Tracker::Result Tracker::track(const Expr *E, const ExplodedNode *N,
2640fe6060f1SDimitry Andric                                TrackingOptions Opts) {
2641fe6060f1SDimitry Andric   if (!E || !N)
2642fe6060f1SDimitry Andric     return {};
2643fe6060f1SDimitry Andric 
2644fe6060f1SDimitry Andric   const Expr *Inner = peelOffOuterExpr(E, N);
2645fe6060f1SDimitry Andric   const ExplodedNode *LVNode = findNodeForExpression(N, Inner);
2646fe6060f1SDimitry Andric   if (!LVNode)
2647fe6060f1SDimitry Andric     return {};
2648fe6060f1SDimitry Andric 
2649fe6060f1SDimitry Andric   Result CombinedResult;
2650fe6060f1SDimitry Andric   // Iterate through the handlers in the order according to their priorities.
2651fe6060f1SDimitry Andric   for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2652fe6060f1SDimitry Andric     CombinedResult.combineWith(Handler->handle(Inner, N, LVNode, Opts));
2653fe6060f1SDimitry Andric     if (CombinedResult.WasInterrupted) {
2654fe6060f1SDimitry Andric       // There is no need to confuse our users here.
2655fe6060f1SDimitry Andric       // We got interrupted, but our users don't need to know about it.
2656fe6060f1SDimitry Andric       CombinedResult.WasInterrupted = false;
2657fe6060f1SDimitry Andric       break;
2658fe6060f1SDimitry Andric     }
2659fe6060f1SDimitry Andric   }
2660fe6060f1SDimitry Andric 
2661fe6060f1SDimitry Andric   return CombinedResult;
2662fe6060f1SDimitry Andric }
2663fe6060f1SDimitry Andric 
track(SVal V,const MemRegion * R,TrackingOptions Opts,const StackFrameContext * Origin)2664fe6060f1SDimitry Andric Tracker::Result Tracker::track(SVal V, const MemRegion *R, TrackingOptions Opts,
2665fe6060f1SDimitry Andric                                const StackFrameContext *Origin) {
2666fe6060f1SDimitry Andric   if (auto KV = V.getAs<KnownSVal>()) {
2667fe6060f1SDimitry Andric     Report.addVisitor<StoreSiteFinder>(this, *KV, R, Opts, Origin);
2668fe6060f1SDimitry Andric     return {true};
2669fe6060f1SDimitry Andric   }
2670fe6060f1SDimitry Andric   return {};
2671fe6060f1SDimitry Andric }
2672fe6060f1SDimitry Andric 
handle(StoreInfo SI,BugReporterContext & BRC,TrackingOptions Opts)2673fe6060f1SDimitry Andric PathDiagnosticPieceRef Tracker::handle(StoreInfo SI, BugReporterContext &BRC,
2674fe6060f1SDimitry Andric                                        TrackingOptions Opts) {
2675fe6060f1SDimitry Andric   // Iterate through the handlers in the order according to their priorities.
2676fe6060f1SDimitry Andric   for (StoreHandlerPtr &Handler : StoreHandlers) {
2677fe6060f1SDimitry Andric     if (PathDiagnosticPieceRef Result = Handler->handle(SI, BRC, Opts))
2678fe6060f1SDimitry Andric       // If the handler produced a non-null piece, return it.
2679fe6060f1SDimitry Andric       // There is no need in asking other handlers.
2680fe6060f1SDimitry Andric       return Result;
2681fe6060f1SDimitry Andric   }
2682fe6060f1SDimitry Andric   return {};
2683fe6060f1SDimitry Andric }
2684fe6060f1SDimitry Andric 
trackExpressionValue(const ExplodedNode * InputNode,const Expr * E,PathSensitiveBugReport & Report,TrackingOptions Opts)2685fe6060f1SDimitry Andric bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
2686fe6060f1SDimitry Andric                                        const Expr *E,
2687fe6060f1SDimitry Andric 
2688fe6060f1SDimitry Andric                                        PathSensitiveBugReport &Report,
2689fe6060f1SDimitry Andric                                        TrackingOptions Opts) {
2690fe6060f1SDimitry Andric   return Tracker::create(Report)
2691fe6060f1SDimitry Andric       ->track(E, InputNode, Opts)
2692fe6060f1SDimitry Andric       .FoundSomethingToTrack;
2693fe6060f1SDimitry Andric }
2694fe6060f1SDimitry Andric 
trackStoredValue(KnownSVal V,const MemRegion * R,PathSensitiveBugReport & Report,TrackingOptions Opts,const StackFrameContext * Origin)2695fe6060f1SDimitry Andric void bugreporter::trackStoredValue(KnownSVal V, const MemRegion *R,
2696fe6060f1SDimitry Andric                                    PathSensitiveBugReport &Report,
2697fe6060f1SDimitry Andric                                    TrackingOptions Opts,
2698fe6060f1SDimitry Andric                                    const StackFrameContext *Origin) {
2699fe6060f1SDimitry Andric   Tracker::create(Report)->track(V, R, Opts, Origin);
27000b57cec5SDimitry Andric }
27010b57cec5SDimitry Andric 
27020b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
27030b57cec5SDimitry Andric // Implementation of NulReceiverBRVisitor.
27040b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
27050b57cec5SDimitry Andric 
getNilReceiver(const Stmt * S,const ExplodedNode * N)27060b57cec5SDimitry Andric const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S,
27070b57cec5SDimitry Andric                                                  const ExplodedNode *N) {
27080b57cec5SDimitry Andric   const auto *ME = dyn_cast<ObjCMessageExpr>(S);
27090b57cec5SDimitry Andric   if (!ME)
27100b57cec5SDimitry Andric     return nullptr;
27110b57cec5SDimitry Andric   if (const Expr *Receiver = ME->getInstanceReceiver()) {
27120b57cec5SDimitry Andric     ProgramStateRef state = N->getState();
27130b57cec5SDimitry Andric     SVal V = N->getSVal(Receiver);
27140b57cec5SDimitry Andric     if (state->isNull(V).isConstrainedTrue())
27150b57cec5SDimitry Andric       return Receiver;
27160b57cec5SDimitry Andric   }
27170b57cec5SDimitry Andric   return nullptr;
27180b57cec5SDimitry Andric }
27190b57cec5SDimitry Andric 
2720a7dea167SDimitry Andric PathDiagnosticPieceRef
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)2721a7dea167SDimitry Andric NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
2722a7dea167SDimitry Andric                                 PathSensitiveBugReport &BR) {
2723bdd1243dSDimitry Andric   std::optional<PreStmt> P = N->getLocationAs<PreStmt>();
27240b57cec5SDimitry Andric   if (!P)
27250b57cec5SDimitry Andric     return nullptr;
27260b57cec5SDimitry Andric 
27270b57cec5SDimitry Andric   const Stmt *S = P->getStmt();
27280b57cec5SDimitry Andric   const Expr *Receiver = getNilReceiver(S, N);
27290b57cec5SDimitry Andric   if (!Receiver)
27300b57cec5SDimitry Andric     return nullptr;
27310b57cec5SDimitry Andric 
27320b57cec5SDimitry Andric   llvm::SmallString<256> Buf;
27330b57cec5SDimitry Andric   llvm::raw_svector_ostream OS(Buf);
27340b57cec5SDimitry Andric 
27350b57cec5SDimitry Andric   if (const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
27360b57cec5SDimitry Andric     OS << "'";
27370b57cec5SDimitry Andric     ME->getSelector().print(OS);
27380b57cec5SDimitry Andric     OS << "' not called";
27390b57cec5SDimitry Andric   }
27400b57cec5SDimitry Andric   else {
27410b57cec5SDimitry Andric     OS << "No method is called";
27420b57cec5SDimitry Andric   }
27430b57cec5SDimitry Andric   OS << " because the receiver is nil";
27440b57cec5SDimitry Andric 
27450b57cec5SDimitry Andric   // The receiver was nil, and hence the method was skipped.
27460b57cec5SDimitry Andric   // Register a BugReporterVisitor to issue a message telling us how
27470b57cec5SDimitry Andric   // the receiver was null.
2748fe6060f1SDimitry Andric   bugreporter::trackExpressionValue(N, Receiver, BR,
2749fe6060f1SDimitry Andric                                     {bugreporter::TrackingKind::Thorough,
2750fe6060f1SDimitry Andric                                      /*EnableNullFPSuppression*/ false});
27510b57cec5SDimitry Andric   // Issue a message saying that the method was skipped.
27520b57cec5SDimitry Andric   PathDiagnosticLocation L(Receiver, BRC.getSourceManager(),
27530b57cec5SDimitry Andric                                      N->getLocationContext());
27540b57cec5SDimitry Andric   return std::make_shared<PathDiagnosticEventPiece>(L, OS.str());
27550b57cec5SDimitry Andric }
27560b57cec5SDimitry Andric 
27570b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
27580b57cec5SDimitry Andric // Visitor that tries to report interesting diagnostics from conditions.
27590b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
27600b57cec5SDimitry Andric 
27610b57cec5SDimitry Andric /// Return the tag associated with this visitor.  This tag will be used
27620b57cec5SDimitry Andric /// to make all PathDiagnosticPieces created by this visitor.
getTag()2763a7dea167SDimitry Andric const char *ConditionBRVisitor::getTag() { return "ConditionBRVisitor"; }
27640b57cec5SDimitry Andric 
2765a7dea167SDimitry Andric PathDiagnosticPieceRef
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)2766a7dea167SDimitry Andric ConditionBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
2767a7dea167SDimitry Andric                               PathSensitiveBugReport &BR) {
27680b57cec5SDimitry Andric   auto piece = VisitNodeImpl(N, BRC, BR);
27690b57cec5SDimitry Andric   if (piece) {
27700b57cec5SDimitry Andric     piece->setTag(getTag());
27710b57cec5SDimitry Andric     if (auto *ev = dyn_cast<PathDiagnosticEventPiece>(piece.get()))
27720b57cec5SDimitry Andric       ev->setPrunable(true, /* override */ false);
27730b57cec5SDimitry Andric   }
27740b57cec5SDimitry Andric   return piece;
27750b57cec5SDimitry Andric }
27760b57cec5SDimitry Andric 
2777a7dea167SDimitry Andric PathDiagnosticPieceRef
VisitNodeImpl(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)27780b57cec5SDimitry Andric ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
2779a7dea167SDimitry Andric                                   BugReporterContext &BRC,
2780a7dea167SDimitry Andric                                   PathSensitiveBugReport &BR) {
27810b57cec5SDimitry Andric   ProgramPoint ProgPoint = N->getLocation();
27820b57cec5SDimitry Andric   const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
27830b57cec5SDimitry Andric       ExprEngine::geteagerlyAssumeBinOpBifurcationTags();
27840b57cec5SDimitry Andric 
27850b57cec5SDimitry Andric   // If an assumption was made on a branch, it should be caught
27860b57cec5SDimitry Andric   // here by looking at the state transition.
2787bdd1243dSDimitry Andric   if (std::optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
27880b57cec5SDimitry Andric     const CFGBlock *SrcBlock = BE->getSrc();
27890b57cec5SDimitry Andric     if (const Stmt *Term = SrcBlock->getTerminatorStmt()) {
27900b57cec5SDimitry Andric       // If the tag of the previous node is 'Eagerly Assume...' the current
27910b57cec5SDimitry Andric       // 'BlockEdge' has the same constraint information. We do not want to
27920b57cec5SDimitry Andric       // report the value as it is just an assumption on the predecessor node
27930b57cec5SDimitry Andric       // which will be caught in the next VisitNode() iteration as a 'PostStmt'.
27940b57cec5SDimitry Andric       const ProgramPointTag *PreviousNodeTag =
27950b57cec5SDimitry Andric           N->getFirstPred()->getLocation().getTag();
27960b57cec5SDimitry Andric       if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
27970b57cec5SDimitry Andric         return nullptr;
27980b57cec5SDimitry Andric 
27990b57cec5SDimitry Andric       return VisitTerminator(Term, N, SrcBlock, BE->getDst(), BR, BRC);
28000b57cec5SDimitry Andric     }
28010b57cec5SDimitry Andric     return nullptr;
28020b57cec5SDimitry Andric   }
28030b57cec5SDimitry Andric 
2804bdd1243dSDimitry Andric   if (std::optional<PostStmt> PS = ProgPoint.getAs<PostStmt>()) {
28050b57cec5SDimitry Andric     const ProgramPointTag *CurrentNodeTag = PS->getTag();
28060b57cec5SDimitry Andric     if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
28070b57cec5SDimitry Andric       return nullptr;
28080b57cec5SDimitry Andric 
28090b57cec5SDimitry Andric     bool TookTrue = CurrentNodeTag == Tags.first;
28100b57cec5SDimitry Andric     return VisitTrueTest(cast<Expr>(PS->getStmt()), BRC, BR, N, TookTrue);
28110b57cec5SDimitry Andric   }
28120b57cec5SDimitry Andric 
28130b57cec5SDimitry Andric   return nullptr;
28140b57cec5SDimitry Andric }
28150b57cec5SDimitry Andric 
VisitTerminator(const Stmt * Term,const ExplodedNode * N,const CFGBlock * srcBlk,const CFGBlock * dstBlk,PathSensitiveBugReport & R,BugReporterContext & BRC)2816a7dea167SDimitry Andric PathDiagnosticPieceRef ConditionBRVisitor::VisitTerminator(
28170b57cec5SDimitry Andric     const Stmt *Term, const ExplodedNode *N, const CFGBlock *srcBlk,
2818a7dea167SDimitry Andric     const CFGBlock *dstBlk, PathSensitiveBugReport &R,
2819a7dea167SDimitry Andric     BugReporterContext &BRC) {
28200b57cec5SDimitry Andric   const Expr *Cond = nullptr;
28210b57cec5SDimitry Andric 
28220b57cec5SDimitry Andric   // In the code below, Term is a CFG terminator and Cond is a branch condition
28230b57cec5SDimitry Andric   // expression upon which the decision is made on this terminator.
28240b57cec5SDimitry Andric   //
28250b57cec5SDimitry Andric   // For example, in "if (x == 0)", the "if (x == 0)" statement is a terminator,
28260b57cec5SDimitry Andric   // and "x == 0" is the respective condition.
28270b57cec5SDimitry Andric   //
28280b57cec5SDimitry Andric   // Another example: in "if (x && y)", we've got two terminators and two
28290b57cec5SDimitry Andric   // conditions due to short-circuit nature of operator "&&":
28300b57cec5SDimitry Andric   // 1. The "if (x && y)" statement is a terminator,
28310b57cec5SDimitry Andric   //    and "y" is the respective condition.
28320b57cec5SDimitry Andric   // 2. Also "x && ..." is another terminator,
28330b57cec5SDimitry Andric   //    and "x" is its condition.
28340b57cec5SDimitry Andric 
28350b57cec5SDimitry Andric   switch (Term->getStmtClass()) {
28360b57cec5SDimitry Andric   // FIXME: Stmt::SwitchStmtClass is worth handling, however it is a bit
28370b57cec5SDimitry Andric   // more tricky because there are more than two branches to account for.
28380b57cec5SDimitry Andric   default:
28390b57cec5SDimitry Andric     return nullptr;
28400b57cec5SDimitry Andric   case Stmt::IfStmtClass:
28410b57cec5SDimitry Andric     Cond = cast<IfStmt>(Term)->getCond();
28420b57cec5SDimitry Andric     break;
28430b57cec5SDimitry Andric   case Stmt::ConditionalOperatorClass:
28440b57cec5SDimitry Andric     Cond = cast<ConditionalOperator>(Term)->getCond();
28450b57cec5SDimitry Andric     break;
28460b57cec5SDimitry Andric   case Stmt::BinaryOperatorClass:
28470b57cec5SDimitry Andric     // When we encounter a logical operator (&& or ||) as a CFG terminator,
28480b57cec5SDimitry Andric     // then the condition is actually its LHS; otherwise, we'd encounter
28490b57cec5SDimitry Andric     // the parent, such as if-statement, as a terminator.
28500b57cec5SDimitry Andric     const auto *BO = cast<BinaryOperator>(Term);
28510b57cec5SDimitry Andric     assert(BO->isLogicalOp() &&
28520b57cec5SDimitry Andric            "CFG terminator is not a short-circuit operator!");
28530b57cec5SDimitry Andric     Cond = BO->getLHS();
28540b57cec5SDimitry Andric     break;
28550b57cec5SDimitry Andric   }
28560b57cec5SDimitry Andric 
28570b57cec5SDimitry Andric   Cond = Cond->IgnoreParens();
28580b57cec5SDimitry Andric 
28590b57cec5SDimitry Andric   // However, when we encounter a logical operator as a branch condition,
28600b57cec5SDimitry Andric   // then the condition is actually its RHS, because LHS would be
28610b57cec5SDimitry Andric   // the condition for the logical operator terminator.
28620b57cec5SDimitry Andric   while (const auto *InnerBO = dyn_cast<BinaryOperator>(Cond)) {
28630b57cec5SDimitry Andric     if (!InnerBO->isLogicalOp())
28640b57cec5SDimitry Andric       break;
28650b57cec5SDimitry Andric     Cond = InnerBO->getRHS()->IgnoreParens();
28660b57cec5SDimitry Andric   }
28670b57cec5SDimitry Andric 
28680b57cec5SDimitry Andric   assert(Cond);
28690b57cec5SDimitry Andric   assert(srcBlk->succ_size() == 2);
28700b57cec5SDimitry Andric   const bool TookTrue = *(srcBlk->succ_begin()) == dstBlk;
28710b57cec5SDimitry Andric   return VisitTrueTest(Cond, BRC, R, N, TookTrue);
28720b57cec5SDimitry Andric }
28730b57cec5SDimitry Andric 
2874a7dea167SDimitry Andric PathDiagnosticPieceRef
VisitTrueTest(const Expr * Cond,BugReporterContext & BRC,PathSensitiveBugReport & R,const ExplodedNode * N,bool TookTrue)28750b57cec5SDimitry Andric ConditionBRVisitor::VisitTrueTest(const Expr *Cond, BugReporterContext &BRC,
2876a7dea167SDimitry Andric                                   PathSensitiveBugReport &R,
2877a7dea167SDimitry Andric                                   const ExplodedNode *N, bool TookTrue) {
28780b57cec5SDimitry Andric   ProgramStateRef CurrentState = N->getState();
28790b57cec5SDimitry Andric   ProgramStateRef PrevState = N->getFirstPred()->getState();
28800b57cec5SDimitry Andric   const LocationContext *LCtx = N->getLocationContext();
28810b57cec5SDimitry Andric 
28820b57cec5SDimitry Andric   // If the constraint information is changed between the current and the
28830b57cec5SDimitry Andric   // previous program state we assuming the newly seen constraint information.
28840b57cec5SDimitry Andric   // If we cannot evaluate the condition (and the constraints are the same)
28850b57cec5SDimitry Andric   // the analyzer has no information about the value and just assuming it.
28860b57cec5SDimitry Andric   bool IsAssuming =
28870b57cec5SDimitry Andric       !BRC.getStateManager().haveEqualConstraints(CurrentState, PrevState) ||
28880b57cec5SDimitry Andric       CurrentState->getSVal(Cond, LCtx).isUnknownOrUndef();
28890b57cec5SDimitry Andric 
28900b57cec5SDimitry Andric   // These will be modified in code below, but we need to preserve the original
28910b57cec5SDimitry Andric   //  values in case we want to throw the generic message.
28920b57cec5SDimitry Andric   const Expr *CondTmp = Cond;
28930b57cec5SDimitry Andric   bool TookTrueTmp = TookTrue;
28940b57cec5SDimitry Andric 
28950b57cec5SDimitry Andric   while (true) {
28960b57cec5SDimitry Andric     CondTmp = CondTmp->IgnoreParenCasts();
28970b57cec5SDimitry Andric     switch (CondTmp->getStmtClass()) {
28980b57cec5SDimitry Andric       default:
28990b57cec5SDimitry Andric         break;
29000b57cec5SDimitry Andric       case Stmt::BinaryOperatorClass:
29010b57cec5SDimitry Andric         if (auto P = VisitTrueTest(Cond, cast<BinaryOperator>(CondTmp),
29020b57cec5SDimitry Andric                                    BRC, R, N, TookTrueTmp, IsAssuming))
29030b57cec5SDimitry Andric           return P;
29040b57cec5SDimitry Andric         break;
29050b57cec5SDimitry Andric       case Stmt::DeclRefExprClass:
29060b57cec5SDimitry Andric         if (auto P = VisitTrueTest(Cond, cast<DeclRefExpr>(CondTmp),
29070b57cec5SDimitry Andric                                    BRC, R, N, TookTrueTmp, IsAssuming))
29080b57cec5SDimitry Andric           return P;
29090b57cec5SDimitry Andric         break;
29100b57cec5SDimitry Andric       case Stmt::MemberExprClass:
29110b57cec5SDimitry Andric         if (auto P = VisitTrueTest(Cond, cast<MemberExpr>(CondTmp),
29120b57cec5SDimitry Andric                                    BRC, R, N, TookTrueTmp, IsAssuming))
29130b57cec5SDimitry Andric           return P;
29140b57cec5SDimitry Andric         break;
29150b57cec5SDimitry Andric       case Stmt::UnaryOperatorClass: {
29160b57cec5SDimitry Andric         const auto *UO = cast<UnaryOperator>(CondTmp);
29170b57cec5SDimitry Andric         if (UO->getOpcode() == UO_LNot) {
29180b57cec5SDimitry Andric           TookTrueTmp = !TookTrueTmp;
29190b57cec5SDimitry Andric           CondTmp = UO->getSubExpr();
29200b57cec5SDimitry Andric           continue;
29210b57cec5SDimitry Andric         }
29220b57cec5SDimitry Andric         break;
29230b57cec5SDimitry Andric       }
29240b57cec5SDimitry Andric     }
29250b57cec5SDimitry Andric     break;
29260b57cec5SDimitry Andric   }
29270b57cec5SDimitry Andric 
29280b57cec5SDimitry Andric   // Condition too complex to explain? Just say something so that the user
29290b57cec5SDimitry Andric   // knew we've made some path decision at this point.
29300b57cec5SDimitry Andric   // If it is too complex and we know the evaluation of the condition do not
29310b57cec5SDimitry Andric   // repeat the note from 'BugReporter.cpp'
29320b57cec5SDimitry Andric   if (!IsAssuming)
29330b57cec5SDimitry Andric     return nullptr;
29340b57cec5SDimitry Andric 
29350b57cec5SDimitry Andric   PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
29360b57cec5SDimitry Andric   if (!Loc.isValid() || !Loc.asLocation().isValid())
29370b57cec5SDimitry Andric     return nullptr;
29380b57cec5SDimitry Andric 
29390b57cec5SDimitry Andric   return std::make_shared<PathDiagnosticEventPiece>(
29400b57cec5SDimitry Andric       Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
29410b57cec5SDimitry Andric }
29420b57cec5SDimitry Andric 
patternMatch(const Expr * Ex,const Expr * ParentEx,raw_ostream & Out,BugReporterContext & BRC,PathSensitiveBugReport & report,const ExplodedNode * N,std::optional<bool> & prunable,bool IsSameFieldName)2943bdd1243dSDimitry Andric bool ConditionBRVisitor::patternMatch(const Expr *Ex, const Expr *ParentEx,
2944bdd1243dSDimitry Andric                                       raw_ostream &Out, BugReporterContext &BRC,
2945a7dea167SDimitry Andric                                       PathSensitiveBugReport &report,
29460b57cec5SDimitry Andric                                       const ExplodedNode *N,
2947bdd1243dSDimitry Andric                                       std::optional<bool> &prunable,
29480b57cec5SDimitry Andric                                       bool IsSameFieldName) {
29490b57cec5SDimitry Andric   const Expr *OriginalExpr = Ex;
29500b57cec5SDimitry Andric   Ex = Ex->IgnoreParenCasts();
29510b57cec5SDimitry Andric 
2952349cc55cSDimitry Andric   if (isa<GNUNullExpr, ObjCBoolLiteralExpr, CXXBoolLiteralExpr, IntegerLiteral,
2953349cc55cSDimitry Andric           FloatingLiteral>(Ex)) {
29540b57cec5SDimitry Andric     // Use heuristics to determine if the expression is a macro
29550b57cec5SDimitry Andric     // expanding to a literal and if so, use the macro's name.
29560b57cec5SDimitry Andric     SourceLocation BeginLoc = OriginalExpr->getBeginLoc();
29570b57cec5SDimitry Andric     SourceLocation EndLoc = OriginalExpr->getEndLoc();
29580b57cec5SDimitry Andric     if (BeginLoc.isMacroID() && EndLoc.isMacroID()) {
2959a7dea167SDimitry Andric       const SourceManager &SM = BRC.getSourceManager();
29600b57cec5SDimitry Andric       const LangOptions &LO = BRC.getASTContext().getLangOpts();
29610b57cec5SDimitry Andric       if (Lexer::isAtStartOfMacroExpansion(BeginLoc, SM, LO) &&
29620b57cec5SDimitry Andric           Lexer::isAtEndOfMacroExpansion(EndLoc, SM, LO)) {
29630b57cec5SDimitry Andric         CharSourceRange R = Lexer::getAsCharRange({BeginLoc, EndLoc}, SM, LO);
29640b57cec5SDimitry Andric         Out << Lexer::getSourceText(R, SM, LO);
29650b57cec5SDimitry Andric         return false;
29660b57cec5SDimitry Andric       }
29670b57cec5SDimitry Andric     }
29680b57cec5SDimitry Andric   }
29690b57cec5SDimitry Andric 
29700b57cec5SDimitry Andric   if (const auto *DR = dyn_cast<DeclRefExpr>(Ex)) {
29710b57cec5SDimitry Andric     const bool quotes = isa<VarDecl>(DR->getDecl());
29720b57cec5SDimitry Andric     if (quotes) {
29730b57cec5SDimitry Andric       Out << '\'';
29740b57cec5SDimitry Andric       const LocationContext *LCtx = N->getLocationContext();
29750b57cec5SDimitry Andric       const ProgramState *state = N->getState().get();
29760b57cec5SDimitry Andric       if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()),
29770b57cec5SDimitry Andric                                                 LCtx).getAsRegion()) {
29780b57cec5SDimitry Andric         if (report.isInteresting(R))
29790b57cec5SDimitry Andric           prunable = false;
29800b57cec5SDimitry Andric         else {
29810b57cec5SDimitry Andric           const ProgramState *state = N->getState().get();
29820b57cec5SDimitry Andric           SVal V = state->getSVal(R);
29830b57cec5SDimitry Andric           if (report.isInteresting(V))
29840b57cec5SDimitry Andric             prunable = false;
29850b57cec5SDimitry Andric         }
29860b57cec5SDimitry Andric       }
29870b57cec5SDimitry Andric     }
29880b57cec5SDimitry Andric     Out << DR->getDecl()->getDeclName().getAsString();
29890b57cec5SDimitry Andric     if (quotes)
29900b57cec5SDimitry Andric       Out << '\'';
29910b57cec5SDimitry Andric     return quotes;
29920b57cec5SDimitry Andric   }
29930b57cec5SDimitry Andric 
29940b57cec5SDimitry Andric   if (const auto *IL = dyn_cast<IntegerLiteral>(Ex)) {
29950b57cec5SDimitry Andric     QualType OriginalTy = OriginalExpr->getType();
29960b57cec5SDimitry Andric     if (OriginalTy->isPointerType()) {
29970b57cec5SDimitry Andric       if (IL->getValue() == 0) {
29980b57cec5SDimitry Andric         Out << "null";
29990b57cec5SDimitry Andric         return false;
30000b57cec5SDimitry Andric       }
30010b57cec5SDimitry Andric     }
30020b57cec5SDimitry Andric     else if (OriginalTy->isObjCObjectPointerType()) {
30030b57cec5SDimitry Andric       if (IL->getValue() == 0) {
30040b57cec5SDimitry Andric         Out << "nil";
30050b57cec5SDimitry Andric         return false;
30060b57cec5SDimitry Andric       }
30070b57cec5SDimitry Andric     }
30080b57cec5SDimitry Andric 
30090b57cec5SDimitry Andric     Out << IL->getValue();
30100b57cec5SDimitry Andric     return false;
30110b57cec5SDimitry Andric   }
30120b57cec5SDimitry Andric 
30130b57cec5SDimitry Andric   if (const auto *ME = dyn_cast<MemberExpr>(Ex)) {
30140b57cec5SDimitry Andric     if (!IsSameFieldName)
30150b57cec5SDimitry Andric       Out << "field '" << ME->getMemberDecl()->getName() << '\'';
30160b57cec5SDimitry Andric     else
30170b57cec5SDimitry Andric       Out << '\''
30180b57cec5SDimitry Andric           << Lexer::getSourceText(
30190b57cec5SDimitry Andric                  CharSourceRange::getTokenRange(Ex->getSourceRange()),
302004eeddc0SDimitry Andric                  BRC.getSourceManager(), BRC.getASTContext().getLangOpts(),
302104eeddc0SDimitry Andric                  nullptr)
30220b57cec5SDimitry Andric           << '\'';
30230b57cec5SDimitry Andric   }
30240b57cec5SDimitry Andric 
30250b57cec5SDimitry Andric   return false;
30260b57cec5SDimitry Andric }
30270b57cec5SDimitry Andric 
VisitTrueTest(const Expr * Cond,const BinaryOperator * BExpr,BugReporterContext & BRC,PathSensitiveBugReport & R,const ExplodedNode * N,bool TookTrue,bool IsAssuming)3028a7dea167SDimitry Andric PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
30290b57cec5SDimitry Andric     const Expr *Cond, const BinaryOperator *BExpr, BugReporterContext &BRC,
3030a7dea167SDimitry Andric     PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue,
3031a7dea167SDimitry Andric     bool IsAssuming) {
30320b57cec5SDimitry Andric   bool shouldInvert = false;
3033bdd1243dSDimitry Andric   std::optional<bool> shouldPrune;
30340b57cec5SDimitry Andric 
30350b57cec5SDimitry Andric   // Check if the field name of the MemberExprs is ambiguous. Example:
30360b57cec5SDimitry Andric   // " 'a.d' is equal to 'h.d' " in 'test/Analysis/null-deref-path-notes.cpp'.
30370b57cec5SDimitry Andric   bool IsSameFieldName = false;
3038a7dea167SDimitry Andric   const auto *LhsME = dyn_cast<MemberExpr>(BExpr->getLHS()->IgnoreParenCasts());
3039a7dea167SDimitry Andric   const auto *RhsME = dyn_cast<MemberExpr>(BExpr->getRHS()->IgnoreParenCasts());
3040a7dea167SDimitry Andric 
3041a7dea167SDimitry Andric   if (LhsME && RhsME)
3042a7dea167SDimitry Andric     IsSameFieldName =
3043a7dea167SDimitry Andric         LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
30440b57cec5SDimitry Andric 
30450b57cec5SDimitry Andric   SmallString<128> LhsString, RhsString;
30460b57cec5SDimitry Andric   {
30470b57cec5SDimitry Andric     llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
30480b57cec5SDimitry Andric     const bool isVarLHS = patternMatch(BExpr->getLHS(), BExpr, OutLHS, BRC, R,
30490b57cec5SDimitry Andric                                        N, shouldPrune, IsSameFieldName);
30500b57cec5SDimitry Andric     const bool isVarRHS = patternMatch(BExpr->getRHS(), BExpr, OutRHS, BRC, R,
30510b57cec5SDimitry Andric                                        N, shouldPrune, IsSameFieldName);
30520b57cec5SDimitry Andric 
30530b57cec5SDimitry Andric     shouldInvert = !isVarLHS && isVarRHS;
30540b57cec5SDimitry Andric   }
30550b57cec5SDimitry Andric 
30560b57cec5SDimitry Andric   BinaryOperator::Opcode Op = BExpr->getOpcode();
30570b57cec5SDimitry Andric 
30580b57cec5SDimitry Andric   if (BinaryOperator::isAssignmentOp(Op)) {
30590b57cec5SDimitry Andric     // For assignment operators, all that we care about is that the LHS
30600b57cec5SDimitry Andric     // evaluates to "true" or "false".
30610b57cec5SDimitry Andric     return VisitConditionVariable(LhsString, BExpr->getLHS(), BRC, R, N,
30620b57cec5SDimitry Andric                                   TookTrue);
30630b57cec5SDimitry Andric   }
30640b57cec5SDimitry Andric 
30650b57cec5SDimitry Andric   // For non-assignment operations, we require that we can understand
30660b57cec5SDimitry Andric   // both the LHS and RHS.
30670b57cec5SDimitry Andric   if (LhsString.empty() || RhsString.empty() ||
30680b57cec5SDimitry Andric       !BinaryOperator::isComparisonOp(Op) || Op == BO_Cmp)
30690b57cec5SDimitry Andric     return nullptr;
30700b57cec5SDimitry Andric 
30710b57cec5SDimitry Andric   // Should we invert the strings if the LHS is not a variable name?
30720b57cec5SDimitry Andric   SmallString<256> buf;
30730b57cec5SDimitry Andric   llvm::raw_svector_ostream Out(buf);
30740b57cec5SDimitry Andric   Out << (IsAssuming ? "Assuming " : "")
30750b57cec5SDimitry Andric       << (shouldInvert ? RhsString : LhsString) << " is ";
30760b57cec5SDimitry Andric 
30770b57cec5SDimitry Andric   // Do we need to invert the opcode?
30780b57cec5SDimitry Andric   if (shouldInvert)
30790b57cec5SDimitry Andric     switch (Op) {
30800b57cec5SDimitry Andric       default: break;
30810b57cec5SDimitry Andric       case BO_LT: Op = BO_GT; break;
30820b57cec5SDimitry Andric       case BO_GT: Op = BO_LT; break;
30830b57cec5SDimitry Andric       case BO_LE: Op = BO_GE; break;
30840b57cec5SDimitry Andric       case BO_GE: Op = BO_LE; break;
30850b57cec5SDimitry Andric     }
30860b57cec5SDimitry Andric 
30870b57cec5SDimitry Andric   if (!TookTrue)
30880b57cec5SDimitry Andric     switch (Op) {
30890b57cec5SDimitry Andric       case BO_EQ: Op = BO_NE; break;
30900b57cec5SDimitry Andric       case BO_NE: Op = BO_EQ; break;
30910b57cec5SDimitry Andric       case BO_LT: Op = BO_GE; break;
30920b57cec5SDimitry Andric       case BO_GT: Op = BO_LE; break;
30930b57cec5SDimitry Andric       case BO_LE: Op = BO_GT; break;
30940b57cec5SDimitry Andric       case BO_GE: Op = BO_LT; break;
30950b57cec5SDimitry Andric       default:
30960b57cec5SDimitry Andric         return nullptr;
30970b57cec5SDimitry Andric     }
30980b57cec5SDimitry Andric 
30990b57cec5SDimitry Andric   switch (Op) {
31000b57cec5SDimitry Andric     case BO_EQ:
31010b57cec5SDimitry Andric       Out << "equal to ";
31020b57cec5SDimitry Andric       break;
31030b57cec5SDimitry Andric     case BO_NE:
31040b57cec5SDimitry Andric       Out << "not equal to ";
31050b57cec5SDimitry Andric       break;
31060b57cec5SDimitry Andric     default:
31070b57cec5SDimitry Andric       Out << BinaryOperator::getOpcodeStr(Op) << ' ';
31080b57cec5SDimitry Andric       break;
31090b57cec5SDimitry Andric   }
31100b57cec5SDimitry Andric 
31110b57cec5SDimitry Andric   Out << (shouldInvert ? LhsString : RhsString);
31120b57cec5SDimitry Andric   const LocationContext *LCtx = N->getLocationContext();
3113a7dea167SDimitry Andric   const SourceManager &SM = BRC.getSourceManager();
3114a7dea167SDimitry Andric 
3115a7dea167SDimitry Andric   if (isVarAnInterestingCondition(BExpr->getLHS(), N, &R) ||
3116a7dea167SDimitry Andric       isVarAnInterestingCondition(BExpr->getRHS(), N, &R))
3117a7dea167SDimitry Andric     Out << WillBeUsedForACondition;
31180b57cec5SDimitry Andric 
31190b57cec5SDimitry Andric   // Convert 'field ...' to 'Field ...' if it is a MemberExpr.
31205ffd83dbSDimitry Andric   std::string Message = std::string(Out.str());
31210b57cec5SDimitry Andric   Message[0] = toupper(Message[0]);
31220b57cec5SDimitry Andric 
3123a7dea167SDimitry Andric   // If we know the value create a pop-up note to the value part of 'BExpr'.
3124a7dea167SDimitry Andric   if (!IsAssuming) {
3125a7dea167SDimitry Andric     PathDiagnosticLocation Loc;
3126a7dea167SDimitry Andric     if (!shouldInvert) {
3127a7dea167SDimitry Andric       if (LhsME && LhsME->getMemberLoc().isValid())
3128a7dea167SDimitry Andric         Loc = PathDiagnosticLocation(LhsME->getMemberLoc(), SM);
3129a7dea167SDimitry Andric       else
3130a7dea167SDimitry Andric         Loc = PathDiagnosticLocation(BExpr->getLHS(), SM, LCtx);
3131a7dea167SDimitry Andric     } else {
3132a7dea167SDimitry Andric       if (RhsME && RhsME->getMemberLoc().isValid())
3133a7dea167SDimitry Andric         Loc = PathDiagnosticLocation(RhsME->getMemberLoc(), SM);
3134a7dea167SDimitry Andric       else
3135a7dea167SDimitry Andric         Loc = PathDiagnosticLocation(BExpr->getRHS(), SM, LCtx);
3136a7dea167SDimitry Andric     }
31370b57cec5SDimitry Andric 
3138a7dea167SDimitry Andric     return std::make_shared<PathDiagnosticPopUpPiece>(Loc, Message);
3139a7dea167SDimitry Andric   }
3140a7dea167SDimitry Andric 
3141a7dea167SDimitry Andric   PathDiagnosticLocation Loc(Cond, SM, LCtx);
31420b57cec5SDimitry Andric   auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Message);
314381ad6265SDimitry Andric   if (shouldPrune)
3144bdd1243dSDimitry Andric     event->setPrunable(*shouldPrune);
31450b57cec5SDimitry Andric   return event;
31460b57cec5SDimitry Andric }
31470b57cec5SDimitry Andric 
VisitConditionVariable(StringRef LhsString,const Expr * CondVarExpr,BugReporterContext & BRC,PathSensitiveBugReport & report,const ExplodedNode * N,bool TookTrue)3148a7dea167SDimitry Andric PathDiagnosticPieceRef ConditionBRVisitor::VisitConditionVariable(
31490b57cec5SDimitry Andric     StringRef LhsString, const Expr *CondVarExpr, BugReporterContext &BRC,
3150a7dea167SDimitry Andric     PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue) {
31510b57cec5SDimitry Andric   // FIXME: If there's already a constraint tracker for this variable,
31520b57cec5SDimitry Andric   // we shouldn't emit anything here (c.f. the double note in
31530b57cec5SDimitry Andric   // test/Analysis/inlining/path-notes.c)
31540b57cec5SDimitry Andric   SmallString<256> buf;
31550b57cec5SDimitry Andric   llvm::raw_svector_ostream Out(buf);
31560b57cec5SDimitry Andric   Out << "Assuming " << LhsString << " is ";
31570b57cec5SDimitry Andric 
31580b57cec5SDimitry Andric   if (!printValue(CondVarExpr, Out, N, TookTrue, /*IsAssuming=*/true))
31590b57cec5SDimitry Andric     return nullptr;
31600b57cec5SDimitry Andric 
31610b57cec5SDimitry Andric   const LocationContext *LCtx = N->getLocationContext();
31620b57cec5SDimitry Andric   PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx);
3163a7dea167SDimitry Andric 
3164a7dea167SDimitry Andric   if (isVarAnInterestingCondition(CondVarExpr, N, &report))
3165a7dea167SDimitry Andric     Out << WillBeUsedForACondition;
3166a7dea167SDimitry Andric 
31670b57cec5SDimitry Andric   auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Out.str());
31680b57cec5SDimitry Andric 
3169a7dea167SDimitry Andric   if (isInterestingExpr(CondVarExpr, N, &report))
31700b57cec5SDimitry Andric     event->setPrunable(false);
31710b57cec5SDimitry Andric 
31720b57cec5SDimitry Andric   return event;
31730b57cec5SDimitry Andric }
31740b57cec5SDimitry Andric 
VisitTrueTest(const Expr * Cond,const DeclRefExpr * DRE,BugReporterContext & BRC,PathSensitiveBugReport & report,const ExplodedNode * N,bool TookTrue,bool IsAssuming)3175a7dea167SDimitry Andric PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
31760b57cec5SDimitry Andric     const Expr *Cond, const DeclRefExpr *DRE, BugReporterContext &BRC,
3177a7dea167SDimitry Andric     PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue,
3178a7dea167SDimitry Andric     bool IsAssuming) {
31790b57cec5SDimitry Andric   const auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
31800b57cec5SDimitry Andric   if (!VD)
31810b57cec5SDimitry Andric     return nullptr;
31820b57cec5SDimitry Andric 
31830b57cec5SDimitry Andric   SmallString<256> Buf;
31840b57cec5SDimitry Andric   llvm::raw_svector_ostream Out(Buf);
31850b57cec5SDimitry Andric 
31860b57cec5SDimitry Andric   Out << (IsAssuming ? "Assuming '" : "'") << VD->getDeclName() << "' is ";
31870b57cec5SDimitry Andric 
31880b57cec5SDimitry Andric   if (!printValue(DRE, Out, N, TookTrue, IsAssuming))
31890b57cec5SDimitry Andric     return nullptr;
31900b57cec5SDimitry Andric 
31910b57cec5SDimitry Andric   const LocationContext *LCtx = N->getLocationContext();
31920b57cec5SDimitry Andric 
3193a7dea167SDimitry Andric   if (isVarAnInterestingCondition(DRE, N, &report))
3194a7dea167SDimitry Andric     Out << WillBeUsedForACondition;
3195a7dea167SDimitry Andric 
3196a7dea167SDimitry Andric   // If we know the value create a pop-up note to the 'DRE'.
3197a7dea167SDimitry Andric   if (!IsAssuming) {
3198a7dea167SDimitry Andric     PathDiagnosticLocation Loc(DRE, BRC.getSourceManager(), LCtx);
31990b57cec5SDimitry Andric     return std::make_shared<PathDiagnosticPopUpPiece>(Loc, Out.str());
3200a7dea167SDimitry Andric   }
32010b57cec5SDimitry Andric 
3202a7dea167SDimitry Andric   PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
32030b57cec5SDimitry Andric   auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Out.str());
3204a7dea167SDimitry Andric 
3205a7dea167SDimitry Andric   if (isInterestingExpr(DRE, N, &report))
32060b57cec5SDimitry Andric     event->setPrunable(false);
3207a7dea167SDimitry Andric 
32080b57cec5SDimitry Andric   return std::move(event);
32090b57cec5SDimitry Andric }
32100b57cec5SDimitry Andric 
VisitTrueTest(const Expr * Cond,const MemberExpr * ME,BugReporterContext & BRC,PathSensitiveBugReport & report,const ExplodedNode * N,bool TookTrue,bool IsAssuming)3211a7dea167SDimitry Andric PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
32120b57cec5SDimitry Andric     const Expr *Cond, const MemberExpr *ME, BugReporterContext &BRC,
3213a7dea167SDimitry Andric     PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue,
3214a7dea167SDimitry Andric     bool IsAssuming) {
32150b57cec5SDimitry Andric   SmallString<256> Buf;
32160b57cec5SDimitry Andric   llvm::raw_svector_ostream Out(Buf);
32170b57cec5SDimitry Andric 
32180b57cec5SDimitry Andric   Out << (IsAssuming ? "Assuming field '" : "Field '")
32190b57cec5SDimitry Andric       << ME->getMemberDecl()->getName() << "' is ";
32200b57cec5SDimitry Andric 
32210b57cec5SDimitry Andric   if (!printValue(ME, Out, N, TookTrue, IsAssuming))
32220b57cec5SDimitry Andric     return nullptr;
32230b57cec5SDimitry Andric 
32240b57cec5SDimitry Andric   const LocationContext *LCtx = N->getLocationContext();
3225a7dea167SDimitry Andric   PathDiagnosticLocation Loc;
3226a7dea167SDimitry Andric 
3227a7dea167SDimitry Andric   // If we know the value create a pop-up note to the member of the MemberExpr.
3228a7dea167SDimitry Andric   if (!IsAssuming && ME->getMemberLoc().isValid())
3229a7dea167SDimitry Andric     Loc = PathDiagnosticLocation(ME->getMemberLoc(), BRC.getSourceManager());
3230a7dea167SDimitry Andric   else
3231a7dea167SDimitry Andric     Loc = PathDiagnosticLocation(Cond, BRC.getSourceManager(), LCtx);
3232a7dea167SDimitry Andric 
32330b57cec5SDimitry Andric   if (!Loc.isValid() || !Loc.asLocation().isValid())
32340b57cec5SDimitry Andric     return nullptr;
32350b57cec5SDimitry Andric 
3236a7dea167SDimitry Andric   if (isVarAnInterestingCondition(ME, N, &report))
3237a7dea167SDimitry Andric     Out << WillBeUsedForACondition;
3238a7dea167SDimitry Andric 
32390b57cec5SDimitry Andric   // If we know the value create a pop-up note.
32400b57cec5SDimitry Andric   if (!IsAssuming)
32410b57cec5SDimitry Andric     return std::make_shared<PathDiagnosticPopUpPiece>(Loc, Out.str());
32420b57cec5SDimitry Andric 
3243a7dea167SDimitry Andric   auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Out.str());
3244a7dea167SDimitry Andric   if (isInterestingExpr(ME, N, &report))
3245a7dea167SDimitry Andric     event->setPrunable(false);
3246a7dea167SDimitry Andric   return event;
32470b57cec5SDimitry Andric }
32480b57cec5SDimitry Andric 
printValue(const Expr * CondVarExpr,raw_ostream & Out,const ExplodedNode * N,bool TookTrue,bool IsAssuming)32490b57cec5SDimitry Andric bool ConditionBRVisitor::printValue(const Expr *CondVarExpr, raw_ostream &Out,
32500b57cec5SDimitry Andric                                     const ExplodedNode *N, bool TookTrue,
32510b57cec5SDimitry Andric                                     bool IsAssuming) {
32520b57cec5SDimitry Andric   QualType Ty = CondVarExpr->getType();
32530b57cec5SDimitry Andric 
32540b57cec5SDimitry Andric   if (Ty->isPointerType()) {
32550b57cec5SDimitry Andric     Out << (TookTrue ? "non-null" : "null");
32560b57cec5SDimitry Andric     return true;
32570b57cec5SDimitry Andric   }
32580b57cec5SDimitry Andric 
32590b57cec5SDimitry Andric   if (Ty->isObjCObjectPointerType()) {
32600b57cec5SDimitry Andric     Out << (TookTrue ? "non-nil" : "nil");
32610b57cec5SDimitry Andric     return true;
32620b57cec5SDimitry Andric   }
32630b57cec5SDimitry Andric 
32640b57cec5SDimitry Andric   if (!Ty->isIntegralOrEnumerationType())
32650b57cec5SDimitry Andric     return false;
32660b57cec5SDimitry Andric 
3267bdd1243dSDimitry Andric   std::optional<const llvm::APSInt *> IntValue;
32680b57cec5SDimitry Andric   if (!IsAssuming)
32690b57cec5SDimitry Andric     IntValue = getConcreteIntegerValue(CondVarExpr, N);
32700b57cec5SDimitry Andric 
327181ad6265SDimitry Andric   if (IsAssuming || !IntValue) {
32720b57cec5SDimitry Andric     if (Ty->isBooleanType())
32730b57cec5SDimitry Andric       Out << (TookTrue ? "true" : "false");
32740b57cec5SDimitry Andric     else
32750b57cec5SDimitry Andric       Out << (TookTrue ? "not equal to 0" : "0");
32760b57cec5SDimitry Andric   } else {
32770b57cec5SDimitry Andric     if (Ty->isBooleanType())
3278bdd1243dSDimitry Andric       Out << ((*IntValue)->getBoolValue() ? "true" : "false");
32790b57cec5SDimitry Andric     else
3280bdd1243dSDimitry Andric       Out << **IntValue;
32810b57cec5SDimitry Andric   }
32820b57cec5SDimitry Andric 
32830b57cec5SDimitry Andric   return true;
32840b57cec5SDimitry Andric }
32850b57cec5SDimitry Andric 
3286a7dea167SDimitry Andric constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;
3287a7dea167SDimitry Andric constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;
32880b57cec5SDimitry Andric 
isPieceMessageGeneric(const PathDiagnosticPiece * Piece)32890b57cec5SDimitry Andric bool ConditionBRVisitor::isPieceMessageGeneric(
32900b57cec5SDimitry Andric     const PathDiagnosticPiece *Piece) {
32910b57cec5SDimitry Andric   return Piece->getString() == GenericTrueMessage ||
32920b57cec5SDimitry Andric          Piece->getString() == GenericFalseMessage;
32930b57cec5SDimitry Andric }
32940b57cec5SDimitry Andric 
32950b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
32960b57cec5SDimitry Andric // Implementation of LikelyFalsePositiveSuppressionBRVisitor.
32970b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
32980b57cec5SDimitry Andric 
finalizeVisitor(BugReporterContext & BRC,const ExplodedNode * N,PathSensitiveBugReport & BR)32990b57cec5SDimitry Andric void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
3300a7dea167SDimitry Andric     BugReporterContext &BRC, const ExplodedNode *N,
3301a7dea167SDimitry Andric     PathSensitiveBugReport &BR) {
33020b57cec5SDimitry Andric   // Here we suppress false positives coming from system headers. This list is
33030b57cec5SDimitry Andric   // based on known issues.
3304a7dea167SDimitry Andric   const AnalyzerOptions &Options = BRC.getAnalyzerOptions();
33050b57cec5SDimitry Andric   const Decl *D = N->getLocationContext()->getDecl();
33060b57cec5SDimitry Andric 
33070b57cec5SDimitry Andric   if (AnalysisDeclContext::isInStdNamespace(D)) {
33080b57cec5SDimitry Andric     // Skip reports within the 'std' namespace. Although these can sometimes be
33090b57cec5SDimitry Andric     // the user's fault, we currently don't report them very well, and
33100b57cec5SDimitry Andric     // Note that this will not help for any other data structure libraries, like
33110b57cec5SDimitry Andric     // TR1, Boost, or llvm/ADT.
33120b57cec5SDimitry Andric     if (Options.ShouldSuppressFromCXXStandardLibrary) {
33130b57cec5SDimitry Andric       BR.markInvalid(getTag(), nullptr);
33140b57cec5SDimitry Andric       return;
33150b57cec5SDimitry Andric     } else {
33160b57cec5SDimitry Andric       // If the complete 'std' suppression is not enabled, suppress reports
33170b57cec5SDimitry Andric       // from the 'std' namespace that are known to produce false positives.
33180b57cec5SDimitry Andric 
33190b57cec5SDimitry Andric       // The analyzer issues a false use-after-free when std::list::pop_front
33200b57cec5SDimitry Andric       // or std::list::pop_back are called multiple times because we cannot
33210b57cec5SDimitry Andric       // reason about the internal invariants of the data structure.
33220b57cec5SDimitry Andric       if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
33230b57cec5SDimitry Andric         const CXXRecordDecl *CD = MD->getParent();
33240b57cec5SDimitry Andric         if (CD->getName() == "list") {
33250b57cec5SDimitry Andric           BR.markInvalid(getTag(), nullptr);
33260b57cec5SDimitry Andric           return;
33270b57cec5SDimitry Andric         }
33280b57cec5SDimitry Andric       }
33290b57cec5SDimitry Andric 
33300b57cec5SDimitry Andric       // The analyzer issues a false positive when the constructor of
33310b57cec5SDimitry Andric       // std::__independent_bits_engine from algorithms is used.
33320b57cec5SDimitry Andric       if (const auto *MD = dyn_cast<CXXConstructorDecl>(D)) {
33330b57cec5SDimitry Andric         const CXXRecordDecl *CD = MD->getParent();
33340b57cec5SDimitry Andric         if (CD->getName() == "__independent_bits_engine") {
33350b57cec5SDimitry Andric           BR.markInvalid(getTag(), nullptr);
33360b57cec5SDimitry Andric           return;
33370b57cec5SDimitry Andric         }
33380b57cec5SDimitry Andric       }
33390b57cec5SDimitry Andric 
33400b57cec5SDimitry Andric       for (const LocationContext *LCtx = N->getLocationContext(); LCtx;
33410b57cec5SDimitry Andric            LCtx = LCtx->getParent()) {
33420b57cec5SDimitry Andric         const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
33430b57cec5SDimitry Andric         if (!MD)
33440b57cec5SDimitry Andric           continue;
33450b57cec5SDimitry Andric 
33460b57cec5SDimitry Andric         const CXXRecordDecl *CD = MD->getParent();
33470b57cec5SDimitry Andric         // The analyzer issues a false positive on
33480b57cec5SDimitry Andric         //   std::basic_string<uint8_t> v; v.push_back(1);
33490b57cec5SDimitry Andric         // and
33500b57cec5SDimitry Andric         //   std::u16string s; s += u'a';
33510b57cec5SDimitry Andric         // because we cannot reason about the internal invariants of the
33520b57cec5SDimitry Andric         // data structure.
33530b57cec5SDimitry Andric         if (CD->getName() == "basic_string") {
33540b57cec5SDimitry Andric           BR.markInvalid(getTag(), nullptr);
33550b57cec5SDimitry Andric           return;
33560b57cec5SDimitry Andric         }
33570b57cec5SDimitry Andric 
33580b57cec5SDimitry Andric         // The analyzer issues a false positive on
33590b57cec5SDimitry Andric         //    std::shared_ptr<int> p(new int(1)); p = nullptr;
33600b57cec5SDimitry Andric         // because it does not reason properly about temporary destructors.
33610b57cec5SDimitry Andric         if (CD->getName() == "shared_ptr") {
33620b57cec5SDimitry Andric           BR.markInvalid(getTag(), nullptr);
33630b57cec5SDimitry Andric           return;
33640b57cec5SDimitry Andric         }
33650b57cec5SDimitry Andric       }
33660b57cec5SDimitry Andric     }
33670b57cec5SDimitry Andric   }
33680b57cec5SDimitry Andric 
33690b57cec5SDimitry Andric   // Skip reports within the sys/queue.h macros as we do not have the ability to
33700b57cec5SDimitry Andric   // reason about data structure shapes.
3371a7dea167SDimitry Andric   const SourceManager &SM = BRC.getSourceManager();
3372a7dea167SDimitry Andric   FullSourceLoc Loc = BR.getLocation().asLocation();
33730b57cec5SDimitry Andric   while (Loc.isMacroID()) {
33740b57cec5SDimitry Andric     Loc = Loc.getSpellingLoc();
33755f757f3fSDimitry Andric     if (SM.getFilename(Loc).ends_with("sys/queue.h")) {
33760b57cec5SDimitry Andric       BR.markInvalid(getTag(), nullptr);
33770b57cec5SDimitry Andric       return;
33780b57cec5SDimitry Andric     }
33790b57cec5SDimitry Andric   }
33800b57cec5SDimitry Andric }
33810b57cec5SDimitry Andric 
33820b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
33830b57cec5SDimitry Andric // Implementation of UndefOrNullArgVisitor.
33840b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
33850b57cec5SDimitry Andric 
3386a7dea167SDimitry Andric PathDiagnosticPieceRef
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)3387a7dea167SDimitry Andric UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
3388a7dea167SDimitry Andric                                  PathSensitiveBugReport &BR) {
33890b57cec5SDimitry Andric   ProgramStateRef State = N->getState();
33900b57cec5SDimitry Andric   ProgramPoint ProgLoc = N->getLocation();
33910b57cec5SDimitry Andric 
33920b57cec5SDimitry Andric   // We are only interested in visiting CallEnter nodes.
3393bdd1243dSDimitry Andric   std::optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>();
33940b57cec5SDimitry Andric   if (!CEnter)
33950b57cec5SDimitry Andric     return nullptr;
33960b57cec5SDimitry Andric 
33970b57cec5SDimitry Andric   // Check if one of the arguments is the region the visitor is tracking.
33980b57cec5SDimitry Andric   CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
33990b57cec5SDimitry Andric   CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State);
34000b57cec5SDimitry Andric   unsigned Idx = 0;
34010b57cec5SDimitry Andric   ArrayRef<ParmVarDecl *> parms = Call->parameters();
34020b57cec5SDimitry Andric 
34030b57cec5SDimitry Andric   for (const auto ParamDecl : parms) {
34040b57cec5SDimitry Andric     const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion();
34050b57cec5SDimitry Andric     ++Idx;
34060b57cec5SDimitry Andric 
34070b57cec5SDimitry Andric     // Are we tracking the argument or its subregion?
34080b57cec5SDimitry Andric     if ( !ArgReg || !R->isSubRegionOf(ArgReg->StripCasts()))
34090b57cec5SDimitry Andric       continue;
34100b57cec5SDimitry Andric 
34110b57cec5SDimitry Andric     // Check the function parameter type.
34120b57cec5SDimitry Andric     assert(ParamDecl && "Formal parameter has no decl?");
34130b57cec5SDimitry Andric     QualType T = ParamDecl->getType();
34140b57cec5SDimitry Andric 
34150b57cec5SDimitry Andric     if (!(T->isAnyPointerType() || T->isReferenceType())) {
34160b57cec5SDimitry Andric       // Function can only change the value passed in by address.
34170b57cec5SDimitry Andric       continue;
34180b57cec5SDimitry Andric     }
34190b57cec5SDimitry Andric 
34200b57cec5SDimitry Andric     // If it is a const pointer value, the function does not intend to
34210b57cec5SDimitry Andric     // change the value.
34220b57cec5SDimitry Andric     if (T->getPointeeType().isConstQualified())
34230b57cec5SDimitry Andric       continue;
34240b57cec5SDimitry Andric 
34250b57cec5SDimitry Andric     // Mark the call site (LocationContext) as interesting if the value of the
34260b57cec5SDimitry Andric     // argument is undefined or '0'/'NULL'.
34270b57cec5SDimitry Andric     SVal BoundVal = State->getSVal(R);
34280b57cec5SDimitry Andric     if (BoundVal.isUndef() || BoundVal.isZeroConstant()) {
34290b57cec5SDimitry Andric       BR.markInteresting(CEnter->getCalleeContext());
34300b57cec5SDimitry Andric       return nullptr;
34310b57cec5SDimitry Andric     }
34320b57cec5SDimitry Andric   }
34330b57cec5SDimitry Andric   return nullptr;
34340b57cec5SDimitry Andric }
34350b57cec5SDimitry Andric 
34360b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
34370b57cec5SDimitry Andric // Implementation of FalsePositiveRefutationBRVisitor.
34380b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
34390b57cec5SDimitry Andric 
FalsePositiveRefutationBRVisitor()34400b57cec5SDimitry Andric FalsePositiveRefutationBRVisitor::FalsePositiveRefutationBRVisitor()
3441e8d8bef9SDimitry Andric     : Constraints(ConstraintMap::Factory().getEmptyMap()) {}
34420b57cec5SDimitry Andric 
finalizeVisitor(BugReporterContext & BRC,const ExplodedNode * EndPathNode,PathSensitiveBugReport & BR)34430b57cec5SDimitry Andric void FalsePositiveRefutationBRVisitor::finalizeVisitor(
3444a7dea167SDimitry Andric     BugReporterContext &BRC, const ExplodedNode *EndPathNode,
3445a7dea167SDimitry Andric     PathSensitiveBugReport &BR) {
34460b57cec5SDimitry Andric   // Collect new constraints
34475ffd83dbSDimitry Andric   addConstraints(EndPathNode, /*OverwriteConstraintsOnExistingSyms=*/true);
34480b57cec5SDimitry Andric 
34490b57cec5SDimitry Andric   // Create a refutation manager
34500b57cec5SDimitry Andric   llvm::SMTSolverRef RefutationSolver = llvm::CreateZ3Solver();
34510b57cec5SDimitry Andric   ASTContext &Ctx = BRC.getASTContext();
34520b57cec5SDimitry Andric 
34530b57cec5SDimitry Andric   // Add constraints to the solver
34540b57cec5SDimitry Andric   for (const auto &I : Constraints) {
34550b57cec5SDimitry Andric     const SymbolRef Sym = I.first;
34560b57cec5SDimitry Andric     auto RangeIt = I.second.begin();
34570b57cec5SDimitry Andric 
34585ffd83dbSDimitry Andric     llvm::SMTExprRef SMTConstraints = SMTConv::getRangeExpr(
34590b57cec5SDimitry Andric         RefutationSolver, Ctx, Sym, RangeIt->From(), RangeIt->To(),
34600b57cec5SDimitry Andric         /*InRange=*/true);
34610b57cec5SDimitry Andric     while ((++RangeIt) != I.second.end()) {
34625ffd83dbSDimitry Andric       SMTConstraints = RefutationSolver->mkOr(
34635ffd83dbSDimitry Andric           SMTConstraints, SMTConv::getRangeExpr(RefutationSolver, Ctx, Sym,
34640b57cec5SDimitry Andric                                                 RangeIt->From(), RangeIt->To(),
34650b57cec5SDimitry Andric                                                 /*InRange=*/true));
34660b57cec5SDimitry Andric     }
34670b57cec5SDimitry Andric 
34685ffd83dbSDimitry Andric     RefutationSolver->addConstraint(SMTConstraints);
34690b57cec5SDimitry Andric   }
34700b57cec5SDimitry Andric 
34710b57cec5SDimitry Andric   // And check for satisfiability
3472bdd1243dSDimitry Andric   std::optional<bool> IsSAT = RefutationSolver->check();
347381ad6265SDimitry Andric   if (!IsSAT)
34740b57cec5SDimitry Andric     return;
34750b57cec5SDimitry Andric 
3476bdd1243dSDimitry Andric   if (!*IsSAT)
34770b57cec5SDimitry Andric     BR.markInvalid("Infeasible constraints", EndPathNode->getLocationContext());
34780b57cec5SDimitry Andric }
34790b57cec5SDimitry Andric 
addConstraints(const ExplodedNode * N,bool OverwriteConstraintsOnExistingSyms)34805ffd83dbSDimitry Andric void FalsePositiveRefutationBRVisitor::addConstraints(
34815ffd83dbSDimitry Andric     const ExplodedNode *N, bool OverwriteConstraintsOnExistingSyms) {
34820b57cec5SDimitry Andric   // Collect new constraints
3483e8d8bef9SDimitry Andric   ConstraintMap NewCs = getConstraintMap(N->getState());
3484e8d8bef9SDimitry Andric   ConstraintMap::Factory &CF = N->getState()->get_context<ConstraintMap>();
34850b57cec5SDimitry Andric 
34860b57cec5SDimitry Andric   // Add constraints if we don't have them yet
34870b57cec5SDimitry Andric   for (auto const &C : NewCs) {
34880b57cec5SDimitry Andric     const SymbolRef &Sym = C.first;
34890b57cec5SDimitry Andric     if (!Constraints.contains(Sym)) {
34905ffd83dbSDimitry Andric       // This symbol is new, just add the constraint.
34915ffd83dbSDimitry Andric       Constraints = CF.add(Constraints, Sym, C.second);
34925ffd83dbSDimitry Andric     } else if (OverwriteConstraintsOnExistingSyms) {
34935ffd83dbSDimitry Andric       // Overwrite the associated constraint of the Symbol.
34945ffd83dbSDimitry Andric       Constraints = CF.remove(Constraints, Sym);
34950b57cec5SDimitry Andric       Constraints = CF.add(Constraints, Sym, C.second);
34960b57cec5SDimitry Andric     }
34970b57cec5SDimitry Andric   }
34985ffd83dbSDimitry Andric }
34990b57cec5SDimitry Andric 
VisitNode(const ExplodedNode * N,BugReporterContext &,PathSensitiveBugReport &)35005ffd83dbSDimitry Andric PathDiagnosticPieceRef FalsePositiveRefutationBRVisitor::VisitNode(
35015ffd83dbSDimitry Andric     const ExplodedNode *N, BugReporterContext &, PathSensitiveBugReport &) {
35025ffd83dbSDimitry Andric   addConstraints(N, /*OverwriteConstraintsOnExistingSyms=*/false);
35030b57cec5SDimitry Andric   return nullptr;
35040b57cec5SDimitry Andric }
35050b57cec5SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const35060b57cec5SDimitry Andric void FalsePositiveRefutationBRVisitor::Profile(
35070b57cec5SDimitry Andric     llvm::FoldingSetNodeID &ID) const {
35080b57cec5SDimitry Andric   static int Tag = 0;
35090b57cec5SDimitry Andric   ID.AddPointer(&Tag);
35100b57cec5SDimitry Andric }
35110b57cec5SDimitry Andric 
35120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
35130b57cec5SDimitry Andric // Implementation of TagVisitor.
35140b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
35150b57cec5SDimitry Andric 
35160b57cec5SDimitry Andric int NoteTag::Kind = 0;
35170b57cec5SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const35180b57cec5SDimitry Andric void TagVisitor::Profile(llvm::FoldingSetNodeID &ID) const {
35190b57cec5SDimitry Andric   static int Tag = 0;
35200b57cec5SDimitry Andric   ID.AddPointer(&Tag);
35210b57cec5SDimitry Andric }
35220b57cec5SDimitry Andric 
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & R)3523a7dea167SDimitry Andric PathDiagnosticPieceRef TagVisitor::VisitNode(const ExplodedNode *N,
3524a7dea167SDimitry Andric                                              BugReporterContext &BRC,
3525a7dea167SDimitry Andric                                              PathSensitiveBugReport &R) {
35260b57cec5SDimitry Andric   ProgramPoint PP = N->getLocation();
35270b57cec5SDimitry Andric   const NoteTag *T = dyn_cast_or_null<NoteTag>(PP.getTag());
35280b57cec5SDimitry Andric   if (!T)
35290b57cec5SDimitry Andric     return nullptr;
35300b57cec5SDimitry Andric 
3531bdd1243dSDimitry Andric   if (std::optional<std::string> Msg = T->generateMessage(BRC, R)) {
35320b57cec5SDimitry Andric     PathDiagnosticLocation Loc =
35330b57cec5SDimitry Andric         PathDiagnosticLocation::create(PP, BRC.getSourceManager());
35340b57cec5SDimitry Andric     auto Piece = std::make_shared<PathDiagnosticEventPiece>(Loc, *Msg);
35350b57cec5SDimitry Andric     Piece->setPrunable(T->isPrunable());
35360b57cec5SDimitry Andric     return Piece;
35370b57cec5SDimitry Andric   }
35380b57cec5SDimitry Andric 
35390b57cec5SDimitry Andric   return nullptr;
35400b57cec5SDimitry Andric }
3541