xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- BugReporterVisitors.cpp - Helpers for reporting bugs ---------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  This file defines a set of BugReporter "visitors" which can be used to
10 //  enhance the diagnostics reported for a bug.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclBase.h"
18 #include "clang/AST/DeclCXX.h"
19 #include "clang/AST/Expr.h"
20 #include "clang/AST/ExprCXX.h"
21 #include "clang/AST/ExprObjC.h"
22 #include "clang/AST/Stmt.h"
23 #include "clang/AST/Type.h"
24 #include "clang/ASTMatchers/ASTMatchFinder.h"
25 #include "clang/Analysis/Analyses/Dominators.h"
26 #include "clang/Analysis/AnalysisDeclContext.h"
27 #include "clang/Analysis/CFG.h"
28 #include "clang/Analysis/CFGStmtMap.h"
29 #include "clang/Analysis/PathDiagnostic.h"
30 #include "clang/Analysis/ProgramPoint.h"
31 #include "clang/Basic/IdentifierTable.h"
32 #include "clang/Basic/LLVM.h"
33 #include "clang/Basic/SourceLocation.h"
34 #include "clang/Basic/SourceManager.h"
35 #include "clang/Lex/Lexer.h"
36 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
37 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
38 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
39 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
40 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
41 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
42 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
43 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
44 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
45 #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
46 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
47 #include "llvm/ADT/ArrayRef.h"
48 #include "llvm/ADT/SmallPtrSet.h"
49 #include "llvm/ADT/SmallString.h"
50 #include "llvm/ADT/StringExtras.h"
51 #include "llvm/ADT/StringRef.h"
52 #include "llvm/Support/Casting.h"
53 #include "llvm/Support/ErrorHandling.h"
54 #include "llvm/Support/raw_ostream.h"
55 #include <cassert>
56 #include <memory>
57 #include <optional>
58 #include <stack>
59 #include <string>
60 #include <utility>
61 
62 using namespace clang;
63 using namespace ento;
64 using namespace bugreporter;
65 
66 //===----------------------------------------------------------------------===//
67 // Utility functions.
68 //===----------------------------------------------------------------------===//
69 
peelOffPointerArithmetic(const BinaryOperator * B)70 static const Expr *peelOffPointerArithmetic(const BinaryOperator *B) {
71   if (B->isAdditiveOp() && B->getType()->isPointerType()) {
72     if (B->getLHS()->getType()->isPointerType()) {
73       return B->getLHS();
74     } else if (B->getRHS()->getType()->isPointerType()) {
75       return B->getRHS();
76     }
77   }
78   return nullptr;
79 }
80 
81 /// \return A subexpression of @c Ex which represents the
82 /// expression-of-interest.
83 static const Expr *peelOffOuterExpr(const Expr *Ex, const ExplodedNode *N);
84 
85 /// Given that expression S represents a pointer that would be dereferenced,
86 /// try to find a sub-expression from which the pointer came from.
87 /// This is used for tracking down origins of a null or undefined value:
88 /// "this is null because that is null because that is null" etc.
89 /// We wipe away field and element offsets because they merely add offsets.
90 /// We also wipe away all casts except lvalue-to-rvalue casts, because the
91 /// latter represent an actual pointer dereference; however, we remove
92 /// the final lvalue-to-rvalue cast before returning from this function
93 /// because it demonstrates more clearly from where the pointer rvalue was
94 /// loaded. Examples:
95 ///   x->y.z      ==>  x (lvalue)
96 ///   foo()->y.z  ==>  foo() (rvalue)
getDerefExpr(const Stmt * S)97 const Expr *bugreporter::getDerefExpr(const Stmt *S) {
98   const auto *E = dyn_cast<Expr>(S);
99   if (!E)
100     return nullptr;
101 
102   while (true) {
103     if (const auto *CE = dyn_cast<CastExpr>(E)) {
104       if (CE->getCastKind() == CK_LValueToRValue) {
105         // This cast represents the load we're looking for.
106         break;
107       }
108       E = CE->getSubExpr();
109     } else if (const auto *B = dyn_cast<BinaryOperator>(E)) {
110       // Pointer arithmetic: '*(x + 2)' -> 'x') etc.
111       if (const Expr *Inner = peelOffPointerArithmetic(B)) {
112         E = Inner;
113       } else if (B->isAssignmentOp()) {
114         // Follow LHS of assignments: '*p = 404' -> 'p'.
115         E = B->getLHS();
116       } else {
117         // Probably more arithmetic can be pattern-matched here,
118         // but for now give up.
119         break;
120       }
121     } else if (const auto *U = dyn_cast<UnaryOperator>(E)) {
122       if (U->getOpcode() == UO_Deref || U->getOpcode() == UO_AddrOf ||
123           (U->isIncrementDecrementOp() && U->getType()->isPointerType())) {
124         // Operators '*' and '&' don't actually mean anything.
125         // We look at casts instead.
126         E = U->getSubExpr();
127       } else {
128         // Probably more arithmetic can be pattern-matched here,
129         // but for now give up.
130         break;
131       }
132     }
133     // Pattern match for a few useful cases: a[0], p->f, *p etc.
134     else if (const auto *ME = dyn_cast<MemberExpr>(E)) {
135       // This handles the case when the dereferencing of a member reference
136       // happens. This is needed, because the AST for dereferencing a
137       // member reference looks like the following:
138       // |-MemberExpr
139       //  `-DeclRefExpr
140       // Without this special case the notes would refer to the whole object
141       // (struct, class or union variable) instead of just the relevant member.
142 
143       if (ME->getMemberDecl()->getType()->isReferenceType())
144         break;
145       E = ME->getBase();
146     } else if (const auto *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
147       E = IvarRef->getBase();
148     } else if (const auto *AE = dyn_cast<ArraySubscriptExpr>(E)) {
149       E = AE->getBase();
150     } else if (const auto *PE = dyn_cast<ParenExpr>(E)) {
151       E = PE->getSubExpr();
152     } else if (const auto *FE = dyn_cast<FullExpr>(E)) {
153       E = FE->getSubExpr();
154     } else {
155       // Other arbitrary stuff.
156       break;
157     }
158   }
159 
160   // Special case: remove the final lvalue-to-rvalue cast, but do not recurse
161   // deeper into the sub-expression. This way we return the lvalue from which
162   // our pointer rvalue was loaded.
163   if (const auto *CE = dyn_cast<ImplicitCastExpr>(E))
164     if (CE->getCastKind() == CK_LValueToRValue)
165       E = CE->getSubExpr();
166 
167   return E;
168 }
169 
getVarDeclForExpression(const Expr * E)170 static const VarDecl *getVarDeclForExpression(const Expr *E) {
171   if (const auto *DR = dyn_cast<DeclRefExpr>(E))
172     return dyn_cast<VarDecl>(DR->getDecl());
173   return nullptr;
174 }
175 
176 static const MemRegion *
getLocationRegionIfReference(const Expr * E,const ExplodedNode * N,bool LookingForReference=true)177 getLocationRegionIfReference(const Expr *E, const ExplodedNode *N,
178                              bool LookingForReference = true) {
179   if (const auto *ME = dyn_cast<MemberExpr>(E)) {
180     // This handles null references from FieldRegions, for example:
181     //   struct Wrapper { int &ref; };
182     //   Wrapper w = { *(int *)0 };
183     //   w.ref = 1;
184     const Expr *Base = ME->getBase();
185     const VarDecl *VD = getVarDeclForExpression(Base);
186     if (!VD)
187       return nullptr;
188 
189     const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
190     if (!FD)
191       return nullptr;
192 
193     if (FD->getType()->isReferenceType()) {
194       SVal StructSVal = N->getState()->getLValue(VD, N->getLocationContext());
195       return N->getState()->getLValue(FD, StructSVal).getAsRegion();
196     }
197     return nullptr;
198   }
199 
200   const VarDecl *VD = getVarDeclForExpression(E);
201   if (!VD)
202     return nullptr;
203   if (LookingForReference && !VD->getType()->isReferenceType())
204     return nullptr;
205   return N->getState()->getLValue(VD, N->getLocationContext()).getAsRegion();
206 }
207 
208 /// Comparing internal representations of symbolic values (via
209 /// SVal::operator==()) is a valid way to check if the value was updated,
210 /// unless it's a LazyCompoundVal that may have a different internal
211 /// representation every time it is loaded from the state. In this function we
212 /// do an approximate comparison for lazy compound values, checking that they
213 /// are the immediate snapshots of the tracked region's bindings within the
214 /// node's respective states but not really checking that these snapshots
215 /// actually contain the same set of bindings.
hasVisibleUpdate(const ExplodedNode * LeftNode,SVal LeftVal,const ExplodedNode * RightNode,SVal RightVal)216 static bool hasVisibleUpdate(const ExplodedNode *LeftNode, SVal LeftVal,
217                              const ExplodedNode *RightNode, SVal RightVal) {
218   if (LeftVal == RightVal)
219     return true;
220 
221   const auto LLCV = LeftVal.getAs<nonloc::LazyCompoundVal>();
222   if (!LLCV)
223     return false;
224 
225   const auto RLCV = RightVal.getAs<nonloc::LazyCompoundVal>();
226   if (!RLCV)
227     return false;
228 
229   return LLCV->getRegion() == RLCV->getRegion() &&
230     LLCV->getStore() == LeftNode->getState()->getStore() &&
231     RLCV->getStore() == RightNode->getState()->getStore();
232 }
233 
getSValForVar(const Expr * CondVarExpr,const ExplodedNode * N)234 static std::optional<SVal> getSValForVar(const Expr *CondVarExpr,
235                                          const ExplodedNode *N) {
236   ProgramStateRef State = N->getState();
237   const LocationContext *LCtx = N->getLocationContext();
238 
239   assert(CondVarExpr);
240   CondVarExpr = CondVarExpr->IgnoreImpCasts();
241 
242   // The declaration of the value may rely on a pointer so take its l-value.
243   // FIXME: As seen in VisitCommonDeclRefExpr, sometimes DeclRefExpr may
244   // evaluate to a FieldRegion when it refers to a declaration of a lambda
245   // capture variable. We most likely need to duplicate that logic here.
246   if (const auto *DRE = dyn_cast<DeclRefExpr>(CondVarExpr))
247     if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
248       return State->getSVal(State->getLValue(VD, LCtx));
249 
250   if (const auto *ME = dyn_cast<MemberExpr>(CondVarExpr))
251     if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
252       if (auto FieldL = State->getSVal(ME, LCtx).getAs<Loc>())
253         return State->getRawSVal(*FieldL, FD->getType());
254 
255   return std::nullopt;
256 }
257 
258 static std::optional<const llvm::APSInt *>
getConcreteIntegerValue(const Expr * CondVarExpr,const ExplodedNode * N)259 getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N) {
260 
261   if (std::optional<SVal> V = getSValForVar(CondVarExpr, N))
262     if (auto CI = V->getAs<nonloc::ConcreteInt>())
263       return CI->getValue().get();
264   return std::nullopt;
265 }
266 
isVarAnInterestingCondition(const Expr * CondVarExpr,const ExplodedNode * N,const PathSensitiveBugReport * B)267 static bool isVarAnInterestingCondition(const Expr *CondVarExpr,
268                                         const ExplodedNode *N,
269                                         const PathSensitiveBugReport *B) {
270   // Even if this condition is marked as interesting, it isn't *that*
271   // interesting if it didn't happen in a nested stackframe, the user could just
272   // follow the arrows.
273   if (!B->getErrorNode()->getStackFrame()->isParentOf(N->getStackFrame()))
274     return false;
275 
276   if (std::optional<SVal> V = getSValForVar(CondVarExpr, N))
277     if (std::optional<bugreporter::TrackingKind> K =
278             B->getInterestingnessKind(*V))
279       return *K == bugreporter::TrackingKind::Condition;
280 
281   return false;
282 }
283 
isInterestingExpr(const Expr * E,const ExplodedNode * N,const PathSensitiveBugReport * B)284 static bool isInterestingExpr(const Expr *E, const ExplodedNode *N,
285                               const PathSensitiveBugReport *B) {
286   if (std::optional<SVal> V = getSValForVar(E, N))
287     return B->getInterestingnessKind(*V).has_value();
288   return false;
289 }
290 
291 /// \return name of the macro inside the location \p Loc.
getMacroName(SourceLocation Loc,BugReporterContext & BRC)292 static StringRef getMacroName(SourceLocation Loc,
293     BugReporterContext &BRC) {
294   return Lexer::getImmediateMacroName(
295       Loc,
296       BRC.getSourceManager(),
297       BRC.getASTContext().getLangOpts());
298 }
299 
300 /// \return Whether given spelling location corresponds to an expansion
301 /// of a function-like macro.
isFunctionMacroExpansion(SourceLocation Loc,const SourceManager & SM)302 static bool isFunctionMacroExpansion(SourceLocation Loc,
303                                 const SourceManager &SM) {
304   if (!Loc.isMacroID())
305     return false;
306   while (SM.isMacroArgExpansion(Loc))
307     Loc = SM.getImmediateExpansionRange(Loc).getBegin();
308   FileIDAndOffset TLInfo = SM.getDecomposedLoc(Loc);
309   SrcMgr::SLocEntry SE = SM.getSLocEntry(TLInfo.first);
310   const SrcMgr::ExpansionInfo &EInfo = SE.getExpansion();
311   return EInfo.isFunctionMacroExpansion();
312 }
313 
314 /// \return Whether \c RegionOfInterest was modified at \p N,
315 /// where \p ValueAfter is \c RegionOfInterest's value at the end of the
316 /// stack frame.
wasRegionOfInterestModifiedAt(const SubRegion * RegionOfInterest,const ExplodedNode * N,SVal ValueAfter)317 static bool wasRegionOfInterestModifiedAt(const SubRegion *RegionOfInterest,
318                                           const ExplodedNode *N,
319                                           SVal ValueAfter) {
320   ProgramStateRef State = N->getState();
321   ProgramStateManager &Mgr = N->getState()->getStateManager();
322 
323   if (!N->getLocationAs<PostStore>() && !N->getLocationAs<PostInitializer>() &&
324       !N->getLocationAs<PostStmt>())
325     return false;
326 
327   // Writing into region of interest.
328   if (auto PS = N->getLocationAs<PostStmt>())
329     if (auto *BO = PS->getStmtAs<BinaryOperator>())
330       if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(
331                                       N->getSVal(BO->getLHS()).getAsRegion()))
332         return true;
333 
334   // SVal after the state is possibly different.
335   SVal ValueAtN = N->getState()->getSVal(RegionOfInterest);
336   if (!Mgr.getSValBuilder()
337            .areEqual(State, ValueAtN, ValueAfter)
338            .isConstrainedTrue() &&
339       (!ValueAtN.isUndef() || !ValueAfter.isUndef()))
340     return true;
341 
342   return false;
343 }
344 
345 //===----------------------------------------------------------------------===//
346 // Implementation of BugReporterVisitor.
347 //===----------------------------------------------------------------------===//
348 
getEndPath(BugReporterContext &,const ExplodedNode *,PathSensitiveBugReport &)349 PathDiagnosticPieceRef BugReporterVisitor::getEndPath(BugReporterContext &,
350                                                       const ExplodedNode *,
351                                                       PathSensitiveBugReport &) {
352   return nullptr;
353 }
354 
finalizeVisitor(BugReporterContext &,const ExplodedNode *,PathSensitiveBugReport &)355 void BugReporterVisitor::finalizeVisitor(BugReporterContext &,
356                                          const ExplodedNode *,
357                                          PathSensitiveBugReport &) {}
358 
359 PathDiagnosticPieceRef
getDefaultEndPath(const BugReporterContext & BRC,const ExplodedNode * EndPathNode,const PathSensitiveBugReport & BR)360 BugReporterVisitor::getDefaultEndPath(const BugReporterContext &BRC,
361                                       const ExplodedNode *EndPathNode,
362                                       const PathSensitiveBugReport &BR) {
363   PathDiagnosticLocation L = BR.getLocation();
364   const auto &Ranges = BR.getRanges();
365 
366   // Only add the statement itself as a range if we didn't specify any
367   // special ranges for this report.
368   auto P = std::make_shared<PathDiagnosticEventPiece>(
369       L, BR.getDescription(), Ranges.begin() == Ranges.end());
370   for (SourceRange Range : Ranges)
371     P->addRange(Range);
372 
373   return P;
374 }
375 
376 //===----------------------------------------------------------------------===//
377 // Implementation of NoStateChangeFuncVisitor.
378 //===----------------------------------------------------------------------===//
379 
isModifiedInFrame(const ExplodedNode * N)380 bool NoStateChangeFuncVisitor::isModifiedInFrame(const ExplodedNode *N) {
381   const LocationContext *Ctx = N->getLocationContext();
382   const StackFrameContext *SCtx = Ctx->getStackFrame();
383   if (!FramesModifyingCalculated.count(SCtx))
384     findModifyingFrames(N);
385   return FramesModifying.count(SCtx);
386 }
387 
markFrameAsModifying(const StackFrameContext * SCtx)388 void NoStateChangeFuncVisitor::markFrameAsModifying(
389     const StackFrameContext *SCtx) {
390   while (!SCtx->inTopFrame()) {
391     auto p = FramesModifying.insert(SCtx);
392     if (!p.second)
393       break; // Frame and all its parents already inserted.
394 
395     SCtx = SCtx->getParent()->getStackFrame();
396   }
397 }
398 
getMatchingCallExitEnd(const ExplodedNode * N)399 static const ExplodedNode *getMatchingCallExitEnd(const ExplodedNode *N) {
400   assert(N->getLocationAs<CallEnter>());
401   // The stackframe of the callee is only found in the nodes succeeding
402   // the CallEnter node. CallEnter's stack frame refers to the caller.
403   const StackFrameContext *OrigSCtx = N->getFirstSucc()->getStackFrame();
404 
405   // Similarly, the nodes preceding CallExitEnd refer to the callee's stack
406   // frame.
407   auto IsMatchingCallExitEnd = [OrigSCtx](const ExplodedNode *N) {
408     return N->getLocationAs<CallExitEnd>() &&
409            OrigSCtx == N->getFirstPred()->getStackFrame();
410   };
411   while (N && !IsMatchingCallExitEnd(N)) {
412     assert(N->succ_size() <= 1 &&
413            "This function is to be used on the trimmed ExplodedGraph!");
414     N = N->getFirstSucc();
415   }
416   return N;
417 }
418 
findModifyingFrames(const ExplodedNode * const CallExitBeginN)419 void NoStateChangeFuncVisitor::findModifyingFrames(
420     const ExplodedNode *const CallExitBeginN) {
421 
422   assert(CallExitBeginN->getLocationAs<CallExitBegin>());
423 
424   const StackFrameContext *const OriginalSCtx =
425       CallExitBeginN->getLocationContext()->getStackFrame();
426 
427   const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
428   const StackFrameContext *CurrentSCtx = OriginalSCtx;
429 
430   for (const ExplodedNode *CurrN = CallExitBeginN; CurrN;
431        CurrN = CurrN->getFirstPred()) {
432     // Found a new inlined call.
433     if (CurrN->getLocationAs<CallExitBegin>()) {
434       CurrCallExitBeginN = CurrN;
435       CurrentSCtx = CurrN->getStackFrame();
436       FramesModifyingCalculated.insert(CurrentSCtx);
437       // We won't see a change in between two identical exploded nodes: skip.
438       continue;
439     }
440 
441     if (auto CE = CurrN->getLocationAs<CallEnter>()) {
442       if (const ExplodedNode *CallExitEndN = getMatchingCallExitEnd(CurrN))
443         if (wasModifiedInFunction(CurrN, CallExitEndN))
444           markFrameAsModifying(CurrentSCtx);
445 
446       // We exited this inlined call, lets actualize the stack frame.
447       CurrentSCtx = CurrN->getStackFrame();
448 
449       // Stop calculating at the current function, but always regard it as
450       // modifying, so we can avoid notes like this:
451       //   void f(Foo &F) {
452       //     F.field = 0; // note: 0 assigned to 'F.field'
453       //                  // note: returning without writing to 'F.field'
454       //   }
455       if (CE->getCalleeContext() == OriginalSCtx) {
456         markFrameAsModifying(CurrentSCtx);
457         break;
458       }
459     }
460 
461     if (wasModifiedBeforeCallExit(CurrN, CurrCallExitBeginN))
462       markFrameAsModifying(CurrentSCtx);
463   }
464 }
465 
VisitNode(const ExplodedNode * N,BugReporterContext & BR,PathSensitiveBugReport & R)466 PathDiagnosticPieceRef NoStateChangeFuncVisitor::VisitNode(
467     const ExplodedNode *N, BugReporterContext &BR, PathSensitiveBugReport &R) {
468 
469   const LocationContext *Ctx = N->getLocationContext();
470   const StackFrameContext *SCtx = Ctx->getStackFrame();
471   ProgramStateRef State = N->getState();
472   auto CallExitLoc = N->getLocationAs<CallExitBegin>();
473 
474   // No diagnostic if region was modified inside the frame.
475   if (!CallExitLoc || isModifiedInFrame(N))
476     return nullptr;
477 
478   CallEventRef<> Call =
479       BR.getStateManager().getCallEventManager().getCaller(SCtx, State);
480 
481   // Optimistically suppress uninitialized value bugs that result
482   // from system headers having a chance to initialize the value
483   // but failing to do so. It's too unlikely a system header's fault.
484   // It's much more likely a situation in which the function has a failure
485   // mode that the user decided not to check. If we want to hunt such
486   // omitted checks, we should provide an explicit function-specific note
487   // describing the precondition under which the function isn't supposed to
488   // initialize its out-parameter, and additionally check that such
489   // precondition can actually be fulfilled on the current path.
490   if (Call->isInSystemHeader()) {
491     // We make an exception for system header functions that have no branches.
492     // Such functions unconditionally fail to initialize the variable.
493     // If they call other functions that have more paths within them,
494     // this suppression would still apply when we visit these inner functions.
495     // One common example of a standard function that doesn't ever initialize
496     // its out parameter is operator placement new; it's up to the follow-up
497     // constructor (if any) to initialize the memory.
498     if (!N->getStackFrame()->getCFG()->isLinear()) {
499       static int i = 0;
500       R.markInvalid(&i, nullptr);
501     }
502     return nullptr;
503   }
504 
505   if (const auto *MC = dyn_cast<ObjCMethodCall>(Call)) {
506     // If we failed to construct a piece for self, we still want to check
507     // whether the entity of interest is in a parameter.
508     if (PathDiagnosticPieceRef Piece = maybeEmitNoteForObjCSelf(R, *MC, N))
509       return Piece;
510   }
511 
512   if (const auto *CCall = dyn_cast<CXXConstructorCall>(Call)) {
513     // Do not generate diagnostics for not modified parameters in
514     // constructors.
515     return maybeEmitNoteForCXXThis(R, *CCall, N);
516   }
517 
518   return maybeEmitNoteForParameters(R, *Call, N);
519 }
520 
521 /// \return Whether the method declaration \p Parent
522 /// syntactically has a binary operation writing into the ivar \p Ivar.
potentiallyWritesIntoIvar(const Decl * Parent,const ObjCIvarDecl * Ivar)523 static bool potentiallyWritesIntoIvar(const Decl *Parent,
524                                       const ObjCIvarDecl *Ivar) {
525   using namespace ast_matchers;
526   const char *IvarBind = "Ivar";
527   if (!Parent || !Parent->hasBody())
528     return false;
529   StatementMatcher WriteIntoIvarM = binaryOperator(
530       hasOperatorName("="),
531       hasLHS(ignoringParenImpCasts(
532           objcIvarRefExpr(hasDeclaration(equalsNode(Ivar))).bind(IvarBind))));
533   StatementMatcher ParentM = stmt(hasDescendant(WriteIntoIvarM));
534   auto Matches = match(ParentM, *Parent->getBody(), Parent->getASTContext());
535   for (BoundNodes &Match : Matches) {
536     auto IvarRef = Match.getNodeAs<ObjCIvarRefExpr>(IvarBind);
537     if (IvarRef->isFreeIvar())
538       return true;
539 
540     const Expr *Base = IvarRef->getBase();
541     if (const auto *ICE = dyn_cast<ImplicitCastExpr>(Base))
542       Base = ICE->getSubExpr();
543 
544     if (const auto *DRE = dyn_cast<DeclRefExpr>(Base))
545       if (const auto *ID = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
546         if (ID->getParameterKind() == ImplicitParamKind::ObjCSelf)
547           return true;
548 
549     return false;
550   }
551   return false;
552 }
553 
554 /// Attempts to find the region of interest in a given CXX decl,
555 /// by either following the base classes or fields.
556 /// Dereferences fields up to a given recursion limit.
557 /// Note that \p Vec is passed by value, leading to quadratic copying cost,
558 /// but it's OK in practice since its length is limited to DEREFERENCE_LIMIT.
559 /// \return A chain fields leading to the region of interest or std::nullopt.
560 const std::optional<NoStoreFuncVisitor::RegionVector>
findRegionOfInterestInRecord(const RecordDecl * RD,ProgramStateRef State,const MemRegion * R,const NoStoreFuncVisitor::RegionVector & Vec,int depth)561 NoStoreFuncVisitor::findRegionOfInterestInRecord(
562     const RecordDecl *RD, ProgramStateRef State, const MemRegion *R,
563     const NoStoreFuncVisitor::RegionVector &Vec /* = {} */,
564     int depth /* = 0 */) {
565 
566   if (depth == DEREFERENCE_LIMIT) // Limit the recursion depth.
567     return std::nullopt;
568 
569   if (const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
570     if (!RDX->hasDefinition())
571       return std::nullopt;
572 
573   // Recursively examine the base classes.
574   // Note that following base classes does not increase the recursion depth.
575   if (const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
576     for (const auto &II : RDX->bases())
577       if (const RecordDecl *RRD = II.getType()->getAsRecordDecl())
578         if (std::optional<RegionVector> Out =
579                 findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
580           return Out;
581 
582   for (const FieldDecl *I : RD->fields()) {
583     QualType FT = I->getType();
584     const FieldRegion *FR = MmrMgr.getFieldRegion(I, cast<SubRegion>(R));
585     const SVal V = State->getSVal(FR);
586     const MemRegion *VR = V.getAsRegion();
587 
588     RegionVector VecF = Vec;
589     VecF.push_back(FR);
590 
591     if (RegionOfInterest == VR)
592       return VecF;
593 
594     if (const RecordDecl *RRD = FT->getAsRecordDecl())
595       if (auto Out =
596               findRegionOfInterestInRecord(RRD, State, FR, VecF, depth + 1))
597         return Out;
598 
599     QualType PT = FT->getPointeeType();
600     if (PT.isNull() || PT->isVoidType() || !VR)
601       continue;
602 
603     if (const RecordDecl *RRD = PT->getAsRecordDecl())
604       if (std::optional<RegionVector> Out =
605               findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
606         return Out;
607   }
608 
609   return std::nullopt;
610 }
611 
612 PathDiagnosticPieceRef
maybeEmitNoteForObjCSelf(PathSensitiveBugReport & R,const ObjCMethodCall & Call,const ExplodedNode * N)613 NoStoreFuncVisitor::maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
614                                              const ObjCMethodCall &Call,
615                                              const ExplodedNode *N) {
616   if (const auto *IvarR = dyn_cast<ObjCIvarRegion>(RegionOfInterest)) {
617     const MemRegion *SelfRegion = Call.getReceiverSVal().getAsRegion();
618     if (RegionOfInterest->isSubRegionOf(SelfRegion) &&
619         potentiallyWritesIntoIvar(Call.getRuntimeDefinition().getDecl(),
620                                   IvarR->getDecl()))
621       return maybeEmitNote(R, Call, N, {}, SelfRegion, "self",
622                            /*FirstIsReferenceType=*/false, 1);
623   }
624   return nullptr;
625 }
626 
627 PathDiagnosticPieceRef
maybeEmitNoteForCXXThis(PathSensitiveBugReport & R,const CXXConstructorCall & Call,const ExplodedNode * N)628 NoStoreFuncVisitor::maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
629                                             const CXXConstructorCall &Call,
630                                             const ExplodedNode *N) {
631   const MemRegion *ThisR = Call.getCXXThisVal().getAsRegion();
632   if (RegionOfInterest->isSubRegionOf(ThisR) && !Call.getDecl()->isImplicit())
633     return maybeEmitNote(R, Call, N, {}, ThisR, "this",
634                          /*FirstIsReferenceType=*/false, 1);
635 
636   // Do not generate diagnostics for not modified parameters in
637   // constructors.
638   return nullptr;
639 }
640 
641 /// \return whether \p Ty points to a const type, or is a const reference.
isPointerToConst(QualType Ty)642 static bool isPointerToConst(QualType Ty) {
643   return !Ty->getPointeeType().isNull() &&
644          Ty->getPointeeType().getCanonicalType().isConstQualified();
645 }
646 
maybeEmitNoteForParameters(PathSensitiveBugReport & R,const CallEvent & Call,const ExplodedNode * N)647 PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNoteForParameters(
648     PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N) {
649   ArrayRef<ParmVarDecl *> Parameters = Call.parameters();
650   for (unsigned I = 0; I < Call.getNumArgs() && I < Parameters.size(); ++I) {
651     const ParmVarDecl *PVD = Parameters[I];
652     SVal V = Call.getArgSVal(I);
653     bool ParamIsReferenceType = PVD->getType()->isReferenceType();
654     std::string ParamName = PVD->getNameAsString();
655 
656     unsigned IndirectionLevel = 1;
657     QualType T = PVD->getType();
658     while (const MemRegion *MR = V.getAsRegion()) {
659       if (RegionOfInterest->isSubRegionOf(MR) && !isPointerToConst(T))
660         return maybeEmitNote(R, Call, N, {}, MR, ParamName,
661                              ParamIsReferenceType, IndirectionLevel);
662 
663       QualType PT = T->getPointeeType();
664       if (PT.isNull() || PT->isVoidType())
665         break;
666 
667       ProgramStateRef State = N->getState();
668 
669       if (const RecordDecl *RD = PT->getAsRecordDecl())
670         if (std::optional<RegionVector> P =
671                 findRegionOfInterestInRecord(RD, State, MR))
672           return maybeEmitNote(R, Call, N, *P, RegionOfInterest, ParamName,
673                                ParamIsReferenceType, IndirectionLevel);
674 
675       V = State->getSVal(MR, PT);
676       T = PT;
677       IndirectionLevel++;
678     }
679   }
680 
681   return nullptr;
682 }
683 
wasModifiedBeforeCallExit(const ExplodedNode * CurrN,const ExplodedNode * CallExitBeginN)684 bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
685     const ExplodedNode *CurrN, const ExplodedNode *CallExitBeginN) {
686   return ::wasRegionOfInterestModifiedAt(
687       RegionOfInterest, CurrN,
688       CallExitBeginN->getState()->getSVal(RegionOfInterest));
689 }
690 
691 static llvm::StringLiteral WillBeUsedForACondition =
692     ", which participates in a condition later";
693 
maybeEmitNote(PathSensitiveBugReport & R,const CallEvent & Call,const ExplodedNode * N,const RegionVector & FieldChain,const MemRegion * MatchedRegion,StringRef FirstElement,bool FirstIsReferenceType,unsigned IndirectionLevel)694 PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNote(
695     PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N,
696     const RegionVector &FieldChain, const MemRegion *MatchedRegion,
697     StringRef FirstElement, bool FirstIsReferenceType,
698     unsigned IndirectionLevel) {
699 
700   PathDiagnosticLocation L =
701       PathDiagnosticLocation::create(N->getLocation(), SM);
702 
703   // For now this shouldn't trigger, but once it does (as we add more
704   // functions to the body farm), we'll need to decide if these reports
705   // are worth suppressing as well.
706   if (!L.hasValidLocation())
707     return nullptr;
708 
709   SmallString<256> sbuf;
710   llvm::raw_svector_ostream os(sbuf);
711   os << "Returning without writing to '";
712 
713   // Do not generate the note if failed to pretty-print.
714   if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement,
715                              FirstIsReferenceType, IndirectionLevel, os))
716     return nullptr;
717 
718   os << "'";
719   if (TKind == bugreporter::TrackingKind::Condition)
720     os << WillBeUsedForACondition;
721   return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
722 }
723 
prettyPrintRegionName(const RegionVector & FieldChain,const MemRegion * MatchedRegion,StringRef FirstElement,bool FirstIsReferenceType,unsigned IndirectionLevel,llvm::raw_svector_ostream & os)724 bool NoStoreFuncVisitor::prettyPrintRegionName(const RegionVector &FieldChain,
725                                                const MemRegion *MatchedRegion,
726                                                StringRef FirstElement,
727                                                bool FirstIsReferenceType,
728                                                unsigned IndirectionLevel,
729                                                llvm::raw_svector_ostream &os) {
730 
731   if (FirstIsReferenceType)
732     IndirectionLevel--;
733 
734   RegionVector RegionSequence;
735 
736   // Add the regions in the reverse order, then reverse the resulting array.
737   assert(RegionOfInterest->isSubRegionOf(MatchedRegion));
738   const MemRegion *R = RegionOfInterest;
739   while (R != MatchedRegion) {
740     RegionSequence.push_back(R);
741     R = cast<SubRegion>(R)->getSuperRegion();
742   }
743   std::reverse(RegionSequence.begin(), RegionSequence.end());
744   RegionSequence.append(FieldChain.begin(), FieldChain.end());
745 
746   StringRef Sep;
747   for (const MemRegion *R : RegionSequence) {
748 
749     // Just keep going up to the base region.
750     // Element regions may appear due to casts.
751     if (isa<CXXBaseObjectRegion, CXXTempObjectRegion>(R))
752       continue;
753 
754     if (Sep.empty())
755       Sep = prettyPrintFirstElement(FirstElement,
756                                     /*MoreItemsExpected=*/true,
757                                     IndirectionLevel, os);
758 
759     os << Sep;
760 
761     // Can only reasonably pretty-print DeclRegions.
762     if (!isa<DeclRegion>(R))
763       return false;
764 
765     const auto *DR = cast<DeclRegion>(R);
766     Sep = DR->getValueType()->isAnyPointerType() ? "->" : ".";
767     DR->getDecl()->getDeclName().print(os, PP);
768   }
769 
770   if (Sep.empty())
771     prettyPrintFirstElement(FirstElement,
772                             /*MoreItemsExpected=*/false, IndirectionLevel, os);
773   return true;
774 }
775 
prettyPrintFirstElement(StringRef FirstElement,bool MoreItemsExpected,int IndirectionLevel,llvm::raw_svector_ostream & os)776 StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
777     StringRef FirstElement, bool MoreItemsExpected, int IndirectionLevel,
778     llvm::raw_svector_ostream &os) {
779   StringRef Out = ".";
780 
781   if (IndirectionLevel > 0 && MoreItemsExpected) {
782     IndirectionLevel--;
783     Out = "->";
784   }
785 
786   if (IndirectionLevel > 0 && MoreItemsExpected)
787     os << "(";
788 
789   for (int i = 0; i < IndirectionLevel; i++)
790     os << "*";
791   os << FirstElement;
792 
793   if (IndirectionLevel > 0 && MoreItemsExpected)
794     os << ")";
795 
796   return Out;
797 }
798 
799 //===----------------------------------------------------------------------===//
800 // Implementation of MacroNullReturnSuppressionVisitor.
801 //===----------------------------------------------------------------------===//
802 
803 namespace {
804 
805 /// Suppress null-pointer-dereference bugs where dereferenced null was returned
806 /// the macro.
807 class MacroNullReturnSuppressionVisitor final : public BugReporterVisitor {
808   const SubRegion *RegionOfInterest;
809   const SVal ValueAtDereference;
810 
811   // Do not invalidate the reports where the value was modified
812   // after it got assigned to from the macro.
813   bool WasModified = false;
814 
815 public:
MacroNullReturnSuppressionVisitor(const SubRegion * R,const SVal V)816   MacroNullReturnSuppressionVisitor(const SubRegion *R, const SVal V)
817       : RegionOfInterest(R), ValueAtDereference(V) {}
818 
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)819   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
820                                    BugReporterContext &BRC,
821                                    PathSensitiveBugReport &BR) override {
822     if (WasModified)
823       return nullptr;
824 
825     auto BugPoint = BR.getErrorNode()->getLocation().getAs<StmtPoint>();
826     if (!BugPoint)
827       return nullptr;
828 
829     const SourceManager &SMgr = BRC.getSourceManager();
830     if (auto Loc = matchAssignment(N)) {
831       if (isFunctionMacroExpansion(*Loc, SMgr)) {
832         std::string MacroName = std::string(getMacroName(*Loc, BRC));
833         SourceLocation BugLoc = BugPoint->getStmt()->getBeginLoc();
834         if (!BugLoc.isMacroID() || getMacroName(BugLoc, BRC) != MacroName)
835           BR.markInvalid(getTag(), MacroName.c_str());
836       }
837     }
838 
839     if (wasRegionOfInterestModifiedAt(RegionOfInterest, N, ValueAtDereference))
840       WasModified = true;
841 
842     return nullptr;
843   }
844 
addMacroVisitorIfNecessary(const ExplodedNode * N,const MemRegion * R,bool EnableNullFPSuppression,PathSensitiveBugReport & BR,const SVal V)845   static void addMacroVisitorIfNecessary(
846         const ExplodedNode *N, const MemRegion *R,
847         bool EnableNullFPSuppression, PathSensitiveBugReport &BR,
848         const SVal V) {
849     AnalyzerOptions &Options = N->getState()->getAnalysisManager().options;
850     if (EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths &&
851         isa<Loc>(V))
852       BR.addVisitor<MacroNullReturnSuppressionVisitor>(R->getAs<SubRegion>(),
853                                                        V);
854   }
855 
getTag() const856   void* getTag() const {
857     static int Tag = 0;
858     return static_cast<void *>(&Tag);
859   }
860 
Profile(llvm::FoldingSetNodeID & ID) const861   void Profile(llvm::FoldingSetNodeID &ID) const override {
862     ID.AddPointer(getTag());
863   }
864 
865 private:
866   /// \return Source location of right hand side of an assignment
867   /// into \c RegionOfInterest, empty optional if none found.
matchAssignment(const ExplodedNode * N)868   std::optional<SourceLocation> matchAssignment(const ExplodedNode *N) {
869     const Stmt *S = N->getStmtForDiagnostics();
870     ProgramStateRef State = N->getState();
871     auto *LCtx = N->getLocationContext();
872     if (!S)
873       return std::nullopt;
874 
875     if (const auto *DS = dyn_cast<DeclStmt>(S)) {
876       if (const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
877         if (const Expr *RHS = VD->getInit())
878           if (RegionOfInterest->isSubRegionOf(
879                   State->getLValue(VD, LCtx).getAsRegion()))
880             return RHS->getBeginLoc();
881     } else if (const auto *BO = dyn_cast<BinaryOperator>(S)) {
882       const MemRegion *R = N->getSVal(BO->getLHS()).getAsRegion();
883       const Expr *RHS = BO->getRHS();
884       if (BO->isAssignmentOp() && RegionOfInterest->isSubRegionOf(R)) {
885         return RHS->getBeginLoc();
886       }
887     }
888     return std::nullopt;
889   }
890 };
891 
892 } // end of anonymous namespace
893 
894 namespace {
895 
896 /// Emits an extra note at the return statement of an interesting stack frame.
897 ///
898 /// The returned value is marked as an interesting value, and if it's null,
899 /// adds a visitor to track where it became null.
900 ///
901 /// This visitor is intended to be used when another visitor discovers that an
902 /// interesting value comes from an inlined function call.
903 class ReturnVisitor : public TrackingBugReporterVisitor {
904   const StackFrameContext *CalleeSFC;
905   enum {
906     Initial,
907     MaybeUnsuppress,
908     Satisfied
909   } Mode = Initial;
910 
911   bool EnableNullFPSuppression;
912   bool ShouldInvalidate = true;
913   AnalyzerOptions& Options;
914   bugreporter::TrackingKind TKind;
915 
916 public:
ReturnVisitor(TrackerRef ParentTracker,const StackFrameContext * Frame,bool Suppressed,AnalyzerOptions & Options,bugreporter::TrackingKind TKind)917   ReturnVisitor(TrackerRef ParentTracker, const StackFrameContext *Frame,
918                 bool Suppressed, AnalyzerOptions &Options,
919                 bugreporter::TrackingKind TKind)
920       : TrackingBugReporterVisitor(ParentTracker), CalleeSFC(Frame),
921         EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
922 
getTag()923   static void *getTag() {
924     static int Tag = 0;
925     return static_cast<void *>(&Tag);
926   }
927 
Profile(llvm::FoldingSetNodeID & ID) const928   void Profile(llvm::FoldingSetNodeID &ID) const override {
929     ID.AddPointer(ReturnVisitor::getTag());
930     ID.AddPointer(CalleeSFC);
931     ID.AddBoolean(EnableNullFPSuppression);
932   }
933 
visitNodeInitial(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)934   PathDiagnosticPieceRef visitNodeInitial(const ExplodedNode *N,
935                                           BugReporterContext &BRC,
936                                           PathSensitiveBugReport &BR) {
937     // Only print a message at the interesting return statement.
938     if (N->getLocationContext() != CalleeSFC)
939       return nullptr;
940 
941     std::optional<StmtPoint> SP = N->getLocationAs<StmtPoint>();
942     if (!SP)
943       return nullptr;
944 
945     const auto *Ret = dyn_cast<ReturnStmt>(SP->getStmt());
946     if (!Ret)
947       return nullptr;
948 
949     // Okay, we're at the right return statement, but do we have the return
950     // value available?
951     ProgramStateRef State = N->getState();
952     SVal V = State->getSVal(Ret, CalleeSFC);
953     if (V.isUnknownOrUndef())
954       return nullptr;
955 
956     // Don't print any more notes after this one.
957     Mode = Satisfied;
958 
959     const Expr *RetE = Ret->getRetValue();
960     assert(RetE && "Tracking a return value for a void function");
961 
962     // Handle cases where a reference is returned and then immediately used.
963     std::optional<Loc> LValue;
964     if (RetE->isGLValue()) {
965       if ((LValue = V.getAs<Loc>())) {
966         SVal RValue = State->getRawSVal(*LValue, RetE->getType());
967         if (isa<DefinedSVal>(RValue))
968           V = RValue;
969       }
970     }
971 
972     // Ignore aggregate rvalues.
973     if (isa<nonloc::LazyCompoundVal, nonloc::CompoundVal>(V))
974       return nullptr;
975 
976     RetE = RetE->IgnoreParenCasts();
977 
978     // Let's track the return value.
979     getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
980 
981     // Build an appropriate message based on the return value.
982     SmallString<64> Msg;
983     llvm::raw_svector_ostream Out(Msg);
984 
985     bool WouldEventBeMeaningless = false;
986 
987     if (State->isNull(V).isConstrainedTrue()) {
988       if (isa<Loc>(V)) {
989 
990         // If we have counter-suppression enabled, make sure we keep visiting
991         // future nodes. We want to emit a path note as well, in case
992         // the report is resurrected as valid later on.
993         if (EnableNullFPSuppression &&
994             Options.ShouldAvoidSuppressingNullArgumentPaths)
995           Mode = MaybeUnsuppress;
996 
997         if (RetE->getType()->isObjCObjectPointerType()) {
998           Out << "Returning nil";
999         } else {
1000           Out << "Returning null pointer";
1001         }
1002       } else {
1003         Out << "Returning zero";
1004       }
1005 
1006     } else {
1007       if (auto CI = V.getAs<nonloc::ConcreteInt>()) {
1008         Out << "Returning the value " << CI->getValue();
1009       } else {
1010         // There is nothing interesting about returning a value, when it is
1011         // plain value without any constraints, and the function is guaranteed
1012         // to return that every time. We could use CFG::isLinear() here, but
1013         // constexpr branches are obvious to the compiler, not necesserily to
1014         // the programmer.
1015         if (N->getCFG().size() == 3)
1016           WouldEventBeMeaningless = true;
1017 
1018         Out << (isa<Loc>(V) ? "Returning pointer" : "Returning value");
1019       }
1020     }
1021 
1022     if (LValue) {
1023       if (const MemRegion *MR = LValue->getAsRegion()) {
1024         if (MR->canPrintPretty()) {
1025           Out << " (reference to ";
1026           MR->printPretty(Out);
1027           Out << ")";
1028         }
1029       }
1030     } else {
1031       // FIXME: We should have a more generalized location printing mechanism.
1032       if (const auto *DR = dyn_cast<DeclRefExpr>(RetE))
1033         if (const auto *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
1034           Out << " (loaded from '" << *DD << "')";
1035     }
1036 
1037     PathDiagnosticLocation L(Ret, BRC.getSourceManager(), CalleeSFC);
1038     if (!L.isValid() || !L.asLocation().isValid())
1039       return nullptr;
1040 
1041     if (TKind == bugreporter::TrackingKind::Condition)
1042       Out << WillBeUsedForACondition;
1043 
1044     auto EventPiece = std::make_shared<PathDiagnosticEventPiece>(L, Out.str());
1045 
1046     // If we determined that the note is meaningless, make it prunable, and
1047     // don't mark the stackframe interesting.
1048     if (WouldEventBeMeaningless)
1049       EventPiece->setPrunable(true);
1050     else
1051       BR.markInteresting(CalleeSFC);
1052 
1053     return EventPiece;
1054   }
1055 
visitNodeMaybeUnsuppress(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)1056   PathDiagnosticPieceRef visitNodeMaybeUnsuppress(const ExplodedNode *N,
1057                                                   BugReporterContext &BRC,
1058                                                   PathSensitiveBugReport &BR) {
1059     assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
1060 
1061     // Are we at the entry node for this call?
1062     std::optional<CallEnter> CE = N->getLocationAs<CallEnter>();
1063     if (!CE)
1064       return nullptr;
1065 
1066     if (CE->getCalleeContext() != CalleeSFC)
1067       return nullptr;
1068 
1069     Mode = Satisfied;
1070 
1071     // Don't automatically suppress a report if one of the arguments is
1072     // known to be a null pointer. Instead, start tracking /that/ null
1073     // value back to its origin.
1074     ProgramStateManager &StateMgr = BRC.getStateManager();
1075     CallEventManager &CallMgr = StateMgr.getCallEventManager();
1076 
1077     ProgramStateRef State = N->getState();
1078     CallEventRef<> Call = CallMgr.getCaller(CalleeSFC, State);
1079     for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
1080       std::optional<Loc> ArgV = Call->getArgSVal(I).getAs<Loc>();
1081       if (!ArgV)
1082         continue;
1083 
1084       const Expr *ArgE = Call->getArgExpr(I);
1085       if (!ArgE)
1086         continue;
1087 
1088       // Is it possible for this argument to be non-null?
1089       if (!State->isNull(*ArgV).isConstrainedTrue())
1090         continue;
1091 
1092       if (getParentTracker()
1093               .track(ArgE, N, {TKind, EnableNullFPSuppression})
1094               .FoundSomethingToTrack)
1095         ShouldInvalidate = false;
1096 
1097       // If we /can't/ track the null pointer, we should err on the side of
1098       // false negatives, and continue towards marking this report invalid.
1099       // (We will still look at the other arguments, though.)
1100     }
1101 
1102     return nullptr;
1103   }
1104 
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)1105   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
1106                                    BugReporterContext &BRC,
1107                                    PathSensitiveBugReport &BR) override {
1108     switch (Mode) {
1109     case Initial:
1110       return visitNodeInitial(N, BRC, BR);
1111     case MaybeUnsuppress:
1112       return visitNodeMaybeUnsuppress(N, BRC, BR);
1113     case Satisfied:
1114       return nullptr;
1115     }
1116 
1117     llvm_unreachable("Invalid visit mode!");
1118   }
1119 
finalizeVisitor(BugReporterContext &,const ExplodedNode *,PathSensitiveBugReport & BR)1120   void finalizeVisitor(BugReporterContext &, const ExplodedNode *,
1121                        PathSensitiveBugReport &BR) override {
1122     if (EnableNullFPSuppression && ShouldInvalidate)
1123       BR.markInvalid(ReturnVisitor::getTag(), CalleeSFC);
1124   }
1125 };
1126 
1127 //===----------------------------------------------------------------------===//
1128 //                               StoreSiteFinder
1129 //===----------------------------------------------------------------------===//
1130 
1131 /// Finds last store into the given region,
1132 /// which is different from a given symbolic value.
1133 class StoreSiteFinder final : public TrackingBugReporterVisitor {
1134   const MemRegion *R;
1135   SVal V;
1136   bool Satisfied = false;
1137 
1138   TrackingOptions Options;
1139   const StackFrameContext *OriginSFC;
1140 
1141 public:
1142   /// \param V We're searching for the store where \c R received this value.
1143   /// \param R The region we're tracking.
1144   /// \param Options Tracking behavior options.
1145   /// \param OriginSFC Only adds notes when the last store happened in a
1146   ///        different stackframe to this one. Disregarded if the tracking kind
1147   ///        is thorough.
1148   ///        This is useful, because for non-tracked regions, notes about
1149   ///        changes to its value in a nested stackframe could be pruned, and
1150   ///        this visitor can prevent that without polluting the bugpath too
1151   ///        much.
StoreSiteFinder(bugreporter::TrackerRef ParentTracker,SVal V,const MemRegion * R,TrackingOptions Options,const StackFrameContext * OriginSFC=nullptr)1152   StoreSiteFinder(bugreporter::TrackerRef ParentTracker, SVal V,
1153                   const MemRegion *R, TrackingOptions Options,
1154                   const StackFrameContext *OriginSFC = nullptr)
1155       : TrackingBugReporterVisitor(ParentTracker), R(R), V(V), Options(Options),
1156         OriginSFC(OriginSFC) {
1157     assert(R);
1158   }
1159 
1160   void Profile(llvm::FoldingSetNodeID &ID) const override;
1161 
1162   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
1163                                    BugReporterContext &BRC,
1164                                    PathSensitiveBugReport &BR) override;
1165 };
1166 } // namespace
1167 
Profile(llvm::FoldingSetNodeID & ID) const1168 void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID) const {
1169   static int tag = 0;
1170   ID.AddPointer(&tag);
1171   ID.AddPointer(R);
1172   ID.Add(V);
1173   ID.AddInteger(static_cast<int>(Options.Kind));
1174   ID.AddBoolean(Options.EnableNullFPSuppression);
1175 }
1176 
1177 /// Returns true if \p N represents the DeclStmt declaring and initializing
1178 /// \p VR.
isInitializationOfVar(const ExplodedNode * N,const VarRegion * VR)1179 static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
1180   std::optional<PostStmt> P = N->getLocationAs<PostStmt>();
1181   if (!P)
1182     return false;
1183 
1184   const DeclStmt *DS = P->getStmtAs<DeclStmt>();
1185   if (!DS)
1186     return false;
1187 
1188   if (DS->getSingleDecl() != VR->getDecl())
1189     return false;
1190 
1191   const auto *FrameSpace =
1192       VR->getMemorySpaceAs<StackSpaceRegion>(N->getState());
1193 
1194   if (!FrameSpace) {
1195     // If we ever directly evaluate global DeclStmts, this assertion will be
1196     // invalid, but this still seems preferable to silently accepting an
1197     // initialization that may be for a path-sensitive variable.
1198     [[maybe_unused]] bool IsLocalStaticOrLocalExtern =
1199         VR->getDecl()->isStaticLocal() || VR->getDecl()->isLocalExternDecl();
1200     assert(IsLocalStaticOrLocalExtern &&
1201            "Declared a variable on the stack without Stack memspace?");
1202     return true;
1203   }
1204 
1205   assert(VR->getDecl()->hasLocalStorage());
1206   const LocationContext *LCtx = N->getLocationContext();
1207   return FrameSpace->getStackFrame() == LCtx->getStackFrame();
1208 }
1209 
isObjCPointer(const MemRegion * R)1210 static bool isObjCPointer(const MemRegion *R) {
1211   if (R->isBoundable())
1212     if (const auto *TR = dyn_cast<TypedValueRegion>(R))
1213       return TR->getValueType()->isObjCObjectPointerType();
1214 
1215   return false;
1216 }
1217 
isObjCPointer(const ValueDecl * D)1218 static bool isObjCPointer(const ValueDecl *D) {
1219   return D->getType()->isObjCObjectPointerType();
1220 }
1221 
1222 namespace {
1223 using DestTypeValue = std::pair<const StoreInfo &, loc::ConcreteInt>;
1224 
operator <<(llvm::raw_ostream & OS,const DestTypeValue & Val)1225 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const DestTypeValue &Val) {
1226   if (auto *TyR = Val.first.Dest->getAs<TypedRegion>()) {
1227     QualType LocTy = TyR->getLocationType();
1228     if (!LocTy.isNull()) {
1229       if (auto *PtrTy = LocTy->getAs<PointerType>()) {
1230         std::string PStr = PtrTy->getPointeeType().getAsString();
1231         if (!PStr.empty())
1232           OS << "(" << PStr << ")";
1233       }
1234     }
1235   }
1236   SmallString<16> ValStr;
1237   Val.second.getValue()->toString(ValStr, 10, true);
1238   OS << ValStr;
1239   return OS;
1240 }
1241 } // namespace
1242 
1243 /// Show diagnostics for initializing or declaring a region \p R with a bad value.
showBRDiagnostics(llvm::raw_svector_ostream & OS,StoreInfo SI)1244 static void showBRDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI) {
1245   const bool HasPrefix = SI.Dest->canPrintPretty();
1246 
1247   if (HasPrefix) {
1248     SI.Dest->printPretty(OS);
1249     OS << " ";
1250   }
1251 
1252   const char *Action = nullptr;
1253 
1254   switch (SI.StoreKind) {
1255   case StoreInfo::Initialization:
1256     Action = HasPrefix ? "initialized to " : "Initializing to ";
1257     break;
1258   case StoreInfo::BlockCapture:
1259     Action = HasPrefix ? "captured by block as " : "Captured by block as ";
1260     break;
1261   default:
1262     llvm_unreachable("Unexpected store kind");
1263   }
1264 
1265   if (auto CVal = SI.Value.getAs<loc::ConcreteInt>()) {
1266     if (!*CVal->getValue())
1267       OS << Action << (isObjCPointer(SI.Dest) ? "nil" : "a null pointer value");
1268     else
1269       OS << Action << DestTypeValue(SI, *CVal);
1270 
1271   } else if (auto CVal = SI.Value.getAs<nonloc::ConcreteInt>()) {
1272     OS << Action << CVal->getValue();
1273 
1274   } else if (SI.Origin && SI.Origin->canPrintPretty()) {
1275     OS << Action << "the value of ";
1276     SI.Origin->printPretty(OS);
1277 
1278   } else if (SI.StoreKind == StoreInfo::Initialization) {
1279     // We don't need to check here, all these conditions were
1280     // checked by StoreSiteFinder, when it figured out that it is
1281     // initialization.
1282     const auto *DS =
1283         cast<DeclStmt>(SI.StoreSite->getLocationAs<PostStmt>()->getStmt());
1284 
1285     if (SI.Value.isUndef()) {
1286       if (isa<VarRegion>(SI.Dest)) {
1287         const auto *VD = cast<VarDecl>(DS->getSingleDecl());
1288 
1289         if (VD->getInit()) {
1290           OS << (HasPrefix ? "initialized" : "Initializing")
1291              << " to a garbage value";
1292         } else {
1293           OS << (HasPrefix ? "declared" : "Declaring")
1294              << " without an initial value";
1295         }
1296       }
1297     } else {
1298       OS << (HasPrefix ? "initialized" : "Initialized") << " here";
1299     }
1300   }
1301 }
1302 
1303 /// Display diagnostics for passing bad region as a parameter.
showBRParamDiagnostics(llvm::raw_svector_ostream & OS,StoreInfo SI)1304 static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS,
1305                                    StoreInfo SI) {
1306   const auto *VR = cast<VarRegion>(SI.Dest);
1307   const auto *D = VR->getDecl();
1308 
1309   OS << "Passing ";
1310 
1311   if (auto CI = SI.Value.getAs<loc::ConcreteInt>()) {
1312     if (!*CI->getValue())
1313       OS << (isObjCPointer(D) ? "nil object reference" : "null pointer value");
1314     else
1315       OS << (isObjCPointer(D) ? "object reference of value " : "pointer value ")
1316          << DestTypeValue(SI, *CI);
1317 
1318   } else if (SI.Value.isUndef()) {
1319     OS << "uninitialized value";
1320 
1321   } else if (auto CI = SI.Value.getAs<nonloc::ConcreteInt>()) {
1322     OS << "the value " << CI->getValue();
1323 
1324   } else if (SI.Origin && SI.Origin->canPrintPretty()) {
1325     SI.Origin->printPretty(OS);
1326 
1327   } else {
1328     OS << "value";
1329   }
1330 
1331   if (const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1332     // Printed parameter indexes are 1-based, not 0-based.
1333     unsigned Idx = Param->getFunctionScopeIndex() + 1;
1334     OS << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter";
1335     if (VR->canPrintPretty()) {
1336       OS << " ";
1337       VR->printPretty(OS);
1338     }
1339   } else if (const auto *ImplParam = dyn_cast<ImplicitParamDecl>(D)) {
1340     if (ImplParam->getParameterKind() == ImplicitParamKind::ObjCSelf) {
1341       OS << " via implicit parameter 'self'";
1342     }
1343   }
1344 }
1345 
1346 /// Show default diagnostics for storing bad region.
showBRDefaultDiagnostics(llvm::raw_svector_ostream & OS,StoreInfo SI)1347 static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &OS,
1348                                      StoreInfo SI) {
1349   const bool HasSuffix = SI.Dest->canPrintPretty();
1350 
1351   if (auto CV = SI.Value.getAs<loc::ConcreteInt>()) {
1352     APSIntPtr V = CV->getValue();
1353     if (!*V)
1354       OS << (isObjCPointer(SI.Dest)
1355                  ? "nil object reference stored"
1356                  : (HasSuffix ? "Null pointer value stored"
1357                               : "Storing null pointer value"));
1358     else {
1359       if (isObjCPointer(SI.Dest)) {
1360         OS << "object reference of value " << DestTypeValue(SI, *CV)
1361            << " stored";
1362       } else {
1363         if (HasSuffix)
1364           OS << "Pointer value of " << DestTypeValue(SI, *CV) << " stored";
1365         else
1366           OS << "Storing pointer value of " << DestTypeValue(SI, *CV);
1367       }
1368     }
1369   } else if (SI.Value.isUndef()) {
1370     OS << (HasSuffix ? "Uninitialized value stored"
1371                      : "Storing uninitialized value");
1372 
1373   } else if (auto CV = SI.Value.getAs<nonloc::ConcreteInt>()) {
1374     if (HasSuffix)
1375       OS << "The value " << CV->getValue() << " is assigned";
1376     else
1377       OS << "Assigning " << CV->getValue();
1378 
1379   } else if (SI.Origin && SI.Origin->canPrintPretty()) {
1380     if (HasSuffix) {
1381       OS << "The value of ";
1382       SI.Origin->printPretty(OS);
1383       OS << " is assigned";
1384     } else {
1385       OS << "Assigning the value of ";
1386       SI.Origin->printPretty(OS);
1387     }
1388 
1389   } else {
1390     OS << (HasSuffix ? "Value assigned" : "Assigning value");
1391   }
1392 
1393   if (HasSuffix) {
1394     OS << " to ";
1395     SI.Dest->printPretty(OS);
1396   }
1397 }
1398 
isTrivialCopyOrMoveCtor(const CXXConstructExpr * CE)1399 static bool isTrivialCopyOrMoveCtor(const CXXConstructExpr *CE) {
1400   if (!CE)
1401     return false;
1402 
1403   const auto *CtorDecl = CE->getConstructor();
1404 
1405   return CtorDecl->isCopyOrMoveConstructor() && CtorDecl->isTrivial();
1406 }
1407 
tryExtractInitializerFromList(const InitListExpr * ILE,const MemRegion * R)1408 static const Expr *tryExtractInitializerFromList(const InitListExpr *ILE,
1409                                                  const MemRegion *R) {
1410 
1411   const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
1412 
1413   if (!TVR)
1414     return nullptr;
1415 
1416   const auto ITy = ILE->getType().getCanonicalType();
1417 
1418   // Push each sub-region onto the stack.
1419   std::stack<const TypedValueRegion *> TVRStack;
1420   while (isa<FieldRegion>(TVR) || isa<ElementRegion>(TVR)) {
1421     // We found a region that matches the type of the init list,
1422     // so we assume this is the outer-most region. This can happen
1423     // if the initializer list is inside a class. If our assumption
1424     // is wrong, we return a nullptr in the end.
1425     if (ITy == TVR->getValueType().getCanonicalType())
1426       break;
1427 
1428     TVRStack.push(TVR);
1429     TVR = cast<TypedValueRegion>(TVR->getSuperRegion());
1430   }
1431 
1432   // If the type of the outer most region doesn't match the type
1433   // of the ILE, we can't match the ILE and the region.
1434   if (ITy != TVR->getValueType().getCanonicalType())
1435     return nullptr;
1436 
1437   const Expr *Init = ILE;
1438   while (!TVRStack.empty()) {
1439     TVR = TVRStack.top();
1440     TVRStack.pop();
1441 
1442     // We hit something that's not an init list before
1443     // running out of regions, so we most likely failed.
1444     if (!isa<InitListExpr>(Init))
1445       return nullptr;
1446 
1447     ILE = cast<InitListExpr>(Init);
1448     auto NumInits = ILE->getNumInits();
1449 
1450     if (const auto *FR = dyn_cast<FieldRegion>(TVR)) {
1451       const auto *FD = FR->getDecl();
1452 
1453       if (FD->getFieldIndex() >= NumInits)
1454         return nullptr;
1455 
1456       Init = ILE->getInit(FD->getFieldIndex());
1457     } else if (const auto *ER = dyn_cast<ElementRegion>(TVR)) {
1458       const auto Ind = ER->getIndex();
1459 
1460       // If index is symbolic, we can't figure out which expression
1461       // belongs to the region.
1462       if (!Ind.isConstant())
1463         return nullptr;
1464 
1465       const auto IndVal = Ind.getAsInteger()->getLimitedValue();
1466       if (IndVal >= NumInits)
1467         return nullptr;
1468 
1469       Init = ILE->getInit(IndVal);
1470     }
1471   }
1472 
1473   return Init;
1474 }
1475 
VisitNode(const ExplodedNode * Succ,BugReporterContext & BRC,PathSensitiveBugReport & BR)1476 PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
1477                                                   BugReporterContext &BRC,
1478                                                   PathSensitiveBugReport &BR) {
1479   if (Satisfied)
1480     return nullptr;
1481 
1482   const ExplodedNode *StoreSite = nullptr;
1483   const ExplodedNode *Pred = Succ->getFirstPred();
1484   const Expr *InitE = nullptr;
1485   bool IsParam = false;
1486 
1487   // First see if we reached the declaration of the region.
1488   if (const auto *VR = dyn_cast<VarRegion>(R)) {
1489     if (isInitializationOfVar(Pred, VR)) {
1490       StoreSite = Pred;
1491       InitE = VR->getDecl()->getInit();
1492     }
1493   }
1494 
1495   // If this is a post initializer expression, initializing the region, we
1496   // should track the initializer expression.
1497   if (std::optional<PostInitializer> PIP =
1498           Pred->getLocationAs<PostInitializer>()) {
1499     const MemRegion *FieldReg = (const MemRegion *)PIP->getLocationValue();
1500     if (FieldReg == R) {
1501       StoreSite = Pred;
1502       InitE = PIP->getInitializer()->getInit();
1503     }
1504   }
1505 
1506   // Otherwise, see if this is the store site:
1507   // (1) Succ has this binding and Pred does not, i.e. this is
1508   //     where the binding first occurred.
1509   // (2) Succ has this binding and is a PostStore node for this region, i.e.
1510   //     the same binding was re-assigned here.
1511   if (!StoreSite) {
1512     if (Succ->getState()->getSVal(R) != V)
1513       return nullptr;
1514 
1515     if (hasVisibleUpdate(Pred, Pred->getState()->getSVal(R), Succ, V)) {
1516       std::optional<PostStore> PS = Succ->getLocationAs<PostStore>();
1517       if (!PS || PS->getLocationValue() != R)
1518         return nullptr;
1519     }
1520 
1521     StoreSite = Succ;
1522 
1523     if (std::optional<PostStmt> P = Succ->getLocationAs<PostStmt>()) {
1524       // If this is an assignment expression, we can track the value
1525       // being assigned.
1526       if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
1527         if (BO->isAssignmentOp())
1528           InitE = BO->getRHS();
1529       }
1530       // If we have a declaration like 'S s{1,2}' that needs special
1531       // handling, we handle it here.
1532       else if (const auto *DS = P->getStmtAs<DeclStmt>()) {
1533         const auto *Decl = DS->getSingleDecl();
1534         if (isa<VarDecl>(Decl)) {
1535           const auto *VD = cast<VarDecl>(Decl);
1536 
1537           // FIXME: Here we only track the inner most region, so we lose
1538           // information, but it's still better than a crash or no information
1539           // at all.
1540           //
1541           // E.g.: The region we have is 's.s2.s3.s4.y' and we only track 'y',
1542           // and throw away the rest.
1543           if (const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
1544             InitE = tryExtractInitializerFromList(ILE, R);
1545         }
1546       } else if (const auto *CE = P->getStmtAs<CXXConstructExpr>()) {
1547 
1548         const auto State = Succ->getState();
1549 
1550         if (isTrivialCopyOrMoveCtor(CE) && isa<SubRegion>(R)) {
1551           // Migrate the field regions from the current object to
1552           // the parent object. If we track 'a.y.e' and encounter
1553           // 'S a = b' then we need to track 'b.y.e'.
1554 
1555           // Push the regions to a stack, from last to first, so
1556           // considering the example above the stack will look like
1557           // (bottom) 'e' -> 'y' (top).
1558 
1559           std::stack<const SubRegion *> SRStack;
1560           const SubRegion *SR = cast<SubRegion>(R);
1561           while (isa<FieldRegion>(SR) || isa<ElementRegion>(SR)) {
1562             SRStack.push(SR);
1563             SR = cast<SubRegion>(SR->getSuperRegion());
1564           }
1565 
1566           // Get the region for the object we copied/moved from.
1567           const auto *OriginEx = CE->getArg(0);
1568           const auto OriginVal =
1569               State->getSVal(OriginEx, Succ->getLocationContext());
1570 
1571           // Pop the stored field regions and apply them to the origin
1572           // object in the same order we had them on the copy.
1573           // OriginField will evolve like 'b' -> 'b.y' -> 'b.y.e'.
1574           SVal OriginField = OriginVal;
1575           while (!SRStack.empty()) {
1576             const auto *TopR = SRStack.top();
1577             SRStack.pop();
1578 
1579             if (const auto *FR = dyn_cast<FieldRegion>(TopR)) {
1580               OriginField = State->getLValue(FR->getDecl(), OriginField);
1581             } else if (const auto *ER = dyn_cast<ElementRegion>(TopR)) {
1582               OriginField = State->getLValue(ER->getElementType(),
1583                                              ER->getIndex(), OriginField);
1584             } else {
1585               // FIXME: handle other region type
1586             }
1587           }
1588 
1589           // Track 'b.y.e'.
1590           getParentTracker().track(V, OriginField.getAsRegion(), Options);
1591           InitE = OriginEx;
1592         }
1593       }
1594       // This branch can occur in cases like `Ctor() : field{ x, y } {}'.
1595       else if (const auto *ILE = P->getStmtAs<InitListExpr>()) {
1596         // FIXME: Here we only track the top level region, so we lose
1597         // information, but it's still better than a crash or no information
1598         // at all.
1599         //
1600         // E.g.: The region we have is 's.s2.s3.s4.y' and we only track 'y', and
1601         // throw away the rest.
1602         InitE = tryExtractInitializerFromList(ILE, R);
1603       }
1604     }
1605 
1606     // If this is a call entry, the variable should be a parameter.
1607     // FIXME: Handle CXXThisRegion as well. (This is not a priority because
1608     // 'this' should never be NULL, but this visitor isn't just for NULL and
1609     // UndefinedVal.)
1610     if (std::optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) {
1611       if (const auto *VR = dyn_cast<VarRegion>(R)) {
1612 
1613         if (const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
1614           ProgramStateManager &StateMgr = BRC.getStateManager();
1615           CallEventManager &CallMgr = StateMgr.getCallEventManager();
1616 
1617           CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(),
1618                                                   Succ->getState());
1619           InitE = Call->getArgExpr(Param->getFunctionScopeIndex());
1620         } else {
1621           // Handle Objective-C 'self'.
1622           assert(isa<ImplicitParamDecl>(VR->getDecl()));
1623           InitE = cast<ObjCMessageExpr>(CE->getCalleeContext()->getCallSite())
1624                       ->getInstanceReceiver()->IgnoreParenCasts();
1625         }
1626         IsParam = true;
1627       }
1628     }
1629 
1630     // If this is a CXXTempObjectRegion, the Expr responsible for its creation
1631     // is wrapped inside of it.
1632     if (const auto *TmpR = dyn_cast<CXXTempObjectRegion>(R))
1633       InitE = TmpR->getExpr();
1634   }
1635 
1636   if (!StoreSite)
1637     return nullptr;
1638 
1639   Satisfied = true;
1640 
1641   // If we have an expression that provided the value, try to track where it
1642   // came from.
1643   if (InitE) {
1644     if (!IsParam)
1645       InitE = InitE->IgnoreParenCasts();
1646 
1647     getParentTracker().track(InitE, StoreSite, Options);
1648   }
1649 
1650   // Let's try to find the region where the value came from.
1651   const MemRegion *OldRegion = nullptr;
1652 
1653   // If we have init expression, it might be simply a reference
1654   // to a variable, so we can use it.
1655   if (InitE) {
1656     // That region might still be not exactly what we are looking for.
1657     // In situations like `int &ref = val;`, we can't say that
1658     // `ref` is initialized with `val`, rather refers to `val`.
1659     //
1660     // In order, to mitigate situations like this, we check if the last
1661     // stored value in that region is the value that we track.
1662     //
1663     // TODO: support other situations better.
1664     if (const MemRegion *Candidate =
1665             getLocationRegionIfReference(InitE, Succ, false)) {
1666       const StoreManager &SM = BRC.getStateManager().getStoreManager();
1667 
1668       // Here we traverse the graph up to find the last node where the
1669       // candidate region is still in the store.
1670       for (const ExplodedNode *N = StoreSite; N; N = N->getFirstPred()) {
1671         if (SM.includedInBindings(N->getState()->getStore(), Candidate)) {
1672           // And if it was bound to the target value, we can use it.
1673           if (N->getState()->getSVal(Candidate) == V) {
1674             OldRegion = Candidate;
1675           }
1676           break;
1677         }
1678       }
1679     }
1680   }
1681 
1682   // Otherwise, if the current region does indeed contain the value
1683   // we are looking for, we can look for a region where this value
1684   // was before.
1685   //
1686   // It can be useful for situations like:
1687   //     new = identity(old)
1688   // where the analyzer knows that 'identity' returns the value of its
1689   // first argument.
1690   //
1691   // NOTE: If the region R is not a simple var region, it can contain
1692   //       V in one of its subregions.
1693   if (!OldRegion && StoreSite->getState()->getSVal(R) == V) {
1694     // Let's go up the graph to find the node where the region is
1695     // bound to V.
1696     const ExplodedNode *NodeWithoutBinding = StoreSite->getFirstPred();
1697     for (;
1698          NodeWithoutBinding && NodeWithoutBinding->getState()->getSVal(R) == V;
1699          NodeWithoutBinding = NodeWithoutBinding->getFirstPred()) {
1700     }
1701 
1702     if (NodeWithoutBinding) {
1703       // Let's try to find a unique binding for the value in that node.
1704       // We want to use this to find unique bindings because of the following
1705       // situations:
1706       //     b = a;
1707       //     c = identity(b);
1708       //
1709       // Telling the user that the value of 'a' is assigned to 'c', while
1710       // correct, can be confusing.
1711       StoreManager::FindUniqueBinding FB(V.getAsLocSymbol());
1712       BRC.getStateManager().iterBindings(NodeWithoutBinding->getState(), FB);
1713       if (FB)
1714         OldRegion = FB.getRegion();
1715     }
1716   }
1717 
1718   if (Options.Kind == TrackingKind::Condition && OriginSFC &&
1719       !OriginSFC->isParentOf(StoreSite->getStackFrame()))
1720     return nullptr;
1721 
1722   // Okay, we've found the binding. Emit an appropriate message.
1723   SmallString<256> sbuf;
1724   llvm::raw_svector_ostream os(sbuf);
1725 
1726   StoreInfo SI = {StoreInfo::Assignment, // default kind
1727                   StoreSite,
1728                   InitE,
1729                   V,
1730                   R,
1731                   OldRegion};
1732 
1733   if (std::optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) {
1734     const Stmt *S = PS->getStmt();
1735     const auto *DS = dyn_cast<DeclStmt>(S);
1736     const auto *VR = dyn_cast<VarRegion>(R);
1737 
1738     if (DS) {
1739       SI.StoreKind = StoreInfo::Initialization;
1740     } else if (isa<BlockExpr>(S)) {
1741       SI.StoreKind = StoreInfo::BlockCapture;
1742       if (VR) {
1743         // See if we can get the BlockVarRegion.
1744         ProgramStateRef State = StoreSite->getState();
1745         SVal V = StoreSite->getSVal(S);
1746         if (const auto *BDR =
1747                 dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
1748           if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
1749             getParentTracker().track(State->getSVal(OriginalR), OriginalR,
1750                                      Options, OriginSFC);
1751           }
1752         }
1753       }
1754     }
1755   } else if (SI.StoreSite->getLocation().getAs<CallEnter>() &&
1756              isa<VarRegion>(SI.Dest)) {
1757     SI.StoreKind = StoreInfo::CallArgument;
1758   }
1759 
1760   return getParentTracker().handle(SI, BRC, Options);
1761 }
1762 
1763 //===----------------------------------------------------------------------===//
1764 // Implementation of TrackConstraintBRVisitor.
1765 //===----------------------------------------------------------------------===//
1766 
Profile(llvm::FoldingSetNodeID & ID) const1767 void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const {
1768   static int tag = 0;
1769   ID.AddPointer(&tag);
1770   ID.AddString(Message);
1771   ID.AddBoolean(Assumption);
1772   ID.Add(Constraint);
1773 }
1774 
1775 /// Return the tag associated with this visitor.  This tag will be used
1776 /// to make all PathDiagnosticPieces created by this visitor.
getTag()1777 const char *TrackConstraintBRVisitor::getTag() {
1778   return "TrackConstraintBRVisitor";
1779 }
1780 
isZeroCheck() const1781 bool TrackConstraintBRVisitor::isZeroCheck() const {
1782   return !Assumption && Constraint.getAs<Loc>();
1783 }
1784 
isUnderconstrained(const ExplodedNode * N) const1785 bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const {
1786   if (isZeroCheck())
1787     return N->getState()->isNull(Constraint).isUnderconstrained();
1788   return (bool)N->getState()->assume(Constraint, !Assumption);
1789 }
1790 
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport &)1791 PathDiagnosticPieceRef TrackConstraintBRVisitor::VisitNode(
1792     const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &) {
1793   const ExplodedNode *PrevN = N->getFirstPred();
1794   if (IsSatisfied)
1795     return nullptr;
1796 
1797   // Start tracking after we see the first state in which the value is
1798   // constrained.
1799   if (!IsTrackingTurnedOn)
1800     if (!isUnderconstrained(N))
1801       IsTrackingTurnedOn = true;
1802   if (!IsTrackingTurnedOn)
1803     return nullptr;
1804 
1805   // Check if in the previous state it was feasible for this constraint
1806   // to *not* be true.
1807   if (isUnderconstrained(PrevN)) {
1808     IsSatisfied = true;
1809 
1810     // At this point, the negation of the constraint should be infeasible. If it
1811     // is feasible, make sure that the negation of the constrainti was
1812     // infeasible in the current state.  If it is feasible, we somehow missed
1813     // the transition point.
1814     assert(!isUnderconstrained(N));
1815 
1816     // Construct a new PathDiagnosticPiece.
1817     ProgramPoint P = N->getLocation();
1818 
1819     // If this node already have a specialized note, it's probably better
1820     // than our generic note.
1821     // FIXME: This only looks for note tags, not for other ways to add a note.
1822     if (isa_and_nonnull<NoteTag>(P.getTag()))
1823       return nullptr;
1824 
1825     PathDiagnosticLocation L =
1826       PathDiagnosticLocation::create(P, BRC.getSourceManager());
1827     if (!L.isValid())
1828       return nullptr;
1829 
1830     auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message);
1831     X->setTag(getTag());
1832     return std::move(X);
1833   }
1834 
1835   return nullptr;
1836 }
1837 
1838 //===----------------------------------------------------------------------===//
1839 // Implementation of SuppressInlineDefensiveChecksVisitor.
1840 //===----------------------------------------------------------------------===//
1841 
1842 SuppressInlineDefensiveChecksVisitor::
SuppressInlineDefensiveChecksVisitor(DefinedSVal Value,const ExplodedNode * N)1843 SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N)
1844     : V(Value) {
1845   // Check if the visitor is disabled.
1846   AnalyzerOptions &Options = N->getState()->getAnalysisManager().options;
1847   if (!Options.ShouldSuppressInlinedDefensiveChecks)
1848     IsSatisfied = true;
1849 }
1850 
Profile(llvm::FoldingSetNodeID & ID) const1851 void SuppressInlineDefensiveChecksVisitor::Profile(
1852     llvm::FoldingSetNodeID &ID) const {
1853   static int id = 0;
1854   ID.AddPointer(&id);
1855   ID.Add(V);
1856 }
1857 
getTag()1858 const char *SuppressInlineDefensiveChecksVisitor::getTag() {
1859   return "IDCVisitor";
1860 }
1861 
1862 PathDiagnosticPieceRef
VisitNode(const ExplodedNode * Succ,BugReporterContext & BRC,PathSensitiveBugReport & BR)1863 SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
1864                                                 BugReporterContext &BRC,
1865                                                 PathSensitiveBugReport &BR) {
1866   const ExplodedNode *Pred = Succ->getFirstPred();
1867   if (IsSatisfied)
1868     return nullptr;
1869 
1870   // Start tracking after we see the first state in which the value is null.
1871   if (!IsTrackingTurnedOn)
1872     if (Succ->getState()->isNull(V).isConstrainedTrue())
1873       IsTrackingTurnedOn = true;
1874   if (!IsTrackingTurnedOn)
1875     return nullptr;
1876 
1877   // Check if in the previous state it was feasible for this value
1878   // to *not* be null.
1879   if (!Pred->getState()->isNull(V).isConstrainedTrue() &&
1880       Succ->getState()->isNull(V).isConstrainedTrue()) {
1881     IsSatisfied = true;
1882 
1883     // Check if this is inlined defensive checks.
1884     const LocationContext *CurLC = Succ->getLocationContext();
1885     const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext();
1886     if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) {
1887       BR.markInvalid("Suppress IDC", CurLC);
1888       return nullptr;
1889     }
1890 
1891     // Treat defensive checks in function-like macros as if they were an inlined
1892     // defensive check. If the bug location is not in a macro and the
1893     // terminator for the current location is in a macro then suppress the
1894     // warning.
1895     auto BugPoint = BR.getErrorNode()->getLocation().getAs<StmtPoint>();
1896 
1897     if (!BugPoint)
1898       return nullptr;
1899 
1900     ProgramPoint CurPoint = Succ->getLocation();
1901     const Stmt *CurTerminatorStmt = nullptr;
1902     if (auto BE = CurPoint.getAs<BlockEdge>()) {
1903       CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
1904     } else if (auto SP = CurPoint.getAs<StmtPoint>()) {
1905       const Stmt *CurStmt = SP->getStmt();
1906       if (!CurStmt->getBeginLoc().isMacroID())
1907         return nullptr;
1908 
1909       CFGStmtMap *Map = CurLC->getAnalysisDeclContext()->getCFGStmtMap();
1910       CurTerminatorStmt = Map->getBlock(CurStmt)->getTerminatorStmt();
1911     } else {
1912       return nullptr;
1913     }
1914 
1915     if (!CurTerminatorStmt)
1916       return nullptr;
1917 
1918     SourceLocation TerminatorLoc = CurTerminatorStmt->getBeginLoc();
1919     if (TerminatorLoc.isMacroID()) {
1920       SourceLocation BugLoc = BugPoint->getStmt()->getBeginLoc();
1921 
1922       // Suppress reports unless we are in that same macro.
1923       if (!BugLoc.isMacroID() ||
1924           getMacroName(BugLoc, BRC) != getMacroName(TerminatorLoc, BRC)) {
1925         BR.markInvalid("Suppress Macro IDC", CurLC);
1926       }
1927       return nullptr;
1928     }
1929   }
1930   return nullptr;
1931 }
1932 
1933 //===----------------------------------------------------------------------===//
1934 // TrackControlDependencyCondBRVisitor.
1935 //===----------------------------------------------------------------------===//
1936 
1937 namespace {
1938 /// Tracks the expressions that are a control dependency of the node that was
1939 /// supplied to the constructor.
1940 /// For example:
1941 ///
1942 ///   cond = 1;
1943 ///   if (cond)
1944 ///     10 / 0;
1945 ///
1946 /// An error is emitted at line 3. This visitor realizes that the branch
1947 /// on line 2 is a control dependency of line 3, and tracks it's condition via
1948 /// trackExpressionValue().
1949 class TrackControlDependencyCondBRVisitor final
1950     : public TrackingBugReporterVisitor {
1951   const ExplodedNode *Origin;
1952   ControlDependencyCalculator ControlDeps;
1953   llvm::SmallSet<const CFGBlock *, 32> VisitedBlocks;
1954 
1955 public:
TrackControlDependencyCondBRVisitor(TrackerRef ParentTracker,const ExplodedNode * O)1956   TrackControlDependencyCondBRVisitor(TrackerRef ParentTracker,
1957                                       const ExplodedNode *O)
1958       : TrackingBugReporterVisitor(ParentTracker), Origin(O),
1959         ControlDeps(&O->getCFG()) {}
1960 
Profile(llvm::FoldingSetNodeID & ID) const1961   void Profile(llvm::FoldingSetNodeID &ID) const override {
1962     static int x = 0;
1963     ID.AddPointer(&x);
1964   }
1965 
1966   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
1967                                    BugReporterContext &BRC,
1968                                    PathSensitiveBugReport &BR) override;
1969 };
1970 } // end of anonymous namespace
1971 
1972 static std::shared_ptr<PathDiagnosticEventPiece>
constructDebugPieceForTrackedCondition(const Expr * Cond,const ExplodedNode * N,BugReporterContext & BRC)1973 constructDebugPieceForTrackedCondition(const Expr *Cond,
1974                                        const ExplodedNode *N,
1975                                        BugReporterContext &BRC) {
1976 
1977   if (BRC.getAnalyzerOptions().AnalysisDiagOpt == PD_NONE ||
1978       !BRC.getAnalyzerOptions().ShouldTrackConditionsDebug)
1979     return nullptr;
1980 
1981   std::string ConditionText = std::string(Lexer::getSourceText(
1982       CharSourceRange::getTokenRange(Cond->getSourceRange()),
1983       BRC.getSourceManager(), BRC.getASTContext().getLangOpts()));
1984 
1985   return std::make_shared<PathDiagnosticEventPiece>(
1986       PathDiagnosticLocation::createBegin(
1987           Cond, BRC.getSourceManager(), N->getLocationContext()),
1988           (Twine() + "Tracking condition '" + ConditionText + "'").str());
1989 }
1990 
isAssertlikeBlock(const CFGBlock * B,ASTContext & Context)1991 static bool isAssertlikeBlock(const CFGBlock *B, ASTContext &Context) {
1992   if (B->succ_size() != 2)
1993     return false;
1994 
1995   const CFGBlock *Then = B->succ_begin()->getReachableBlock();
1996   const CFGBlock *Else = (B->succ_begin() + 1)->getReachableBlock();
1997 
1998   if (!Then || !Else)
1999     return false;
2000 
2001   if (Then->isInevitablySinking() != Else->isInevitablySinking())
2002     return true;
2003 
2004   // For the following condition the following CFG would be built:
2005   //
2006   //                          ------------->
2007   //                         /              \
2008   //                       [B1] -> [B2] -> [B3] -> [sink]
2009   // assert(A && B || C);            \       \
2010   //                                  -----------> [go on with the execution]
2011   //
2012   // It so happens that CFGBlock::getTerminatorCondition returns 'A' for block
2013   // B1, 'A && B' for B2, and 'A && B || C' for B3. Let's check whether we
2014   // reached the end of the condition!
2015   if (const Stmt *ElseCond = Else->getTerminatorCondition())
2016     if (const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
2017       if (BinOp->isLogicalOp())
2018         return isAssertlikeBlock(Else, Context);
2019 
2020   return false;
2021 }
2022 
2023 PathDiagnosticPieceRef
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)2024 TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N,
2025                                                BugReporterContext &BRC,
2026                                                PathSensitiveBugReport &BR) {
2027   // We can only reason about control dependencies within the same stack frame.
2028   if (Origin->getStackFrame() != N->getStackFrame())
2029     return nullptr;
2030 
2031   CFGBlock *NB = const_cast<CFGBlock *>(N->getCFGBlock());
2032 
2033   // Skip if we already inspected this block.
2034   if (!VisitedBlocks.insert(NB).second)
2035     return nullptr;
2036 
2037   CFGBlock *OriginB = const_cast<CFGBlock *>(Origin->getCFGBlock());
2038 
2039   // TODO: Cache CFGBlocks for each ExplodedNode.
2040   if (!OriginB || !NB)
2041     return nullptr;
2042 
2043   if (isAssertlikeBlock(NB, BRC.getASTContext()))
2044     return nullptr;
2045 
2046   if (ControlDeps.isControlDependent(OriginB, NB)) {
2047     // We don't really want to explain for range loops. Evidence suggests that
2048     // the only thing that leads to is the addition of calls to operator!=.
2049     if (llvm::isa_and_nonnull<CXXForRangeStmt>(NB->getTerminatorStmt()))
2050       return nullptr;
2051 
2052     if (const Expr *Condition = NB->getLastCondition()) {
2053 
2054       // If we can't retrieve a sensible condition, just bail out.
2055       const Expr *InnerExpr = peelOffOuterExpr(Condition, N);
2056       if (!InnerExpr)
2057         return nullptr;
2058 
2059       // If the condition was a function call, we likely won't gain much from
2060       // tracking it either. Evidence suggests that it will mostly trigger in
2061       // scenarios like this:
2062       //
2063       //   void f(int *x) {
2064       //     x = nullptr;
2065       //     if (alwaysTrue()) // We don't need a whole lot of explanation
2066       //                       // here, the function name is good enough.
2067       //       *x = 5;
2068       //   }
2069       //
2070       // Its easy to create a counterexample where this heuristic would make us
2071       // lose valuable information, but we've never really seen one in practice.
2072       if (isa<CallExpr>(InnerExpr))
2073         return nullptr;
2074 
2075       // Keeping track of the already tracked conditions on a visitor level
2076       // isn't sufficient, because a new visitor is created for each tracked
2077       // expression, hence the BugReport level set.
2078       if (BR.addTrackedCondition(N)) {
2079         getParentTracker().track(InnerExpr, N,
2080                                  {bugreporter::TrackingKind::Condition,
2081                                   /*EnableNullFPSuppression=*/false});
2082         return constructDebugPieceForTrackedCondition(Condition, N, BRC);
2083       }
2084     }
2085   }
2086 
2087   return nullptr;
2088 }
2089 
2090 //===----------------------------------------------------------------------===//
2091 // Implementation of trackExpressionValue.
2092 //===----------------------------------------------------------------------===//
2093 
peelOffOuterExpr(const Expr * Ex,const ExplodedNode * N)2094 static const Expr *peelOffOuterExpr(const Expr *Ex, const ExplodedNode *N) {
2095 
2096   Ex = Ex->IgnoreParenCasts();
2097   if (const auto *FE = dyn_cast<FullExpr>(Ex))
2098     return peelOffOuterExpr(FE->getSubExpr(), N);
2099   if (const auto *OVE = dyn_cast<OpaqueValueExpr>(Ex))
2100     return peelOffOuterExpr(OVE->getSourceExpr(), N);
2101   if (const auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) {
2102     const auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
2103     if (PropRef && PropRef->isMessagingGetter()) {
2104       const Expr *GetterMessageSend =
2105           POE->getSemanticExpr(POE->getNumSemanticExprs() - 1);
2106       assert(isa<ObjCMessageExpr>(GetterMessageSend->IgnoreParenCasts()));
2107       return peelOffOuterExpr(GetterMessageSend, N);
2108     }
2109   }
2110 
2111   // Peel off the ternary operator.
2112   if (const auto *CO = dyn_cast<ConditionalOperator>(Ex)) {
2113     // Find a node where the branching occurred and find out which branch
2114     // we took (true/false) by looking at the ExplodedGraph.
2115     const ExplodedNode *NI = N;
2116     do {
2117       ProgramPoint ProgPoint = NI->getLocation();
2118       if (std::optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
2119         const CFGBlock *srcBlk = BE->getSrc();
2120         if (const Stmt *term = srcBlk->getTerminatorStmt()) {
2121           if (term == CO) {
2122             bool TookTrueBranch = (*(srcBlk->succ_begin()) == BE->getDst());
2123             if (TookTrueBranch)
2124               return peelOffOuterExpr(CO->getTrueExpr(), N);
2125             else
2126               return peelOffOuterExpr(CO->getFalseExpr(), N);
2127           }
2128         }
2129       }
2130       NI = NI->getFirstPred();
2131     } while (NI);
2132   }
2133 
2134   if (auto *BO = dyn_cast<BinaryOperator>(Ex))
2135     if (const Expr *SubEx = peelOffPointerArithmetic(BO))
2136       return peelOffOuterExpr(SubEx, N);
2137 
2138   if (auto *UO = dyn_cast<UnaryOperator>(Ex)) {
2139     if (UO->getOpcode() == UO_LNot)
2140       return peelOffOuterExpr(UO->getSubExpr(), N);
2141 
2142     // FIXME: There's a hack in our Store implementation that always computes
2143     // field offsets around null pointers as if they are always equal to 0.
2144     // The idea here is to report accesses to fields as null dereferences
2145     // even though the pointer value that's being dereferenced is actually
2146     // the offset of the field rather than exactly 0.
2147     // See the FIXME in StoreManager's getLValueFieldOrIvar() method.
2148     // This code interacts heavily with this hack; otherwise the value
2149     // would not be null at all for most fields, so we'd be unable to track it.
2150     if (UO->getOpcode() == UO_AddrOf && UO->getSubExpr()->isLValue())
2151       if (const Expr *DerefEx = bugreporter::getDerefExpr(UO->getSubExpr()))
2152         return peelOffOuterExpr(DerefEx, N);
2153   }
2154 
2155   return Ex;
2156 }
2157 
2158 /// Find the ExplodedNode where the lvalue (the value of 'Ex')
2159 /// was computed.
findNodeForExpression(const ExplodedNode * N,const Expr * Inner)2160 static const ExplodedNode* findNodeForExpression(const ExplodedNode *N,
2161                                                  const Expr *Inner) {
2162   while (N) {
2163     if (N->getStmtForDiagnostics() == Inner)
2164       return N;
2165     N = N->getFirstPred();
2166   }
2167   return N;
2168 }
2169 
2170 //===----------------------------------------------------------------------===//
2171 //                            Tracker implementation
2172 //===----------------------------------------------------------------------===//
2173 
constructNote(StoreInfo SI,BugReporterContext & BRC,StringRef NodeText)2174 PathDiagnosticPieceRef StoreHandler::constructNote(StoreInfo SI,
2175                                                    BugReporterContext &BRC,
2176                                                    StringRef NodeText) {
2177   // Construct a new PathDiagnosticPiece.
2178   ProgramPoint P = SI.StoreSite->getLocation();
2179   PathDiagnosticLocation L;
2180   if (P.getAs<CallEnter>() && SI.SourceOfTheValue)
2181     L = PathDiagnosticLocation(SI.SourceOfTheValue, BRC.getSourceManager(),
2182                                P.getLocationContext());
2183 
2184   if (!L.isValid() || !L.asLocation().isValid())
2185     L = PathDiagnosticLocation::create(P, BRC.getSourceManager());
2186 
2187   if (!L.isValid() || !L.asLocation().isValid())
2188     return nullptr;
2189 
2190   return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
2191 }
2192 
2193 namespace {
2194 class DefaultStoreHandler final : public StoreHandler {
2195 public:
2196   using StoreHandler::StoreHandler;
2197 
handle(StoreInfo SI,BugReporterContext & BRC,TrackingOptions Opts)2198   PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC,
2199                                 TrackingOptions Opts) override {
2200     // Okay, we've found the binding. Emit an appropriate message.
2201     SmallString<256> Buffer;
2202     llvm::raw_svector_ostream OS(Buffer);
2203 
2204     switch (SI.StoreKind) {
2205     case StoreInfo::Initialization:
2206     case StoreInfo::BlockCapture:
2207       showBRDiagnostics(OS, SI);
2208       break;
2209     case StoreInfo::CallArgument:
2210       showBRParamDiagnostics(OS, SI);
2211       break;
2212     case StoreInfo::Assignment:
2213       showBRDefaultDiagnostics(OS, SI);
2214       break;
2215     }
2216 
2217     if (Opts.Kind == bugreporter::TrackingKind::Condition)
2218       OS << WillBeUsedForACondition;
2219 
2220     return constructNote(SI, BRC, OS.str());
2221   }
2222 };
2223 
2224 class ControlDependencyHandler final : public ExpressionHandler {
2225 public:
2226   using ExpressionHandler::ExpressionHandler;
2227 
handle(const Expr * Inner,const ExplodedNode * InputNode,const ExplodedNode * LVNode,TrackingOptions Opts)2228   Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
2229                          const ExplodedNode *LVNode,
2230                          TrackingOptions Opts) override {
2231     PathSensitiveBugReport &Report = getParentTracker().getReport();
2232 
2233     // We only track expressions if we believe that they are important. Chances
2234     // are good that control dependencies to the tracking point are also
2235     // important because of this, let's explain why we believe control reached
2236     // this point.
2237     // TODO: Shouldn't we track control dependencies of every bug location,
2238     // rather than only tracked expressions?
2239     if (LVNode->getState()
2240             ->getAnalysisManager()
2241             .getAnalyzerOptions()
2242             .ShouldTrackConditions) {
2243       Report.addVisitor<TrackControlDependencyCondBRVisitor>(
2244           &getParentTracker(), InputNode);
2245       return {/*FoundSomethingToTrack=*/true};
2246     }
2247 
2248     return {};
2249   }
2250 };
2251 
2252 class NilReceiverHandler final : public ExpressionHandler {
2253 public:
2254   using ExpressionHandler::ExpressionHandler;
2255 
handle(const Expr * Inner,const ExplodedNode * InputNode,const ExplodedNode * LVNode,TrackingOptions Opts)2256   Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
2257                          const ExplodedNode *LVNode,
2258                          TrackingOptions Opts) override {
2259     // The message send could be nil due to the receiver being nil.
2260     // At this point in the path, the receiver should be live since we are at
2261     // the message send expr. If it is nil, start tracking it.
2262     if (const Expr *Receiver =
2263             NilReceiverBRVisitor::getNilReceiver(Inner, LVNode))
2264       return getParentTracker().track(Receiver, LVNode, Opts);
2265 
2266     return {};
2267   }
2268 };
2269 
2270 class ArrayIndexHandler final : public ExpressionHandler {
2271 public:
2272   using ExpressionHandler::ExpressionHandler;
2273 
handle(const Expr * Inner,const ExplodedNode * InputNode,const ExplodedNode * LVNode,TrackingOptions Opts)2274   Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
2275                          const ExplodedNode *LVNode,
2276                          TrackingOptions Opts) override {
2277     // Track the index if this is an array subscript.
2278     if (const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
2279       return getParentTracker().track(
2280           Arr->getIdx(), LVNode,
2281           {Opts.Kind, /*EnableNullFPSuppression*/ false});
2282 
2283     return {};
2284   }
2285 };
2286 
2287 // TODO: extract it into more handlers
2288 class InterestingLValueHandler final : public ExpressionHandler {
2289 public:
2290   using ExpressionHandler::ExpressionHandler;
2291 
handle(const Expr * Inner,const ExplodedNode * InputNode,const ExplodedNode * LVNode,TrackingOptions Opts)2292   Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
2293                          const ExplodedNode *LVNode,
2294                          TrackingOptions Opts) override {
2295     ProgramStateRef LVState = LVNode->getState();
2296     const StackFrameContext *SFC = LVNode->getStackFrame();
2297     PathSensitiveBugReport &Report = getParentTracker().getReport();
2298     Tracker::Result Result;
2299 
2300     // See if the expression we're interested refers to a variable.
2301     // If so, we can track both its contents and constraints on its value.
2302     if (ExplodedGraph::isInterestingLValueExpr(Inner)) {
2303       SVal LVal = LVNode->getSVal(Inner);
2304 
2305       const MemRegion *RR = getLocationRegionIfReference(Inner, LVNode);
2306       bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
2307 
2308       // If this is a C++ reference to a null pointer, we are tracking the
2309       // pointer. In addition, we should find the store at which the reference
2310       // got initialized.
2311       if (RR && !LVIsNull)
2312         Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));
2313 
2314       // In case of C++ references, we want to differentiate between a null
2315       // reference and reference to null pointer.
2316       // If the LVal is null, check if we are dealing with null reference.
2317       // For those, we want to track the location of the reference.
2318       const MemRegion *R =
2319           (RR && LVIsNull) ? RR : LVNode->getSVal(Inner).getAsRegion();
2320 
2321       if (R) {
2322 
2323         // Mark both the variable region and its contents as interesting.
2324         SVal V = LVState->getRawSVal(loc::MemRegionVal(R));
2325         Report.addVisitor<NoStoreFuncVisitor>(cast<SubRegion>(R), Opts.Kind);
2326 
2327         // When we got here, we do have something to track, and we will
2328         // interrupt.
2329         Result.FoundSomethingToTrack = true;
2330         Result.WasInterrupted = true;
2331 
2332         MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2333             LVNode, R, Opts.EnableNullFPSuppression, Report, V);
2334 
2335         Report.markInteresting(V, Opts.Kind);
2336         Report.addVisitor<UndefOrNullArgVisitor>(R);
2337 
2338         // If the contents are symbolic and null, find out when they became
2339         // null.
2340         if (V.getAsLocSymbol(/*IncludeBaseRegions=*/true))
2341           if (LVState->isNull(V).isConstrainedTrue())
2342             Report.addVisitor<TrackConstraintBRVisitor>(
2343                 V.castAs<DefinedSVal>(),
2344                 /*Assumption=*/false, "Assuming pointer value is null");
2345 
2346         // Add visitor, which will suppress inline defensive checks.
2347         if (auto DV = V.getAs<DefinedSVal>())
2348           if (!DV->isZeroConstant() && Opts.EnableNullFPSuppression)
2349             // Note that LVNode may be too late (i.e., too far from the
2350             // InputNode) because the lvalue may have been computed before the
2351             // inlined call was evaluated. InputNode may as well be too early
2352             // here, because the symbol is already dead; this, however, is fine
2353             // because we can still find the node in which it collapsed to null
2354             // previously.
2355             Report.addVisitor<SuppressInlineDefensiveChecksVisitor>(*DV,
2356                                                                     InputNode);
2357         getParentTracker().track(V, R, Opts, SFC);
2358       }
2359     }
2360 
2361     return Result;
2362   }
2363 };
2364 
2365 /// Adds a ReturnVisitor if the given statement represents a call that was
2366 /// inlined.
2367 ///
2368 /// This will search back through the ExplodedGraph, starting from the given
2369 /// node, looking for when the given statement was processed. If it turns out
2370 /// the statement is a call that was inlined, we add the visitor to the
2371 /// bug report, so it can print a note later.
2372 class InlinedFunctionCallHandler final : public ExpressionHandler {
2373   using ExpressionHandler::ExpressionHandler;
2374 
handle(const Expr * E,const ExplodedNode * InputNode,const ExplodedNode * ExprNode,TrackingOptions Opts)2375   Tracker::Result handle(const Expr *E, const ExplodedNode *InputNode,
2376                          const ExplodedNode *ExprNode,
2377                          TrackingOptions Opts) override {
2378     if (!CallEvent::isCallStmt(E))
2379       return {};
2380 
2381     // First, find when we processed the statement.
2382     // If we work with a 'CXXNewExpr' that is going to be purged away before
2383     // its call take place. We would catch that purge in the last condition
2384     // as a 'StmtPoint' so we have to bypass it.
2385     const bool BypassCXXNewExprEval = isa<CXXNewExpr>(E);
2386 
2387     // This is moving forward when we enter into another context.
2388     const StackFrameContext *CurrentSFC = ExprNode->getStackFrame();
2389 
2390     do {
2391       // If that is satisfied we found our statement as an inlined call.
2392       if (std::optional<CallExitEnd> CEE =
2393               ExprNode->getLocationAs<CallExitEnd>())
2394         if (CEE->getCalleeContext()->getCallSite() == E)
2395           break;
2396 
2397       // Try to move forward to the end of the call-chain.
2398       ExprNode = ExprNode->getFirstPred();
2399       if (!ExprNode)
2400         break;
2401 
2402       const StackFrameContext *PredSFC = ExprNode->getStackFrame();
2403 
2404       // If that is satisfied we found our statement.
2405       // FIXME: This code currently bypasses the call site for the
2406       //        conservatively evaluated allocator.
2407       if (!BypassCXXNewExprEval)
2408         if (std::optional<StmtPoint> SP = ExprNode->getLocationAs<StmtPoint>())
2409           // See if we do not enter into another context.
2410           if (SP->getStmt() == E && CurrentSFC == PredSFC)
2411             break;
2412 
2413       CurrentSFC = PredSFC;
2414     } while (ExprNode->getStackFrame() == CurrentSFC);
2415 
2416     // Next, step over any post-statement checks.
2417     while (ExprNode && ExprNode->getLocation().getAs<PostStmt>())
2418       ExprNode = ExprNode->getFirstPred();
2419     if (!ExprNode)
2420       return {};
2421 
2422     // Finally, see if we inlined the call.
2423     std::optional<CallExitEnd> CEE = ExprNode->getLocationAs<CallExitEnd>();
2424     if (!CEE)
2425       return {};
2426 
2427     const StackFrameContext *CalleeContext = CEE->getCalleeContext();
2428     if (CalleeContext->getCallSite() != E)
2429       return {};
2430 
2431     // Check the return value.
2432     ProgramStateRef State = ExprNode->getState();
2433     SVal RetVal = ExprNode->getSVal(E);
2434 
2435     // Handle cases where a reference is returned and then immediately used.
2436     if (cast<Expr>(E)->isGLValue())
2437       if (std::optional<Loc> LValue = RetVal.getAs<Loc>())
2438         RetVal = State->getSVal(*LValue);
2439 
2440     // See if the return value is NULL. If so, suppress the report.
2441     AnalyzerOptions &Options = State->getAnalysisManager().options;
2442 
2443     bool EnableNullFPSuppression = false;
2444     if (Opts.EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths)
2445       if (std::optional<Loc> RetLoc = RetVal.getAs<Loc>())
2446         EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
2447 
2448     PathSensitiveBugReport &Report = getParentTracker().getReport();
2449     Report.addVisitor<ReturnVisitor>(&getParentTracker(), CalleeContext,
2450                                      EnableNullFPSuppression, Options,
2451                                      Opts.Kind);
2452     return {true};
2453   }
2454 };
2455 
2456 class DefaultExpressionHandler final : public ExpressionHandler {
2457 public:
2458   using ExpressionHandler::ExpressionHandler;
2459 
handle(const Expr * Inner,const ExplodedNode * InputNode,const ExplodedNode * LVNode,TrackingOptions Opts)2460   Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
2461                          const ExplodedNode *LVNode,
2462                          TrackingOptions Opts) override {
2463     ProgramStateRef LVState = LVNode->getState();
2464     const StackFrameContext *SFC = LVNode->getStackFrame();
2465     PathSensitiveBugReport &Report = getParentTracker().getReport();
2466     Tracker::Result Result;
2467 
2468     // If the expression is not an "lvalue expression", we can still
2469     // track the constraints on its contents.
2470     SVal V = LVState->getSValAsScalarOrLoc(Inner, LVNode->getLocationContext());
2471 
2472     // Is it a symbolic value?
2473     if (auto L = V.getAs<loc::MemRegionVal>()) {
2474       // FIXME: this is a hack for fixing a later crash when attempting to
2475       // dereference a void* pointer.
2476       // We should not try to dereference pointers at all when we don't care
2477       // what is written inside the pointer.
2478       bool CanDereference = true;
2479       if (const auto *SR = L->getRegionAs<SymbolicRegion>()) {
2480         if (SR->getPointeeStaticType()->isVoidType())
2481           CanDereference = false;
2482       } else if (L->getRegionAs<AllocaRegion>())
2483         CanDereference = false;
2484 
2485       // At this point we are dealing with the region's LValue.
2486       // However, if the rvalue is a symbolic region, we should track it as
2487       // well. Try to use the correct type when looking up the value.
2488       SVal RVal;
2489       if (ExplodedGraph::isInterestingLValueExpr(Inner))
2490         RVal = LVState->getRawSVal(*L, Inner->getType());
2491       else if (CanDereference)
2492         RVal = LVState->getSVal(L->getRegion());
2493 
2494       if (CanDereference) {
2495         Report.addVisitor<UndefOrNullArgVisitor>(L->getRegion());
2496         Result.FoundSomethingToTrack = true;
2497 
2498         if (!RVal.isUnknown())
2499           Result.combineWith(
2500               getParentTracker().track(RVal, L->getRegion(), Opts, SFC));
2501       }
2502 
2503       const MemRegion *RegionRVal = RVal.getAsRegion();
2504       if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
2505         Report.markInteresting(RegionRVal, Opts.Kind);
2506         Report.addVisitor<TrackConstraintBRVisitor>(
2507             loc::MemRegionVal(RegionRVal),
2508             /*Assumption=*/false, "Assuming pointer value is null");
2509         Result.FoundSomethingToTrack = true;
2510       }
2511     }
2512 
2513     return Result;
2514   }
2515 };
2516 
2517 /// Attempts to add visitors to track an RValue expression back to its point of
2518 /// origin.
2519 class PRValueHandler final : public ExpressionHandler {
2520 public:
2521   using ExpressionHandler::ExpressionHandler;
2522 
handle(const Expr * E,const ExplodedNode * InputNode,const ExplodedNode * ExprNode,TrackingOptions Opts)2523   Tracker::Result handle(const Expr *E, const ExplodedNode *InputNode,
2524                          const ExplodedNode *ExprNode,
2525                          TrackingOptions Opts) override {
2526     if (!E->isPRValue())
2527       return {};
2528 
2529     const ExplodedNode *RVNode = findNodeForExpression(ExprNode, E);
2530     if (!RVNode)
2531       return {};
2532 
2533     Tracker::Result CombinedResult;
2534     Tracker &Parent = getParentTracker();
2535 
2536     const auto track = [&CombinedResult, &Parent, ExprNode,
2537                         Opts](const Expr *Inner) {
2538       CombinedResult.combineWith(Parent.track(Inner, ExprNode, Opts));
2539     };
2540 
2541     // FIXME: Initializer lists can appear in many different contexts
2542     // and most of them needs a special handling. For now let's handle
2543     // what we can. If the initializer list only has 1 element, we track
2544     // that.
2545     // This snippet even handles nesting, e.g.: int *x{{{{{y}}}}};
2546     if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
2547       if (ILE->getNumInits() == 1) {
2548         track(ILE->getInit(0));
2549 
2550         return CombinedResult;
2551       }
2552 
2553       return {};
2554     }
2555 
2556     ProgramStateRef RVState = RVNode->getState();
2557     SVal V = RVState->getSValAsScalarOrLoc(E, RVNode->getLocationContext());
2558     const auto *BO = dyn_cast<BinaryOperator>(E);
2559 
2560     if (!BO || !BO->isMultiplicativeOp() || !V.isZeroConstant())
2561       return {};
2562 
2563     SVal RHSV = RVState->getSVal(BO->getRHS(), RVNode->getLocationContext());
2564     SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->getLocationContext());
2565 
2566     // Track both LHS and RHS of a multiplication.
2567     if (BO->getOpcode() == BO_Mul) {
2568       if (LHSV.isZeroConstant())
2569         track(BO->getLHS());
2570       if (RHSV.isZeroConstant())
2571         track(BO->getRHS());
2572     } else { // Track only the LHS of a division or a modulo.
2573       if (LHSV.isZeroConstant())
2574         track(BO->getLHS());
2575     }
2576 
2577     return CombinedResult;
2578   }
2579 };
2580 } // namespace
2581 
Tracker(PathSensitiveBugReport & Report)2582 Tracker::Tracker(PathSensitiveBugReport &Report) : Report(Report) {
2583   // Default expression handlers.
2584   addLowPriorityHandler<ControlDependencyHandler>();
2585   addLowPriorityHandler<NilReceiverHandler>();
2586   addLowPriorityHandler<ArrayIndexHandler>();
2587   addLowPriorityHandler<InterestingLValueHandler>();
2588   addLowPriorityHandler<InlinedFunctionCallHandler>();
2589   addLowPriorityHandler<DefaultExpressionHandler>();
2590   addLowPriorityHandler<PRValueHandler>();
2591   // Default store handlers.
2592   addHighPriorityHandler<DefaultStoreHandler>();
2593 }
2594 
track(const Expr * E,const ExplodedNode * N,TrackingOptions Opts)2595 Tracker::Result Tracker::track(const Expr *E, const ExplodedNode *N,
2596                                TrackingOptions Opts) {
2597   if (!E || !N)
2598     return {};
2599 
2600   const Expr *Inner = peelOffOuterExpr(E, N);
2601   const ExplodedNode *LVNode = findNodeForExpression(N, Inner);
2602   if (!LVNode)
2603     return {};
2604 
2605   Result CombinedResult;
2606   // Iterate through the handlers in the order according to their priorities.
2607   for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
2608     CombinedResult.combineWith(Handler->handle(Inner, N, LVNode, Opts));
2609     if (CombinedResult.WasInterrupted) {
2610       // There is no need to confuse our users here.
2611       // We got interrupted, but our users don't need to know about it.
2612       CombinedResult.WasInterrupted = false;
2613       break;
2614     }
2615   }
2616 
2617   return CombinedResult;
2618 }
2619 
track(SVal V,const MemRegion * R,TrackingOptions Opts,const StackFrameContext * Origin)2620 Tracker::Result Tracker::track(SVal V, const MemRegion *R, TrackingOptions Opts,
2621                                const StackFrameContext *Origin) {
2622   if (!V.isUnknown()) {
2623     Report.addVisitor<StoreSiteFinder>(this, V, R, Opts, Origin);
2624     return {true};
2625   }
2626   return {};
2627 }
2628 
handle(StoreInfo SI,BugReporterContext & BRC,TrackingOptions Opts)2629 PathDiagnosticPieceRef Tracker::handle(StoreInfo SI, BugReporterContext &BRC,
2630                                        TrackingOptions Opts) {
2631   // Iterate through the handlers in the order according to their priorities.
2632   for (StoreHandlerPtr &Handler : StoreHandlers) {
2633     if (PathDiagnosticPieceRef Result = Handler->handle(SI, BRC, Opts))
2634       // If the handler produced a non-null piece, return it.
2635       // There is no need in asking other handlers.
2636       return Result;
2637   }
2638   return {};
2639 }
2640 
trackExpressionValue(const ExplodedNode * InputNode,const Expr * E,PathSensitiveBugReport & Report,TrackingOptions Opts)2641 bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
2642                                        const Expr *E,
2643 
2644                                        PathSensitiveBugReport &Report,
2645                                        TrackingOptions Opts) {
2646   return Tracker::create(Report)
2647       ->track(E, InputNode, Opts)
2648       .FoundSomethingToTrack;
2649 }
2650 
trackStoredValue(SVal V,const MemRegion * R,PathSensitiveBugReport & Report,TrackingOptions Opts,const StackFrameContext * Origin)2651 void bugreporter::trackStoredValue(SVal V, const MemRegion *R,
2652                                    PathSensitiveBugReport &Report,
2653                                    TrackingOptions Opts,
2654                                    const StackFrameContext *Origin) {
2655   Tracker::create(Report)->track(V, R, Opts, Origin);
2656 }
2657 
2658 //===----------------------------------------------------------------------===//
2659 // Implementation of NulReceiverBRVisitor.
2660 //===----------------------------------------------------------------------===//
2661 
getNilReceiver(const Stmt * S,const ExplodedNode * N)2662 const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S,
2663                                                  const ExplodedNode *N) {
2664   const auto *ME = dyn_cast<ObjCMessageExpr>(S);
2665   if (!ME)
2666     return nullptr;
2667   if (const Expr *Receiver = ME->getInstanceReceiver()) {
2668     ProgramStateRef state = N->getState();
2669     SVal V = N->getSVal(Receiver);
2670     if (state->isNull(V).isConstrainedTrue())
2671       return Receiver;
2672   }
2673   return nullptr;
2674 }
2675 
2676 PathDiagnosticPieceRef
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)2677 NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
2678                                 PathSensitiveBugReport &BR) {
2679   std::optional<PreStmt> P = N->getLocationAs<PreStmt>();
2680   if (!P)
2681     return nullptr;
2682 
2683   const Stmt *S = P->getStmt();
2684   const Expr *Receiver = getNilReceiver(S, N);
2685   if (!Receiver)
2686     return nullptr;
2687 
2688   llvm::SmallString<256> Buf;
2689   llvm::raw_svector_ostream OS(Buf);
2690 
2691   if (const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
2692     OS << "'";
2693     ME->getSelector().print(OS);
2694     OS << "' not called";
2695   }
2696   else {
2697     OS << "No method is called";
2698   }
2699   OS << " because the receiver is nil";
2700 
2701   // The receiver was nil, and hence the method was skipped.
2702   // Register a BugReporterVisitor to issue a message telling us how
2703   // the receiver was null.
2704   bugreporter::trackExpressionValue(N, Receiver, BR,
2705                                     {bugreporter::TrackingKind::Thorough,
2706                                      /*EnableNullFPSuppression*/ false});
2707   // Issue a message saying that the method was skipped.
2708   PathDiagnosticLocation L(Receiver, BRC.getSourceManager(),
2709                                      N->getLocationContext());
2710   return std::make_shared<PathDiagnosticEventPiece>(L, OS.str());
2711 }
2712 
2713 //===----------------------------------------------------------------------===//
2714 // Visitor that tries to report interesting diagnostics from conditions.
2715 //===----------------------------------------------------------------------===//
2716 
2717 /// Return the tag associated with this visitor.  This tag will be used
2718 /// to make all PathDiagnosticPieces created by this visitor.
getTag()2719 const char *ConditionBRVisitor::getTag() { return "ConditionBRVisitor"; }
2720 
2721 PathDiagnosticPieceRef
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)2722 ConditionBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
2723                               PathSensitiveBugReport &BR) {
2724   auto piece = VisitNodeImpl(N, BRC, BR);
2725   if (piece) {
2726     piece->setTag(getTag());
2727     if (auto *ev = dyn_cast<PathDiagnosticEventPiece>(piece.get()))
2728       ev->setPrunable(true, /* override */ false);
2729   }
2730   return piece;
2731 }
2732 
2733 PathDiagnosticPieceRef
VisitNodeImpl(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)2734 ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
2735                                   BugReporterContext &BRC,
2736                                   PathSensitiveBugReport &BR) {
2737   ProgramPoint ProgPoint = N->getLocation();
2738   const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
2739       ExprEngine::getEagerlyAssumeBifurcationTags();
2740 
2741   // If an assumption was made on a branch, it should be caught
2742   // here by looking at the state transition.
2743   if (std::optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
2744     const CFGBlock *SrcBlock = BE->getSrc();
2745     if (const Stmt *Term = SrcBlock->getTerminatorStmt()) {
2746       // If the tag of the previous node is 'Eagerly Assume...' the current
2747       // 'BlockEdge' has the same constraint information. We do not want to
2748       // report the value as it is just an assumption on the predecessor node
2749       // which will be caught in the next VisitNode() iteration as a 'PostStmt'.
2750       const ProgramPointTag *PreviousNodeTag =
2751           N->getFirstPred()->getLocation().getTag();
2752       if (PreviousNodeTag == Tags.first || PreviousNodeTag == Tags.second)
2753         return nullptr;
2754 
2755       return VisitTerminator(Term, N, SrcBlock, BE->getDst(), BR, BRC);
2756     }
2757     return nullptr;
2758   }
2759 
2760   if (std::optional<PostStmt> PS = ProgPoint.getAs<PostStmt>()) {
2761     const ProgramPointTag *CurrentNodeTag = PS->getTag();
2762     if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
2763       return nullptr;
2764 
2765     bool TookTrue = CurrentNodeTag == Tags.first;
2766     return VisitTrueTest(cast<Expr>(PS->getStmt()), BRC, BR, N, TookTrue);
2767   }
2768 
2769   return nullptr;
2770 }
2771 
VisitTerminator(const Stmt * Term,const ExplodedNode * N,const CFGBlock * srcBlk,const CFGBlock * dstBlk,PathSensitiveBugReport & R,BugReporterContext & BRC)2772 PathDiagnosticPieceRef ConditionBRVisitor::VisitTerminator(
2773     const Stmt *Term, const ExplodedNode *N, const CFGBlock *srcBlk,
2774     const CFGBlock *dstBlk, PathSensitiveBugReport &R,
2775     BugReporterContext &BRC) {
2776   const Expr *Cond = nullptr;
2777 
2778   // In the code below, Term is a CFG terminator and Cond is a branch condition
2779   // expression upon which the decision is made on this terminator.
2780   //
2781   // For example, in "if (x == 0)", the "if (x == 0)" statement is a terminator,
2782   // and "x == 0" is the respective condition.
2783   //
2784   // Another example: in "if (x && y)", we've got two terminators and two
2785   // conditions due to short-circuit nature of operator "&&":
2786   // 1. The "if (x && y)" statement is a terminator,
2787   //    and "y" is the respective condition.
2788   // 2. Also "x && ..." is another terminator,
2789   //    and "x" is its condition.
2790 
2791   switch (Term->getStmtClass()) {
2792   // FIXME: Stmt::SwitchStmtClass is worth handling, however it is a bit
2793   // more tricky because there are more than two branches to account for.
2794   default:
2795     return nullptr;
2796   case Stmt::IfStmtClass: {
2797     const auto *IfStatement = cast<IfStmt>(Term);
2798     // Handle if consteval which doesn't have a traditional condition.
2799     if (IfStatement->isConsteval())
2800       return nullptr;
2801     Cond = IfStatement->getCond();
2802     break;
2803   }
2804   case Stmt::ConditionalOperatorClass:
2805     Cond = cast<ConditionalOperator>(Term)->getCond();
2806     break;
2807   case Stmt::BinaryOperatorClass:
2808     // When we encounter a logical operator (&& or ||) as a CFG terminator,
2809     // then the condition is actually its LHS; otherwise, we'd encounter
2810     // the parent, such as if-statement, as a terminator.
2811     const auto *BO = cast<BinaryOperator>(Term);
2812     assert(BO->isLogicalOp() &&
2813            "CFG terminator is not a short-circuit operator!");
2814     Cond = BO->getLHS();
2815     break;
2816   }
2817 
2818   Cond = Cond->IgnoreParens();
2819 
2820   // However, when we encounter a logical operator as a branch condition,
2821   // then the condition is actually its RHS, because LHS would be
2822   // the condition for the logical operator terminator.
2823   while (const auto *InnerBO = dyn_cast<BinaryOperator>(Cond)) {
2824     if (!InnerBO->isLogicalOp())
2825       break;
2826     Cond = InnerBO->getRHS()->IgnoreParens();
2827   }
2828 
2829   assert(Cond);
2830   assert(srcBlk->succ_size() == 2);
2831   const bool TookTrue = *(srcBlk->succ_begin()) == dstBlk;
2832   return VisitTrueTest(Cond, BRC, R, N, TookTrue);
2833 }
2834 
2835 PathDiagnosticPieceRef
VisitTrueTest(const Expr * Cond,BugReporterContext & BRC,PathSensitiveBugReport & R,const ExplodedNode * N,bool TookTrue)2836 ConditionBRVisitor::VisitTrueTest(const Expr *Cond, BugReporterContext &BRC,
2837                                   PathSensitiveBugReport &R,
2838                                   const ExplodedNode *N, bool TookTrue) {
2839   ProgramStateRef CurrentState = N->getState();
2840   ProgramStateRef PrevState = N->getFirstPred()->getState();
2841   const LocationContext *LCtx = N->getLocationContext();
2842 
2843   // If the constraint information is changed between the current and the
2844   // previous program state we assuming the newly seen constraint information.
2845   // If we cannot evaluate the condition (and the constraints are the same)
2846   // the analyzer has no information about the value and just assuming it.
2847   // FIXME: This logic is not entirely correct, because e.g. in code like
2848   //   void f(unsigned arg) {
2849   //     if (arg >= 0) {
2850   //       // ...
2851   //     }
2852   //   }
2853   // it will say that the "arg >= 0" check is _assuming_ something new because
2854   // the constraint that "$arg >= 0" is 1 was added to the list of known
2855   // constraints. However, the unsigned value is always >= 0 so semantically
2856   // this is not a "real" assumption.
2857   bool IsAssuming =
2858       !BRC.getStateManager().haveEqualConstraints(CurrentState, PrevState) ||
2859       CurrentState->getSVal(Cond, LCtx).isUnknownOrUndef();
2860 
2861   // These will be modified in code below, but we need to preserve the original
2862   //  values in case we want to throw the generic message.
2863   const Expr *CondTmp = Cond;
2864   bool TookTrueTmp = TookTrue;
2865 
2866   while (true) {
2867     CondTmp = CondTmp->IgnoreParenCasts();
2868     switch (CondTmp->getStmtClass()) {
2869       default:
2870         break;
2871       case Stmt::BinaryOperatorClass:
2872         if (auto P = VisitTrueTest(Cond, cast<BinaryOperator>(CondTmp),
2873                                    BRC, R, N, TookTrueTmp, IsAssuming))
2874           return P;
2875         break;
2876       case Stmt::DeclRefExprClass:
2877         if (auto P = VisitTrueTest(Cond, cast<DeclRefExpr>(CondTmp),
2878                                    BRC, R, N, TookTrueTmp, IsAssuming))
2879           return P;
2880         break;
2881       case Stmt::MemberExprClass:
2882         if (auto P = VisitTrueTest(Cond, cast<MemberExpr>(CondTmp),
2883                                    BRC, R, N, TookTrueTmp, IsAssuming))
2884           return P;
2885         break;
2886       case Stmt::UnaryOperatorClass: {
2887         const auto *UO = cast<UnaryOperator>(CondTmp);
2888         if (UO->getOpcode() == UO_LNot) {
2889           TookTrueTmp = !TookTrueTmp;
2890           CondTmp = UO->getSubExpr();
2891           continue;
2892         }
2893         break;
2894       }
2895     }
2896     break;
2897   }
2898 
2899   // Condition too complex to explain? Just say something so that the user
2900   // knew we've made some path decision at this point.
2901   // If it is too complex and we know the evaluation of the condition do not
2902   // repeat the note from 'BugReporter.cpp'
2903   if (!IsAssuming)
2904     return nullptr;
2905 
2906   PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
2907   if (!Loc.isValid() || !Loc.asLocation().isValid())
2908     return nullptr;
2909 
2910   return std::make_shared<PathDiagnosticEventPiece>(
2911       Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
2912 }
2913 
patternMatch(const Expr * Ex,const Expr * ParentEx,raw_ostream & Out,BugReporterContext & BRC,PathSensitiveBugReport & report,const ExplodedNode * N,std::optional<bool> & prunable,bool IsSameFieldName)2914 bool ConditionBRVisitor::patternMatch(const Expr *Ex, const Expr *ParentEx,
2915                                       raw_ostream &Out, BugReporterContext &BRC,
2916                                       PathSensitiveBugReport &report,
2917                                       const ExplodedNode *N,
2918                                       std::optional<bool> &prunable,
2919                                       bool IsSameFieldName) {
2920   const Expr *OriginalExpr = Ex;
2921   Ex = Ex->IgnoreParenCasts();
2922 
2923   if (isa<GNUNullExpr, ObjCBoolLiteralExpr, CXXBoolLiteralExpr, IntegerLiteral,
2924           FloatingLiteral>(Ex)) {
2925     // Use heuristics to determine if the expression is a macro
2926     // expanding to a literal and if so, use the macro's name.
2927     SourceLocation BeginLoc = OriginalExpr->getBeginLoc();
2928     SourceLocation EndLoc = OriginalExpr->getEndLoc();
2929     if (BeginLoc.isMacroID() && EndLoc.isMacroID()) {
2930       const SourceManager &SM = BRC.getSourceManager();
2931       const LangOptions &LO = BRC.getASTContext().getLangOpts();
2932       if (Lexer::isAtStartOfMacroExpansion(BeginLoc, SM, LO) &&
2933           Lexer::isAtEndOfMacroExpansion(EndLoc, SM, LO)) {
2934         CharSourceRange R = Lexer::getAsCharRange({BeginLoc, EndLoc}, SM, LO);
2935         Out << Lexer::getSourceText(R, SM, LO);
2936         return false;
2937       }
2938     }
2939   }
2940 
2941   if (const auto *DR = dyn_cast<DeclRefExpr>(Ex)) {
2942     const bool quotes = isa<VarDecl>(DR->getDecl());
2943     if (quotes) {
2944       Out << '\'';
2945       const LocationContext *LCtx = N->getLocationContext();
2946       const ProgramState *state = N->getState().get();
2947       if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()),
2948                                                 LCtx).getAsRegion()) {
2949         if (report.isInteresting(R))
2950           prunable = false;
2951         else {
2952           const ProgramState *state = N->getState().get();
2953           SVal V = state->getSVal(R);
2954           if (report.isInteresting(V))
2955             prunable = false;
2956         }
2957       }
2958     }
2959     Out << DR->getDecl()->getDeclName().getAsString();
2960     if (quotes)
2961       Out << '\'';
2962     return quotes;
2963   }
2964 
2965   if (const auto *IL = dyn_cast<IntegerLiteral>(Ex)) {
2966     QualType OriginalTy = OriginalExpr->getType();
2967     if (OriginalTy->isPointerType()) {
2968       if (IL->getValue() == 0) {
2969         Out << "null";
2970         return false;
2971       }
2972     }
2973     else if (OriginalTy->isObjCObjectPointerType()) {
2974       if (IL->getValue() == 0) {
2975         Out << "nil";
2976         return false;
2977       }
2978     }
2979 
2980     Out << IL->getValue();
2981     return false;
2982   }
2983 
2984   if (const auto *ME = dyn_cast<MemberExpr>(Ex)) {
2985     if (!IsSameFieldName)
2986       Out << "field '" << ME->getMemberDecl()->getName() << '\'';
2987     else
2988       Out << '\''
2989           << Lexer::getSourceText(
2990                  CharSourceRange::getTokenRange(Ex->getSourceRange()),
2991                  BRC.getSourceManager(), BRC.getASTContext().getLangOpts(),
2992                  nullptr)
2993           << '\'';
2994   }
2995 
2996   return false;
2997 }
2998 
VisitTrueTest(const Expr * Cond,const BinaryOperator * BExpr,BugReporterContext & BRC,PathSensitiveBugReport & R,const ExplodedNode * N,bool TookTrue,bool IsAssuming)2999 PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
3000     const Expr *Cond, const BinaryOperator *BExpr, BugReporterContext &BRC,
3001     PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue,
3002     bool IsAssuming) {
3003   bool shouldInvert = false;
3004   std::optional<bool> shouldPrune;
3005 
3006   // Check if the field name of the MemberExprs is ambiguous. Example:
3007   // " 'a.d' is equal to 'h.d' " in 'test/Analysis/null-deref-path-notes.cpp'.
3008   bool IsSameFieldName = false;
3009   const auto *LhsME = dyn_cast<MemberExpr>(BExpr->getLHS()->IgnoreParenCasts());
3010   const auto *RhsME = dyn_cast<MemberExpr>(BExpr->getRHS()->IgnoreParenCasts());
3011 
3012   if (LhsME && RhsME)
3013     IsSameFieldName =
3014         LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
3015 
3016   SmallString<128> LhsString, RhsString;
3017   {
3018     llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
3019     const bool isVarLHS = patternMatch(BExpr->getLHS(), BExpr, OutLHS, BRC, R,
3020                                        N, shouldPrune, IsSameFieldName);
3021     const bool isVarRHS = patternMatch(BExpr->getRHS(), BExpr, OutRHS, BRC, R,
3022                                        N, shouldPrune, IsSameFieldName);
3023 
3024     shouldInvert = !isVarLHS && isVarRHS;
3025   }
3026 
3027   BinaryOperator::Opcode Op = BExpr->getOpcode();
3028 
3029   if (BinaryOperator::isAssignmentOp(Op)) {
3030     // For assignment operators, all that we care about is that the LHS
3031     // evaluates to "true" or "false".
3032     return VisitConditionVariable(LhsString, BExpr->getLHS(), BRC, R, N,
3033                                   TookTrue);
3034   }
3035 
3036   // For non-assignment operations, we require that we can understand
3037   // both the LHS and RHS.
3038   if (LhsString.empty() || RhsString.empty() ||
3039       !BinaryOperator::isComparisonOp(Op) || Op == BO_Cmp)
3040     return nullptr;
3041 
3042   // Should we invert the strings if the LHS is not a variable name?
3043   SmallString<256> buf;
3044   llvm::raw_svector_ostream Out(buf);
3045   Out << (IsAssuming ? "Assuming " : "")
3046       << (shouldInvert ? RhsString : LhsString) << " is ";
3047 
3048   // Do we need to invert the opcode?
3049   if (shouldInvert)
3050     switch (Op) {
3051       default: break;
3052       case BO_LT: Op = BO_GT; break;
3053       case BO_GT: Op = BO_LT; break;
3054       case BO_LE: Op = BO_GE; break;
3055       case BO_GE: Op = BO_LE; break;
3056     }
3057 
3058   if (!TookTrue)
3059     switch (Op) {
3060       case BO_EQ: Op = BO_NE; break;
3061       case BO_NE: Op = BO_EQ; break;
3062       case BO_LT: Op = BO_GE; break;
3063       case BO_GT: Op = BO_LE; break;
3064       case BO_LE: Op = BO_GT; break;
3065       case BO_GE: Op = BO_LT; break;
3066       default:
3067         return nullptr;
3068     }
3069 
3070   switch (Op) {
3071     case BO_EQ:
3072       Out << "equal to ";
3073       break;
3074     case BO_NE:
3075       Out << "not equal to ";
3076       break;
3077     default:
3078       Out << BinaryOperator::getOpcodeStr(Op) << ' ';
3079       break;
3080   }
3081 
3082   Out << (shouldInvert ? LhsString : RhsString);
3083   const LocationContext *LCtx = N->getLocationContext();
3084   const SourceManager &SM = BRC.getSourceManager();
3085 
3086   if (isVarAnInterestingCondition(BExpr->getLHS(), N, &R) ||
3087       isVarAnInterestingCondition(BExpr->getRHS(), N, &R))
3088     Out << WillBeUsedForACondition;
3089 
3090   // Convert 'field ...' to 'Field ...' if it is a MemberExpr.
3091   std::string Message = std::string(Out.str());
3092   Message[0] = toupper(Message[0]);
3093 
3094   // If we know the value create a pop-up note to the value part of 'BExpr'.
3095   if (!IsAssuming) {
3096     PathDiagnosticLocation Loc;
3097     if (!shouldInvert) {
3098       if (LhsME && LhsME->getMemberLoc().isValid())
3099         Loc = PathDiagnosticLocation(LhsME->getMemberLoc(), SM);
3100       else
3101         Loc = PathDiagnosticLocation(BExpr->getLHS(), SM, LCtx);
3102     } else {
3103       if (RhsME && RhsME->getMemberLoc().isValid())
3104         Loc = PathDiagnosticLocation(RhsME->getMemberLoc(), SM);
3105       else
3106         Loc = PathDiagnosticLocation(BExpr->getRHS(), SM, LCtx);
3107     }
3108 
3109     return std::make_shared<PathDiagnosticPopUpPiece>(Loc, Message);
3110   }
3111 
3112   PathDiagnosticLocation Loc(Cond, SM, LCtx);
3113   auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Message);
3114   if (shouldPrune)
3115     event->setPrunable(*shouldPrune);
3116   return event;
3117 }
3118 
VisitConditionVariable(StringRef LhsString,const Expr * CondVarExpr,BugReporterContext & BRC,PathSensitiveBugReport & report,const ExplodedNode * N,bool TookTrue)3119 PathDiagnosticPieceRef ConditionBRVisitor::VisitConditionVariable(
3120     StringRef LhsString, const Expr *CondVarExpr, BugReporterContext &BRC,
3121     PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue) {
3122   // FIXME: If there's already a constraint tracker for this variable,
3123   // we shouldn't emit anything here (c.f. the double note in
3124   // test/Analysis/inlining/path-notes.c)
3125   SmallString<256> buf;
3126   llvm::raw_svector_ostream Out(buf);
3127   Out << "Assuming " << LhsString << " is ";
3128 
3129   if (!printValue(CondVarExpr, Out, N, TookTrue, /*IsAssuming=*/true))
3130     return nullptr;
3131 
3132   const LocationContext *LCtx = N->getLocationContext();
3133   PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx);
3134 
3135   if (isVarAnInterestingCondition(CondVarExpr, N, &report))
3136     Out << WillBeUsedForACondition;
3137 
3138   auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Out.str());
3139 
3140   if (isInterestingExpr(CondVarExpr, N, &report))
3141     event->setPrunable(false);
3142 
3143   return event;
3144 }
3145 
VisitTrueTest(const Expr * Cond,const DeclRefExpr * DRE,BugReporterContext & BRC,PathSensitiveBugReport & report,const ExplodedNode * N,bool TookTrue,bool IsAssuming)3146 PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
3147     const Expr *Cond, const DeclRefExpr *DRE, BugReporterContext &BRC,
3148     PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue,
3149     bool IsAssuming) {
3150   const auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
3151   if (!VD)
3152     return nullptr;
3153 
3154   SmallString<256> Buf;
3155   llvm::raw_svector_ostream Out(Buf);
3156 
3157   Out << (IsAssuming ? "Assuming '" : "'") << VD->getDeclName() << "' is ";
3158 
3159   if (!printValue(DRE, Out, N, TookTrue, IsAssuming))
3160     return nullptr;
3161 
3162   const LocationContext *LCtx = N->getLocationContext();
3163 
3164   if (isVarAnInterestingCondition(DRE, N, &report))
3165     Out << WillBeUsedForACondition;
3166 
3167   // If we know the value create a pop-up note to the 'DRE'.
3168   if (!IsAssuming) {
3169     PathDiagnosticLocation Loc(DRE, BRC.getSourceManager(), LCtx);
3170     return std::make_shared<PathDiagnosticPopUpPiece>(Loc, Out.str());
3171   }
3172 
3173   PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
3174   auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Out.str());
3175 
3176   if (isInterestingExpr(DRE, N, &report))
3177     event->setPrunable(false);
3178 
3179   return std::move(event);
3180 }
3181 
VisitTrueTest(const Expr * Cond,const MemberExpr * ME,BugReporterContext & BRC,PathSensitiveBugReport & report,const ExplodedNode * N,bool TookTrue,bool IsAssuming)3182 PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
3183     const Expr *Cond, const MemberExpr *ME, BugReporterContext &BRC,
3184     PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue,
3185     bool IsAssuming) {
3186   SmallString<256> Buf;
3187   llvm::raw_svector_ostream Out(Buf);
3188 
3189   Out << (IsAssuming ? "Assuming field '" : "Field '")
3190       << ME->getMemberDecl()->getName() << "' is ";
3191 
3192   if (!printValue(ME, Out, N, TookTrue, IsAssuming))
3193     return nullptr;
3194 
3195   const LocationContext *LCtx = N->getLocationContext();
3196   PathDiagnosticLocation Loc;
3197 
3198   // If we know the value create a pop-up note to the member of the MemberExpr.
3199   if (!IsAssuming && ME->getMemberLoc().isValid())
3200     Loc = PathDiagnosticLocation(ME->getMemberLoc(), BRC.getSourceManager());
3201   else
3202     Loc = PathDiagnosticLocation(Cond, BRC.getSourceManager(), LCtx);
3203 
3204   if (!Loc.isValid() || !Loc.asLocation().isValid())
3205     return nullptr;
3206 
3207   if (isVarAnInterestingCondition(ME, N, &report))
3208     Out << WillBeUsedForACondition;
3209 
3210   // If we know the value create a pop-up note.
3211   if (!IsAssuming)
3212     return std::make_shared<PathDiagnosticPopUpPiece>(Loc, Out.str());
3213 
3214   auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Out.str());
3215   if (isInterestingExpr(ME, N, &report))
3216     event->setPrunable(false);
3217   return event;
3218 }
3219 
printValue(const Expr * CondVarExpr,raw_ostream & Out,const ExplodedNode * N,bool TookTrue,bool IsAssuming)3220 bool ConditionBRVisitor::printValue(const Expr *CondVarExpr, raw_ostream &Out,
3221                                     const ExplodedNode *N, bool TookTrue,
3222                                     bool IsAssuming) {
3223   QualType Ty = CondVarExpr->getType();
3224 
3225   if (Ty->isPointerType()) {
3226     Out << (TookTrue ? "non-null" : "null");
3227     return true;
3228   }
3229 
3230   if (Ty->isObjCObjectPointerType()) {
3231     Out << (TookTrue ? "non-nil" : "nil");
3232     return true;
3233   }
3234 
3235   if (!Ty->isIntegralOrEnumerationType())
3236     return false;
3237 
3238   std::optional<const llvm::APSInt *> IntValue;
3239   if (!IsAssuming)
3240     IntValue = getConcreteIntegerValue(CondVarExpr, N);
3241 
3242   if (IsAssuming || !IntValue) {
3243     if (Ty->isBooleanType())
3244       Out << (TookTrue ? "true" : "false");
3245     else
3246       Out << (TookTrue ? "not equal to 0" : "0");
3247   } else {
3248     if (Ty->isBooleanType())
3249       Out << ((*IntValue)->getBoolValue() ? "true" : "false");
3250     else
3251       Out << **IntValue;
3252   }
3253 
3254   return true;
3255 }
3256 
3257 constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;
3258 constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;
3259 
isPieceMessageGeneric(const PathDiagnosticPiece * Piece)3260 bool ConditionBRVisitor::isPieceMessageGeneric(
3261     const PathDiagnosticPiece *Piece) {
3262   return Piece->getString() == GenericTrueMessage ||
3263          Piece->getString() == GenericFalseMessage;
3264 }
3265 
3266 //===----------------------------------------------------------------------===//
3267 // Implementation of LikelyFalsePositiveSuppressionBRVisitor.
3268 //===----------------------------------------------------------------------===//
3269 
finalizeVisitor(BugReporterContext & BRC,const ExplodedNode * N,PathSensitiveBugReport & BR)3270 void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
3271     BugReporterContext &BRC, const ExplodedNode *N,
3272     PathSensitiveBugReport &BR) {
3273   // Here we suppress false positives coming from system headers. This list is
3274   // based on known issues.
3275   const AnalyzerOptions &Options = BRC.getAnalyzerOptions();
3276   const Decl *D = N->getLocationContext()->getDecl();
3277 
3278   if (AnalysisDeclContext::isInStdNamespace(D)) {
3279     // Skip reports within the 'std' namespace. Although these can sometimes be
3280     // the user's fault, we currently don't report them very well, and
3281     // Note that this will not help for any other data structure libraries, like
3282     // TR1, Boost, or llvm/ADT.
3283     if (Options.ShouldSuppressFromCXXStandardLibrary) {
3284       BR.markInvalid(getTag(), nullptr);
3285       return;
3286     } else {
3287       // If the complete 'std' suppression is not enabled, suppress reports
3288       // from the 'std' namespace that are known to produce false positives.
3289 
3290       // The analyzer issues a false use-after-free when std::list::pop_front
3291       // or std::list::pop_back are called multiple times because we cannot
3292       // reason about the internal invariants of the data structure.
3293       if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3294         const CXXRecordDecl *CD = MD->getParent();
3295         if (CD->getName() == "list") {
3296           BR.markInvalid(getTag(), nullptr);
3297           return;
3298         }
3299       }
3300 
3301       // The analyzer issues a false positive when the constructor of
3302       // std::__independent_bits_engine from algorithms is used.
3303       if (const auto *MD = dyn_cast<CXXConstructorDecl>(D)) {
3304         const CXXRecordDecl *CD = MD->getParent();
3305         if (CD->getName() == "__independent_bits_engine") {
3306           BR.markInvalid(getTag(), nullptr);
3307           return;
3308         }
3309       }
3310 
3311       for (const LocationContext *LCtx = N->getLocationContext(); LCtx;
3312            LCtx = LCtx->getParent()) {
3313         const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
3314         if (!MD)
3315           continue;
3316 
3317         const CXXRecordDecl *CD = MD->getParent();
3318         // The analyzer issues a false positive on
3319         //   std::basic_string<uint8_t> v; v.push_back(1);
3320         // and
3321         //   std::u16string s; s += u'a';
3322         // because we cannot reason about the internal invariants of the
3323         // data structure.
3324         if (CD->getName() == "basic_string") {
3325           BR.markInvalid(getTag(), nullptr);
3326           return;
3327         }
3328 
3329         // The analyzer issues a false positive on
3330         //    std::shared_ptr<int> p(new int(1)); p = nullptr;
3331         // because it does not reason properly about temporary destructors.
3332         if (CD->getName() == "shared_ptr") {
3333           BR.markInvalid(getTag(), nullptr);
3334           return;
3335         }
3336       }
3337     }
3338   }
3339 
3340   // Skip reports within the sys/queue.h macros as we do not have the ability to
3341   // reason about data structure shapes.
3342   const SourceManager &SM = BRC.getSourceManager();
3343   FullSourceLoc Loc = BR.getLocation().asLocation();
3344   while (Loc.isMacroID()) {
3345     Loc = Loc.getSpellingLoc();
3346     if (SM.getFilename(Loc).ends_with("sys/queue.h")) {
3347       BR.markInvalid(getTag(), nullptr);
3348       return;
3349     }
3350   }
3351 }
3352 
3353 //===----------------------------------------------------------------------===//
3354 // Implementation of UndefOrNullArgVisitor.
3355 //===----------------------------------------------------------------------===//
3356 
3357 PathDiagnosticPieceRef
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)3358 UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
3359                                  PathSensitiveBugReport &BR) {
3360   ProgramStateRef State = N->getState();
3361   ProgramPoint ProgLoc = N->getLocation();
3362 
3363   // We are only interested in visiting CallEnter nodes.
3364   std::optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>();
3365   if (!CEnter)
3366     return nullptr;
3367 
3368   // Check if one of the arguments is the region the visitor is tracking.
3369   CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
3370   CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State);
3371   unsigned Idx = 0;
3372   ArrayRef<ParmVarDecl *> parms = Call->parameters();
3373 
3374   for (const auto ParamDecl : parms) {
3375     const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion();
3376     ++Idx;
3377 
3378     // Are we tracking the argument or its subregion?
3379     if ( !ArgReg || !R->isSubRegionOf(ArgReg->StripCasts()))
3380       continue;
3381 
3382     // Check the function parameter type.
3383     assert(ParamDecl && "Formal parameter has no decl?");
3384     QualType T = ParamDecl->getType();
3385 
3386     if (!(T->isAnyPointerType() || T->isReferenceType())) {
3387       // Function can only change the value passed in by address.
3388       continue;
3389     }
3390 
3391     // If it is a const pointer value, the function does not intend to
3392     // change the value.
3393     if (T->getPointeeType().isConstQualified())
3394       continue;
3395 
3396     // Mark the call site (LocationContext) as interesting if the value of the
3397     // argument is undefined or '0'/'NULL'.
3398     SVal BoundVal = State->getSVal(R);
3399     if (BoundVal.isUndef() || BoundVal.isZeroConstant()) {
3400       BR.markInteresting(CEnter->getCalleeContext());
3401       return nullptr;
3402     }
3403   }
3404   return nullptr;
3405 }
3406 
3407 //===----------------------------------------------------------------------===//
3408 // Implementation of TagVisitor.
3409 //===----------------------------------------------------------------------===//
3410 
3411 int NoteTag::Kind = 0;
3412 
Profile(llvm::FoldingSetNodeID & ID) const3413 void TagVisitor::Profile(llvm::FoldingSetNodeID &ID) const {
3414   static int Tag = 0;
3415   ID.AddPointer(&Tag);
3416 }
3417 
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & R)3418 PathDiagnosticPieceRef TagVisitor::VisitNode(const ExplodedNode *N,
3419                                              BugReporterContext &BRC,
3420                                              PathSensitiveBugReport &R) {
3421   ProgramPoint PP = N->getLocation();
3422   const NoteTag *T = dyn_cast_or_null<NoteTag>(PP.getTag());
3423   if (!T)
3424     return nullptr;
3425 
3426   if (std::optional<std::string> Msg = T->generateMessage(BRC, R)) {
3427     PathDiagnosticLocation Loc =
3428         PathDiagnosticLocation::create(PP, BRC.getSourceManager());
3429     auto Piece = std::make_shared<PathDiagnosticEventPiece>(Loc, *Msg);
3430     Piece->setPrunable(T->isPrunable());
3431     return Piece;
3432   }
3433 
3434   return nullptr;
3435 }
3436