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