1 //===- BugReporterVisitors.cpp - Helpers for reporting bugs ---------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines a set of BugReporter "visitors" which can be used to
10 // enhance the diagnostics reported for a bug.
12 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclBase.h"
18 #include "clang/AST/DeclCXX.h"
19 #include "clang/AST/Expr.h"
20 #include "clang/AST/ExprCXX.h"
21 #include "clang/AST/ExprObjC.h"
22 #include "clang/AST/Stmt.h"
23 #include "clang/AST/Type.h"
24 #include "clang/ASTMatchers/ASTMatchFinder.h"
25 #include "clang/Analysis/Analyses/Dominators.h"
26 #include "clang/Analysis/AnalysisDeclContext.h"
27 #include "clang/Analysis/CFG.h"
28 #include "clang/Analysis/CFGStmtMap.h"
29 #include "clang/Analysis/PathDiagnostic.h"
30 #include "clang/Analysis/ProgramPoint.h"
31 #include "clang/Basic/IdentifierTable.h"
32 #include "clang/Basic/LLVM.h"
33 #include "clang/Basic/SourceLocation.h"
34 #include "clang/Basic/SourceManager.h"
35 #include "clang/Lex/Lexer.h"
36 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
37 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
38 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
39 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
40 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
41 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
42 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
43 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
44 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
45 #include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h"
46 #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
47 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
48 #include "llvm/ADT/ArrayRef.h"
49 #include "llvm/ADT/STLExtras.h"
50 #include "llvm/ADT/SmallPtrSet.h"
51 #include "llvm/ADT/SmallString.h"
52 #include "llvm/ADT/SmallVector.h"
53 #include "llvm/ADT/StringExtras.h"
54 #include "llvm/ADT/StringRef.h"
55 #include "llvm/Support/Casting.h"
56 #include "llvm/Support/ErrorHandling.h"
57 #include "llvm/Support/raw_ostream.h"
65 using namespace clang
;
67 using namespace bugreporter
;
69 //===----------------------------------------------------------------------===//
71 //===----------------------------------------------------------------------===//
73 static const Expr
*peelOffPointerArithmetic(const BinaryOperator
*B
) {
74 if (B
->isAdditiveOp() && B
->getType()->isPointerType()) {
75 if (B
->getLHS()->getType()->isPointerType()) {
77 } else if (B
->getRHS()->getType()->isPointerType()) {
84 /// \return A subexpression of @c Ex which represents the
85 /// expression-of-interest.
86 static const Expr
*peelOffOuterExpr(const Expr
*Ex
, const ExplodedNode
*N
);
88 /// Given that expression S represents a pointer that would be dereferenced,
89 /// try to find a sub-expression from which the pointer came from.
90 /// This is used for tracking down origins of a null or undefined value:
91 /// "this is null because that is null because that is null" etc.
92 /// We wipe away field and element offsets because they merely add offsets.
93 /// We also wipe away all casts except lvalue-to-rvalue casts, because the
94 /// latter represent an actual pointer dereference; however, we remove
95 /// the final lvalue-to-rvalue cast before returning from this function
96 /// because it demonstrates more clearly from where the pointer rvalue was
98 /// x->y.z ==> x (lvalue)
99 /// foo()->y.z ==> foo() (rvalue)
100 const Expr
*bugreporter::getDerefExpr(const Stmt
*S
) {
101 const auto *E
= dyn_cast
<Expr
>(S
);
106 if (const auto *CE
= dyn_cast
<CastExpr
>(E
)) {
107 if (CE
->getCastKind() == CK_LValueToRValue
) {
108 // This cast represents the load we're looking for.
111 E
= CE
->getSubExpr();
112 } else if (const auto *B
= dyn_cast
<BinaryOperator
>(E
)) {
113 // Pointer arithmetic: '*(x + 2)' -> 'x') etc.
114 if (const Expr
*Inner
= peelOffPointerArithmetic(B
)) {
117 // Probably more arithmetic can be pattern-matched here,
118 // but for now give up.
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.
128 // Probably more arithmetic can be pattern-matched here,
129 // but for now give up.
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:
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.
143 if (ME
->getMemberDecl()->getType()->isReferenceType())
146 } else if (const auto *IvarRef
= dyn_cast
<ObjCIvarRefExpr
>(E
)) {
147 E
= IvarRef
->getBase();
148 } else if (const auto *AE
= dyn_cast
<ArraySubscriptExpr
>(E
)) {
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();
155 // Other arbitrary stuff.
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();
170 static const VarDecl
*getVarDeclForExpression(const Expr
*E
) {
171 if (const auto *DR
= dyn_cast
<DeclRefExpr
>(E
))
172 return dyn_cast
<VarDecl
>(DR
->getDecl());
176 static const MemRegion
*
177 getLocationRegionIfReference(const Expr
*E
, const ExplodedNode
*N
,
178 bool LookingForReference
= true) {
179 if (const auto *ME
= dyn_cast
<MemberExpr
>(E
)) {
180 // This handles null references from FieldRegions, for example:
181 // struct Wrapper { int &ref; };
182 // Wrapper w = { *(int *)0 };
184 const Expr
*Base
= ME
->getBase();
185 const VarDecl
*VD
= getVarDeclForExpression(Base
);
189 const auto *FD
= dyn_cast
<FieldDecl
>(ME
->getMemberDecl());
193 if (FD
->getType()->isReferenceType()) {
194 SVal StructSVal
= N
->getState()->getLValue(VD
, N
->getLocationContext());
195 return N
->getState()->getLValue(FD
, StructSVal
).getAsRegion();
200 const VarDecl
*VD
= getVarDeclForExpression(E
);
203 if (LookingForReference
&& !VD
->getType()->isReferenceType())
205 return N
->getState()->getLValue(VD
, N
->getLocationContext()).getAsRegion();
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.
216 static bool hasVisibleUpdate(const ExplodedNode
*LeftNode
, SVal LeftVal
,
217 const ExplodedNode
*RightNode
, SVal RightVal
) {
218 if (LeftVal
== RightVal
)
221 const auto LLCV
= LeftVal
.getAs
<nonloc::LazyCompoundVal
>();
225 const auto RLCV
= RightVal
.getAs
<nonloc::LazyCompoundVal
>();
229 return LLCV
->getRegion() == RLCV
->getRegion() &&
230 LLCV
->getStore() == LeftNode
->getState()->getStore() &&
231 RLCV
->getStore() == RightNode
->getState()->getStore();
234 static std::optional
<SVal
> getSValForVar(const Expr
*CondVarExpr
,
235 const ExplodedNode
*N
) {
236 ProgramStateRef State
= N
->getState();
237 const LocationContext
*LCtx
= N
->getLocationContext();
240 CondVarExpr
= CondVarExpr
->IgnoreImpCasts();
242 // The declaration of the value may rely on a pointer so take its l-value.
243 // FIXME: As seen in VisitCommonDeclRefExpr, sometimes DeclRefExpr may
244 // evaluate to a FieldRegion when it refers to a declaration of a lambda
245 // capture variable. We most likely need to duplicate that logic here.
246 if (const auto *DRE
= dyn_cast
<DeclRefExpr
>(CondVarExpr
))
247 if (const auto *VD
= dyn_cast
<VarDecl
>(DRE
->getDecl()))
248 return State
->getSVal(State
->getLValue(VD
, LCtx
));
250 if (const auto *ME
= dyn_cast
<MemberExpr
>(CondVarExpr
))
251 if (const auto *FD
= dyn_cast
<FieldDecl
>(ME
->getMemberDecl()))
252 if (auto FieldL
= State
->getSVal(ME
, LCtx
).getAs
<Loc
>())
253 return State
->getRawSVal(*FieldL
, FD
->getType());
258 static std::optional
<const llvm::APSInt
*>
259 getConcreteIntegerValue(const Expr
*CondVarExpr
, const ExplodedNode
*N
) {
261 if (std::optional
<SVal
> V
= getSValForVar(CondVarExpr
, N
))
262 if (auto CI
= V
->getAs
<nonloc::ConcreteInt
>())
263 return &CI
->getValue();
267 static bool isVarAnInterestingCondition(const Expr
*CondVarExpr
,
268 const ExplodedNode
*N
,
269 const PathSensitiveBugReport
*B
) {
270 // Even if this condition is marked as interesting, it isn't *that*
271 // interesting if it didn't happen in a nested stackframe, the user could just
272 // follow the arrows.
273 if (!B
->getErrorNode()->getStackFrame()->isParentOf(N
->getStackFrame()))
276 if (std::optional
<SVal
> V
= getSValForVar(CondVarExpr
, N
))
277 if (std::optional
<bugreporter::TrackingKind
> K
=
278 B
->getInterestingnessKind(*V
))
279 return *K
== bugreporter::TrackingKind::Condition
;
284 static bool isInterestingExpr(const Expr
*E
, const ExplodedNode
*N
,
285 const PathSensitiveBugReport
*B
) {
286 if (std::optional
<SVal
> V
= getSValForVar(E
, N
))
287 return B
->getInterestingnessKind(*V
).has_value();
291 /// \return name of the macro inside the location \p Loc.
292 static StringRef
getMacroName(SourceLocation Loc
,
293 BugReporterContext
&BRC
) {
294 return Lexer::getImmediateMacroName(
296 BRC
.getSourceManager(),
297 BRC
.getASTContext().getLangOpts());
300 /// \return Whether given spelling location corresponds to an expansion
301 /// of a function-like macro.
302 static bool isFunctionMacroExpansion(SourceLocation Loc
,
303 const SourceManager
&SM
) {
304 if (!Loc
.isMacroID())
306 while (SM
.isMacroArgExpansion(Loc
))
307 Loc
= SM
.getImmediateExpansionRange(Loc
).getBegin();
308 std::pair
<FileID
, unsigned> TLInfo
= SM
.getDecomposedLoc(Loc
);
309 SrcMgr::SLocEntry SE
= SM
.getSLocEntry(TLInfo
.first
);
310 const SrcMgr::ExpansionInfo
&EInfo
= SE
.getExpansion();
311 return EInfo
.isFunctionMacroExpansion();
314 /// \return Whether \c RegionOfInterest was modified at \p N,
315 /// where \p ValueAfter is \c RegionOfInterest's value at the end of the
317 static bool wasRegionOfInterestModifiedAt(const SubRegion
*RegionOfInterest
,
318 const ExplodedNode
*N
,
320 ProgramStateRef State
= N
->getState();
321 ProgramStateManager
&Mgr
= N
->getState()->getStateManager();
323 if (!N
->getLocationAs
<PostStore
>() && !N
->getLocationAs
<PostInitializer
>() &&
324 !N
->getLocationAs
<PostStmt
>())
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()))
334 // SVal after the state is possibly different.
335 SVal ValueAtN
= N
->getState()->getSVal(RegionOfInterest
);
336 if (!Mgr
.getSValBuilder()
337 .areEqual(State
, ValueAtN
, ValueAfter
)
338 .isConstrainedTrue() &&
339 (!ValueAtN
.isUndef() || !ValueAfter
.isUndef()))
345 //===----------------------------------------------------------------------===//
346 // Implementation of BugReporterVisitor.
347 //===----------------------------------------------------------------------===//
349 PathDiagnosticPieceRef
BugReporterVisitor::getEndPath(BugReporterContext
&,
350 const ExplodedNode
*,
351 PathSensitiveBugReport
&) {
355 void BugReporterVisitor::finalizeVisitor(BugReporterContext
&,
356 const ExplodedNode
*,
357 PathSensitiveBugReport
&) {}
359 PathDiagnosticPieceRef
360 BugReporterVisitor::getDefaultEndPath(const BugReporterContext
&BRC
,
361 const ExplodedNode
*EndPathNode
,
362 const PathSensitiveBugReport
&BR
) {
363 PathDiagnosticLocation L
= BR
.getLocation();
364 const auto &Ranges
= BR
.getRanges();
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
)
376 //===----------------------------------------------------------------------===//
377 // Implementation of NoStateChangeFuncVisitor.
378 //===----------------------------------------------------------------------===//
380 bool NoStateChangeFuncVisitor::isModifiedInFrame(const ExplodedNode
*N
) {
381 const LocationContext
*Ctx
= N
->getLocationContext();
382 const StackFrameContext
*SCtx
= Ctx
->getStackFrame();
383 if (!FramesModifyingCalculated
.count(SCtx
))
384 findModifyingFrames(N
);
385 return FramesModifying
.count(SCtx
);
388 void NoStateChangeFuncVisitor::markFrameAsModifying(
389 const StackFrameContext
*SCtx
) {
390 while (!SCtx
->inTopFrame()) {
391 auto p
= FramesModifying
.insert(SCtx
);
393 break; // Frame and all its parents already inserted.
395 SCtx
= SCtx
->getParent()->getStackFrame();
399 static const ExplodedNode
*getMatchingCallExitEnd(const ExplodedNode
*N
) {
400 assert(N
->getLocationAs
<CallEnter
>());
401 // The stackframe of the callee is only found in the nodes succeeding
402 // the CallEnter node. CallEnter's stack frame refers to the caller.
403 const StackFrameContext
*OrigSCtx
= N
->getFirstSucc()->getStackFrame();
405 // Similarly, the nodes preceding CallExitEnd refer to the callee's stack
407 auto IsMatchingCallExitEnd
= [OrigSCtx
](const ExplodedNode
*N
) {
408 return N
->getLocationAs
<CallExitEnd
>() &&
409 OrigSCtx
== N
->getFirstPred()->getStackFrame();
411 while (N
&& !IsMatchingCallExitEnd(N
)) {
412 assert(N
->succ_size() <= 1 &&
413 "This function is to be used on the trimmed ExplodedGraph!");
414 N
= N
->getFirstSucc();
419 void NoStateChangeFuncVisitor::findModifyingFrames(
420 const ExplodedNode
*const CallExitBeginN
) {
422 assert(CallExitBeginN
->getLocationAs
<CallExitBegin
>());
424 const StackFrameContext
*const OriginalSCtx
=
425 CallExitBeginN
->getLocationContext()->getStackFrame();
427 const ExplodedNode
*CurrCallExitBeginN
= CallExitBeginN
;
428 const StackFrameContext
*CurrentSCtx
= OriginalSCtx
;
430 for (const ExplodedNode
*CurrN
= CallExitBeginN
; CurrN
;
431 CurrN
= CurrN
->getFirstPred()) {
432 // Found a new inlined call.
433 if (CurrN
->getLocationAs
<CallExitBegin
>()) {
434 CurrCallExitBeginN
= CurrN
;
435 CurrentSCtx
= CurrN
->getStackFrame();
436 FramesModifyingCalculated
.insert(CurrentSCtx
);
437 // We won't see a change in between two identical exploded nodes: skip.
441 if (auto CE
= CurrN
->getLocationAs
<CallEnter
>()) {
442 if (const ExplodedNode
*CallExitEndN
= getMatchingCallExitEnd(CurrN
))
443 if (wasModifiedInFunction(CurrN
, CallExitEndN
))
444 markFrameAsModifying(CurrentSCtx
);
446 // We exited this inlined call, lets actualize the stack frame.
447 CurrentSCtx
= CurrN
->getStackFrame();
449 // Stop calculating at the current function, but always regard it as
450 // modifying, so we can avoid notes like this:
452 // F.field = 0; // note: 0 assigned to 'F.field'
453 // // note: returning without writing to 'F.field'
455 if (CE
->getCalleeContext() == OriginalSCtx
) {
456 markFrameAsModifying(CurrentSCtx
);
461 if (wasModifiedBeforeCallExit(CurrN
, CurrCallExitBeginN
))
462 markFrameAsModifying(CurrentSCtx
);
466 PathDiagnosticPieceRef
NoStateChangeFuncVisitor::VisitNode(
467 const ExplodedNode
*N
, BugReporterContext
&BR
, PathSensitiveBugReport
&R
) {
469 const LocationContext
*Ctx
= N
->getLocationContext();
470 const StackFrameContext
*SCtx
= Ctx
->getStackFrame();
471 ProgramStateRef State
= N
->getState();
472 auto CallExitLoc
= N
->getLocationAs
<CallExitBegin
>();
474 // No diagnostic if region was modified inside the frame.
475 if (!CallExitLoc
|| isModifiedInFrame(N
))
478 CallEventRef
<> Call
=
479 BR
.getStateManager().getCallEventManager().getCaller(SCtx
, State
);
481 // Optimistically suppress uninitialized value bugs that result
482 // from system headers having a chance to initialize the value
483 // but failing to do so. It's too unlikely a system header's fault.
484 // It's much more likely a situation in which the function has a failure
485 // mode that the user decided not to check. If we want to hunt such
486 // omitted checks, we should provide an explicit function-specific note
487 // describing the precondition under which the function isn't supposed to
488 // initialize its out-parameter, and additionally check that such
489 // precondition can actually be fulfilled on the current path.
490 if (Call
->isInSystemHeader()) {
491 // We make an exception for system header functions that have no branches.
492 // Such functions unconditionally fail to initialize the variable.
493 // If they call other functions that have more paths within them,
494 // this suppression would still apply when we visit these inner functions.
495 // One common example of a standard function that doesn't ever initialize
496 // its out parameter is operator placement new; it's up to the follow-up
497 // constructor (if any) to initialize the memory.
498 if (!N
->getStackFrame()->getCFG()->isLinear()) {
500 R
.markInvalid(&i
, nullptr);
505 if (const auto *MC
= dyn_cast
<ObjCMethodCall
>(Call
)) {
506 // If we failed to construct a piece for self, we still want to check
507 // whether the entity of interest is in a parameter.
508 if (PathDiagnosticPieceRef Piece
= maybeEmitNoteForObjCSelf(R
, *MC
, N
))
512 if (const auto *CCall
= dyn_cast
<CXXConstructorCall
>(Call
)) {
513 // Do not generate diagnostics for not modified parameters in
515 return maybeEmitNoteForCXXThis(R
, *CCall
, N
);
518 return maybeEmitNoteForParameters(R
, *Call
, N
);
521 //===----------------------------------------------------------------------===//
522 // Implementation of NoStoreFuncVisitor.
523 //===----------------------------------------------------------------------===//
526 /// Put a diagnostic on return statement of all inlined functions
527 /// for which the region of interest \p RegionOfInterest was passed into,
528 /// but not written inside, and it has caused an undefined read or a null
529 /// pointer dereference outside.
530 class NoStoreFuncVisitor final
: public NoStateChangeFuncVisitor
{
531 const SubRegion
*RegionOfInterest
;
532 MemRegionManager
&MmrMgr
;
533 const SourceManager
&SM
;
534 const PrintingPolicy
&PP
;
536 /// Recursion limit for dereferencing fields when looking for the
537 /// region of interest.
538 /// The limit of two indicates that we will dereference fields only once.
539 static const unsigned DEREFERENCE_LIMIT
= 2;
541 using RegionVector
= SmallVector
<const MemRegion
*, 5>;
544 NoStoreFuncVisitor(const SubRegion
*R
, bugreporter::TrackingKind TKind
)
545 : NoStateChangeFuncVisitor(TKind
), RegionOfInterest(R
),
546 MmrMgr(R
->getMemRegionManager()),
547 SM(MmrMgr
.getContext().getSourceManager()),
548 PP(MmrMgr
.getContext().getPrintingPolicy()) {}
550 void Profile(llvm::FoldingSetNodeID
&ID
) const override
{
553 ID
.AddPointer(RegionOfInterest
);
557 /// \return Whether \c RegionOfInterest was modified at \p CurrN compared to
558 /// the value it holds in \p CallExitBeginN.
559 bool wasModifiedBeforeCallExit(const ExplodedNode
*CurrN
,
560 const ExplodedNode
*CallExitBeginN
) override
;
562 /// Attempts to find the region of interest in a given record decl,
563 /// by either following the base classes or fields.
564 /// Dereferences fields up to a given recursion limit.
565 /// Note that \p Vec is passed by value, leading to quadratic copying cost,
566 /// but it's OK in practice since its length is limited to DEREFERENCE_LIMIT.
567 /// \return A chain fields leading to the region of interest or std::nullopt.
568 const std::optional
<RegionVector
>
569 findRegionOfInterestInRecord(const RecordDecl
*RD
, ProgramStateRef State
,
570 const MemRegion
*R
, const RegionVector
&Vec
= {},
573 // Region of interest corresponds to an IVar, exiting a method
574 // which could have written into that IVar, but did not.
575 PathDiagnosticPieceRef
maybeEmitNoteForObjCSelf(PathSensitiveBugReport
&R
,
576 const ObjCMethodCall
&Call
,
577 const ExplodedNode
*N
) final
;
579 PathDiagnosticPieceRef
maybeEmitNoteForCXXThis(PathSensitiveBugReport
&R
,
580 const CXXConstructorCall
&Call
,
581 const ExplodedNode
*N
) final
;
583 PathDiagnosticPieceRef
584 maybeEmitNoteForParameters(PathSensitiveBugReport
&R
, const CallEvent
&Call
,
585 const ExplodedNode
*N
) final
;
587 /// Consume the information on the no-store stack frame in order to
588 /// either emit a note or suppress the report enirely.
589 /// \return Diagnostics piece for region not modified in the current function,
590 /// if it decides to emit one.
591 PathDiagnosticPieceRef
592 maybeEmitNote(PathSensitiveBugReport
&R
, const CallEvent
&Call
,
593 const ExplodedNode
*N
, const RegionVector
&FieldChain
,
594 const MemRegion
*MatchedRegion
, StringRef FirstElement
,
595 bool FirstIsReferenceType
, unsigned IndirectionLevel
);
597 bool prettyPrintRegionName(const RegionVector
&FieldChain
,
598 const MemRegion
*MatchedRegion
,
599 StringRef FirstElement
, bool FirstIsReferenceType
,
600 unsigned IndirectionLevel
,
601 llvm::raw_svector_ostream
&os
);
603 StringRef
prettyPrintFirstElement(StringRef FirstElement
,
604 bool MoreItemsExpected
,
605 int IndirectionLevel
,
606 llvm::raw_svector_ostream
&os
);
610 /// \return Whether the method declaration \p Parent
611 /// syntactically has a binary operation writing into the ivar \p Ivar.
612 static bool potentiallyWritesIntoIvar(const Decl
*Parent
,
613 const ObjCIvarDecl
*Ivar
) {
614 using namespace ast_matchers
;
615 const char *IvarBind
= "Ivar";
616 if (!Parent
|| !Parent
->hasBody())
618 StatementMatcher WriteIntoIvarM
= binaryOperator(
619 hasOperatorName("="),
620 hasLHS(ignoringParenImpCasts(
621 objcIvarRefExpr(hasDeclaration(equalsNode(Ivar
))).bind(IvarBind
))));
622 StatementMatcher ParentM
= stmt(hasDescendant(WriteIntoIvarM
));
623 auto Matches
= match(ParentM
, *Parent
->getBody(), Parent
->getASTContext());
624 for (BoundNodes
&Match
: Matches
) {
625 auto IvarRef
= Match
.getNodeAs
<ObjCIvarRefExpr
>(IvarBind
);
626 if (IvarRef
->isFreeIvar())
629 const Expr
*Base
= IvarRef
->getBase();
630 if (const auto *ICE
= dyn_cast
<ImplicitCastExpr
>(Base
))
631 Base
= ICE
->getSubExpr();
633 if (const auto *DRE
= dyn_cast
<DeclRefExpr
>(Base
))
634 if (const auto *ID
= dyn_cast
<ImplicitParamDecl
>(DRE
->getDecl()))
635 if (ID
->getParameterKind() == ImplicitParamKind::ObjCSelf
)
643 /// Attempts to find the region of interest in a given CXX decl,
644 /// by either following the base classes or fields.
645 /// Dereferences fields up to a given recursion limit.
646 /// Note that \p Vec is passed by value, leading to quadratic copying cost,
647 /// but it's OK in practice since its length is limited to DEREFERENCE_LIMIT.
648 /// \return A chain fields leading to the region of interest or std::nullopt.
649 const std::optional
<NoStoreFuncVisitor::RegionVector
>
650 NoStoreFuncVisitor::findRegionOfInterestInRecord(
651 const RecordDecl
*RD
, ProgramStateRef State
, const MemRegion
*R
,
652 const NoStoreFuncVisitor::RegionVector
&Vec
/* = {} */,
653 int depth
/* = 0 */) {
655 if (depth
== DEREFERENCE_LIMIT
) // Limit the recursion depth.
658 if (const auto *RDX
= dyn_cast
<CXXRecordDecl
>(RD
))
659 if (!RDX
->hasDefinition())
662 // Recursively examine the base classes.
663 // Note that following base classes does not increase the recursion depth.
664 if (const auto *RDX
= dyn_cast
<CXXRecordDecl
>(RD
))
665 for (const auto &II
: RDX
->bases())
666 if (const RecordDecl
*RRD
= II
.getType()->getAsRecordDecl())
667 if (std::optional
<RegionVector
> Out
=
668 findRegionOfInterestInRecord(RRD
, State
, R
, Vec
, depth
))
671 for (const FieldDecl
*I
: RD
->fields()) {
672 QualType FT
= I
->getType();
673 const FieldRegion
*FR
= MmrMgr
.getFieldRegion(I
, cast
<SubRegion
>(R
));
674 const SVal V
= State
->getSVal(FR
);
675 const MemRegion
*VR
= V
.getAsRegion();
677 RegionVector VecF
= Vec
;
680 if (RegionOfInterest
== VR
)
683 if (const RecordDecl
*RRD
= FT
->getAsRecordDecl())
685 findRegionOfInterestInRecord(RRD
, State
, FR
, VecF
, depth
+ 1))
688 QualType PT
= FT
->getPointeeType();
689 if (PT
.isNull() || PT
->isVoidType() || !VR
)
692 if (const RecordDecl
*RRD
= PT
->getAsRecordDecl())
693 if (std::optional
<RegionVector
> Out
=
694 findRegionOfInterestInRecord(RRD
, State
, VR
, VecF
, depth
+ 1))
701 PathDiagnosticPieceRef
702 NoStoreFuncVisitor::maybeEmitNoteForObjCSelf(PathSensitiveBugReport
&R
,
703 const ObjCMethodCall
&Call
,
704 const ExplodedNode
*N
) {
705 if (const auto *IvarR
= dyn_cast
<ObjCIvarRegion
>(RegionOfInterest
)) {
706 const MemRegion
*SelfRegion
= Call
.getReceiverSVal().getAsRegion();
707 if (RegionOfInterest
->isSubRegionOf(SelfRegion
) &&
708 potentiallyWritesIntoIvar(Call
.getRuntimeDefinition().getDecl(),
710 return maybeEmitNote(R
, Call
, N
, {}, SelfRegion
, "self",
711 /*FirstIsReferenceType=*/false, 1);
716 PathDiagnosticPieceRef
717 NoStoreFuncVisitor::maybeEmitNoteForCXXThis(PathSensitiveBugReport
&R
,
718 const CXXConstructorCall
&Call
,
719 const ExplodedNode
*N
) {
720 const MemRegion
*ThisR
= Call
.getCXXThisVal().getAsRegion();
721 if (RegionOfInterest
->isSubRegionOf(ThisR
) && !Call
.getDecl()->isImplicit())
722 return maybeEmitNote(R
, Call
, N
, {}, ThisR
, "this",
723 /*FirstIsReferenceType=*/false, 1);
725 // Do not generate diagnostics for not modified parameters in
730 /// \return whether \p Ty points to a const type, or is a const reference.
731 static bool isPointerToConst(QualType Ty
) {
732 return !Ty
->getPointeeType().isNull() &&
733 Ty
->getPointeeType().getCanonicalType().isConstQualified();
736 PathDiagnosticPieceRef
NoStoreFuncVisitor::maybeEmitNoteForParameters(
737 PathSensitiveBugReport
&R
, const CallEvent
&Call
, const ExplodedNode
*N
) {
738 ArrayRef
<ParmVarDecl
*> Parameters
= Call
.parameters();
739 for (unsigned I
= 0; I
< Call
.getNumArgs() && I
< Parameters
.size(); ++I
) {
740 const ParmVarDecl
*PVD
= Parameters
[I
];
741 SVal V
= Call
.getArgSVal(I
);
742 bool ParamIsReferenceType
= PVD
->getType()->isReferenceType();
743 std::string ParamName
= PVD
->getNameAsString();
745 unsigned IndirectionLevel
= 1;
746 QualType T
= PVD
->getType();
747 while (const MemRegion
*MR
= V
.getAsRegion()) {
748 if (RegionOfInterest
->isSubRegionOf(MR
) && !isPointerToConst(T
))
749 return maybeEmitNote(R
, Call
, N
, {}, MR
, ParamName
,
750 ParamIsReferenceType
, IndirectionLevel
);
752 QualType PT
= T
->getPointeeType();
753 if (PT
.isNull() || PT
->isVoidType())
756 ProgramStateRef State
= N
->getState();
758 if (const RecordDecl
*RD
= PT
->getAsRecordDecl())
759 if (std::optional
<RegionVector
> P
=
760 findRegionOfInterestInRecord(RD
, State
, MR
))
761 return maybeEmitNote(R
, Call
, N
, *P
, RegionOfInterest
, ParamName
,
762 ParamIsReferenceType
, IndirectionLevel
);
764 V
= State
->getSVal(MR
, PT
);
773 bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
774 const ExplodedNode
*CurrN
, const ExplodedNode
*CallExitBeginN
) {
775 return ::wasRegionOfInterestModifiedAt(
776 RegionOfInterest
, CurrN
,
777 CallExitBeginN
->getState()->getSVal(RegionOfInterest
));
780 static llvm::StringLiteral WillBeUsedForACondition
=
781 ", which participates in a condition later";
783 PathDiagnosticPieceRef
NoStoreFuncVisitor::maybeEmitNote(
784 PathSensitiveBugReport
&R
, const CallEvent
&Call
, const ExplodedNode
*N
,
785 const RegionVector
&FieldChain
, const MemRegion
*MatchedRegion
,
786 StringRef FirstElement
, bool FirstIsReferenceType
,
787 unsigned IndirectionLevel
) {
789 PathDiagnosticLocation L
=
790 PathDiagnosticLocation::create(N
->getLocation(), SM
);
792 // For now this shouldn't trigger, but once it does (as we add more
793 // functions to the body farm), we'll need to decide if these reports
794 // are worth suppressing as well.
795 if (!L
.hasValidLocation())
798 SmallString
<256> sbuf
;
799 llvm::raw_svector_ostream
os(sbuf
);
800 os
<< "Returning without writing to '";
802 // Do not generate the note if failed to pretty-print.
803 if (!prettyPrintRegionName(FieldChain
, MatchedRegion
, FirstElement
,
804 FirstIsReferenceType
, IndirectionLevel
, os
))
808 if (TKind
== bugreporter::TrackingKind::Condition
)
809 os
<< WillBeUsedForACondition
;
810 return std::make_shared
<PathDiagnosticEventPiece
>(L
, os
.str());
813 bool NoStoreFuncVisitor::prettyPrintRegionName(const RegionVector
&FieldChain
,
814 const MemRegion
*MatchedRegion
,
815 StringRef FirstElement
,
816 bool FirstIsReferenceType
,
817 unsigned IndirectionLevel
,
818 llvm::raw_svector_ostream
&os
) {
820 if (FirstIsReferenceType
)
823 RegionVector RegionSequence
;
825 // Add the regions in the reverse order, then reverse the resulting array.
826 assert(RegionOfInterest
->isSubRegionOf(MatchedRegion
));
827 const MemRegion
*R
= RegionOfInterest
;
828 while (R
!= MatchedRegion
) {
829 RegionSequence
.push_back(R
);
830 R
= cast
<SubRegion
>(R
)->getSuperRegion();
832 std::reverse(RegionSequence
.begin(), RegionSequence
.end());
833 RegionSequence
.append(FieldChain
.begin(), FieldChain
.end());
836 for (const MemRegion
*R
: RegionSequence
) {
838 // Just keep going up to the base region.
839 // Element regions may appear due to casts.
840 if (isa
<CXXBaseObjectRegion
, CXXTempObjectRegion
>(R
))
844 Sep
= prettyPrintFirstElement(FirstElement
,
845 /*MoreItemsExpected=*/true,
846 IndirectionLevel
, os
);
850 // Can only reasonably pretty-print DeclRegions.
851 if (!isa
<DeclRegion
>(R
))
854 const auto *DR
= cast
<DeclRegion
>(R
);
855 Sep
= DR
->getValueType()->isAnyPointerType() ? "->" : ".";
856 DR
->getDecl()->getDeclName().print(os
, PP
);
860 prettyPrintFirstElement(FirstElement
,
861 /*MoreItemsExpected=*/false, IndirectionLevel
, os
);
865 StringRef
NoStoreFuncVisitor::prettyPrintFirstElement(
866 StringRef FirstElement
, bool MoreItemsExpected
, int IndirectionLevel
,
867 llvm::raw_svector_ostream
&os
) {
870 if (IndirectionLevel
> 0 && MoreItemsExpected
) {
875 if (IndirectionLevel
> 0 && MoreItemsExpected
)
878 for (int i
= 0; i
< IndirectionLevel
; i
++)
882 if (IndirectionLevel
> 0 && MoreItemsExpected
)
888 //===----------------------------------------------------------------------===//
889 // Implementation of MacroNullReturnSuppressionVisitor.
890 //===----------------------------------------------------------------------===//
894 /// Suppress null-pointer-dereference bugs where dereferenced null was returned
896 class MacroNullReturnSuppressionVisitor final
: public BugReporterVisitor
{
897 const SubRegion
*RegionOfInterest
;
898 const SVal ValueAtDereference
;
900 // Do not invalidate the reports where the value was modified
901 // after it got assigned to from the macro.
902 bool WasModified
= false;
905 MacroNullReturnSuppressionVisitor(const SubRegion
*R
, const SVal V
)
906 : RegionOfInterest(R
), ValueAtDereference(V
) {}
908 PathDiagnosticPieceRef
VisitNode(const ExplodedNode
*N
,
909 BugReporterContext
&BRC
,
910 PathSensitiveBugReport
&BR
) override
{
914 auto BugPoint
= BR
.getErrorNode()->getLocation().getAs
<StmtPoint
>();
918 const SourceManager
&SMgr
= BRC
.getSourceManager();
919 if (auto Loc
= matchAssignment(N
)) {
920 if (isFunctionMacroExpansion(*Loc
, SMgr
)) {
921 std::string MacroName
= std::string(getMacroName(*Loc
, BRC
));
922 SourceLocation BugLoc
= BugPoint
->getStmt()->getBeginLoc();
923 if (!BugLoc
.isMacroID() || getMacroName(BugLoc
, BRC
) != MacroName
)
924 BR
.markInvalid(getTag(), MacroName
.c_str());
928 if (wasRegionOfInterestModifiedAt(RegionOfInterest
, N
, ValueAtDereference
))
934 static void addMacroVisitorIfNecessary(
935 const ExplodedNode
*N
, const MemRegion
*R
,
936 bool EnableNullFPSuppression
, PathSensitiveBugReport
&BR
,
938 AnalyzerOptions
&Options
= N
->getState()->getAnalysisManager().options
;
939 if (EnableNullFPSuppression
&& Options
.ShouldSuppressNullReturnPaths
&&
941 BR
.addVisitor
<MacroNullReturnSuppressionVisitor
>(R
->getAs
<SubRegion
>(),
945 void* getTag() const {
947 return static_cast<void *>(&Tag
);
950 void Profile(llvm::FoldingSetNodeID
&ID
) const override
{
951 ID
.AddPointer(getTag());
955 /// \return Source location of right hand side of an assignment
956 /// into \c RegionOfInterest, empty optional if none found.
957 std::optional
<SourceLocation
> matchAssignment(const ExplodedNode
*N
) {
958 const Stmt
*S
= N
->getStmtForDiagnostics();
959 ProgramStateRef State
= N
->getState();
960 auto *LCtx
= N
->getLocationContext();
964 if (const auto *DS
= dyn_cast
<DeclStmt
>(S
)) {
965 if (const auto *VD
= dyn_cast
<VarDecl
>(DS
->getSingleDecl()))
966 if (const Expr
*RHS
= VD
->getInit())
967 if (RegionOfInterest
->isSubRegionOf(
968 State
->getLValue(VD
, LCtx
).getAsRegion()))
969 return RHS
->getBeginLoc();
970 } else if (const auto *BO
= dyn_cast
<BinaryOperator
>(S
)) {
971 const MemRegion
*R
= N
->getSVal(BO
->getLHS()).getAsRegion();
972 const Expr
*RHS
= BO
->getRHS();
973 if (BO
->isAssignmentOp() && RegionOfInterest
->isSubRegionOf(R
)) {
974 return RHS
->getBeginLoc();
981 } // end of anonymous namespace
985 /// Emits an extra note at the return statement of an interesting stack frame.
987 /// The returned value is marked as an interesting value, and if it's null,
988 /// adds a visitor to track where it became null.
990 /// This visitor is intended to be used when another visitor discovers that an
991 /// interesting value comes from an inlined function call.
992 class ReturnVisitor
: public TrackingBugReporterVisitor
{
993 const StackFrameContext
*CalleeSFC
;
1000 bool EnableNullFPSuppression
;
1001 bool ShouldInvalidate
= true;
1002 AnalyzerOptions
& Options
;
1003 bugreporter::TrackingKind TKind
;
1006 ReturnVisitor(TrackerRef ParentTracker
, const StackFrameContext
*Frame
,
1007 bool Suppressed
, AnalyzerOptions
&Options
,
1008 bugreporter::TrackingKind TKind
)
1009 : TrackingBugReporterVisitor(ParentTracker
), CalleeSFC(Frame
),
1010 EnableNullFPSuppression(Suppressed
), Options(Options
), TKind(TKind
) {}
1012 static void *getTag() {
1014 return static_cast<void *>(&Tag
);
1017 void Profile(llvm::FoldingSetNodeID
&ID
) const override
{
1018 ID
.AddPointer(ReturnVisitor::getTag());
1019 ID
.AddPointer(CalleeSFC
);
1020 ID
.AddBoolean(EnableNullFPSuppression
);
1023 PathDiagnosticPieceRef
visitNodeInitial(const ExplodedNode
*N
,
1024 BugReporterContext
&BRC
,
1025 PathSensitiveBugReport
&BR
) {
1026 // Only print a message at the interesting return statement.
1027 if (N
->getLocationContext() != CalleeSFC
)
1030 std::optional
<StmtPoint
> SP
= N
->getLocationAs
<StmtPoint
>();
1034 const auto *Ret
= dyn_cast
<ReturnStmt
>(SP
->getStmt());
1038 // Okay, we're at the right return statement, but do we have the return
1040 ProgramStateRef State
= N
->getState();
1041 SVal V
= State
->getSVal(Ret
, CalleeSFC
);
1042 if (V
.isUnknownOrUndef())
1045 // Don't print any more notes after this one.
1048 const Expr
*RetE
= Ret
->getRetValue();
1049 assert(RetE
&& "Tracking a return value for a void function");
1051 // Handle cases where a reference is returned and then immediately used.
1052 std::optional
<Loc
> LValue
;
1053 if (RetE
->isGLValue()) {
1054 if ((LValue
= V
.getAs
<Loc
>())) {
1055 SVal RValue
= State
->getRawSVal(*LValue
, RetE
->getType());
1056 if (isa
<DefinedSVal
>(RValue
))
1061 // Ignore aggregate rvalues.
1062 if (isa
<nonloc::LazyCompoundVal
, nonloc::CompoundVal
>(V
))
1065 RetE
= RetE
->IgnoreParenCasts();
1067 // Let's track the return value.
1068 getParentTracker().track(RetE
, N
, {TKind
, EnableNullFPSuppression
});
1070 // Build an appropriate message based on the return value.
1071 SmallString
<64> Msg
;
1072 llvm::raw_svector_ostream
Out(Msg
);
1074 bool WouldEventBeMeaningless
= false;
1076 if (State
->isNull(V
).isConstrainedTrue()) {
1079 // If we have counter-suppression enabled, make sure we keep visiting
1080 // future nodes. We want to emit a path note as well, in case
1081 // the report is resurrected as valid later on.
1082 if (EnableNullFPSuppression
&&
1083 Options
.ShouldAvoidSuppressingNullArgumentPaths
)
1084 Mode
= MaybeUnsuppress
;
1086 if (RetE
->getType()->isObjCObjectPointerType()) {
1087 Out
<< "Returning nil";
1089 Out
<< "Returning null pointer";
1092 Out
<< "Returning zero";
1096 if (auto CI
= V
.getAs
<nonloc::ConcreteInt
>()) {
1097 Out
<< "Returning the value " << CI
->getValue();
1099 // There is nothing interesting about returning a value, when it is
1100 // plain value without any constraints, and the function is guaranteed
1101 // to return that every time. We could use CFG::isLinear() here, but
1102 // constexpr branches are obvious to the compiler, not necesserily to
1104 if (N
->getCFG().size() == 3)
1105 WouldEventBeMeaningless
= true;
1107 Out
<< (isa
<Loc
>(V
) ? "Returning pointer" : "Returning value");
1112 if (const MemRegion
*MR
= LValue
->getAsRegion()) {
1113 if (MR
->canPrintPretty()) {
1114 Out
<< " (reference to ";
1115 MR
->printPretty(Out
);
1120 // FIXME: We should have a more generalized location printing mechanism.
1121 if (const auto *DR
= dyn_cast
<DeclRefExpr
>(RetE
))
1122 if (const auto *DD
= dyn_cast
<DeclaratorDecl
>(DR
->getDecl()))
1123 Out
<< " (loaded from '" << *DD
<< "')";
1126 PathDiagnosticLocation
L(Ret
, BRC
.getSourceManager(), CalleeSFC
);
1127 if (!L
.isValid() || !L
.asLocation().isValid())
1130 if (TKind
== bugreporter::TrackingKind::Condition
)
1131 Out
<< WillBeUsedForACondition
;
1133 auto EventPiece
= std::make_shared
<PathDiagnosticEventPiece
>(L
, Out
.str());
1135 // If we determined that the note is meaningless, make it prunable, and
1136 // don't mark the stackframe interesting.
1137 if (WouldEventBeMeaningless
)
1138 EventPiece
->setPrunable(true);
1140 BR
.markInteresting(CalleeSFC
);
1145 PathDiagnosticPieceRef
visitNodeMaybeUnsuppress(const ExplodedNode
*N
,
1146 BugReporterContext
&BRC
,
1147 PathSensitiveBugReport
&BR
) {
1148 assert(Options
.ShouldAvoidSuppressingNullArgumentPaths
);
1150 // Are we at the entry node for this call?
1151 std::optional
<CallEnter
> CE
= N
->getLocationAs
<CallEnter
>();
1155 if (CE
->getCalleeContext() != CalleeSFC
)
1160 // Don't automatically suppress a report if one of the arguments is
1161 // known to be a null pointer. Instead, start tracking /that/ null
1162 // value back to its origin.
1163 ProgramStateManager
&StateMgr
= BRC
.getStateManager();
1164 CallEventManager
&CallMgr
= StateMgr
.getCallEventManager();
1166 ProgramStateRef State
= N
->getState();
1167 CallEventRef
<> Call
= CallMgr
.getCaller(CalleeSFC
, State
);
1168 for (unsigned I
= 0, E
= Call
->getNumArgs(); I
!= E
; ++I
) {
1169 std::optional
<Loc
> ArgV
= Call
->getArgSVal(I
).getAs
<Loc
>();
1173 const Expr
*ArgE
= Call
->getArgExpr(I
);
1177 // Is it possible for this argument to be non-null?
1178 if (!State
->isNull(*ArgV
).isConstrainedTrue())
1181 if (getParentTracker()
1182 .track(ArgE
, N
, {TKind
, EnableNullFPSuppression
})
1183 .FoundSomethingToTrack
)
1184 ShouldInvalidate
= false;
1186 // If we /can't/ track the null pointer, we should err on the side of
1187 // false negatives, and continue towards marking this report invalid.
1188 // (We will still look at the other arguments, though.)
1194 PathDiagnosticPieceRef
VisitNode(const ExplodedNode
*N
,
1195 BugReporterContext
&BRC
,
1196 PathSensitiveBugReport
&BR
) override
{
1199 return visitNodeInitial(N
, BRC
, BR
);
1200 case MaybeUnsuppress
:
1201 return visitNodeMaybeUnsuppress(N
, BRC
, BR
);
1206 llvm_unreachable("Invalid visit mode!");
1209 void finalizeVisitor(BugReporterContext
&, const ExplodedNode
*,
1210 PathSensitiveBugReport
&BR
) override
{
1211 if (EnableNullFPSuppression
&& ShouldInvalidate
)
1212 BR
.markInvalid(ReturnVisitor::getTag(), CalleeSFC
);
1216 //===----------------------------------------------------------------------===//
1218 //===----------------------------------------------------------------------===//
1220 /// Finds last store into the given region,
1221 /// which is different from a given symbolic value.
1222 class StoreSiteFinder final
: public TrackingBugReporterVisitor
{
1225 bool Satisfied
= false;
1227 TrackingOptions Options
;
1228 const StackFrameContext
*OriginSFC
;
1231 /// \param V We're searching for the store where \c R received this value.
1232 /// \param R The region we're tracking.
1233 /// \param Options Tracking behavior options.
1234 /// \param OriginSFC Only adds notes when the last store happened in a
1235 /// different stackframe to this one. Disregarded if the tracking kind
1237 /// This is useful, because for non-tracked regions, notes about
1238 /// changes to its value in a nested stackframe could be pruned, and
1239 /// this visitor can prevent that without polluting the bugpath too
1241 StoreSiteFinder(bugreporter::TrackerRef ParentTracker
, KnownSVal V
,
1242 const MemRegion
*R
, TrackingOptions Options
,
1243 const StackFrameContext
*OriginSFC
= nullptr)
1244 : TrackingBugReporterVisitor(ParentTracker
), R(R
), V(V
), Options(Options
),
1245 OriginSFC(OriginSFC
) {
1249 void Profile(llvm::FoldingSetNodeID
&ID
) const override
;
1251 PathDiagnosticPieceRef
VisitNode(const ExplodedNode
*N
,
1252 BugReporterContext
&BRC
,
1253 PathSensitiveBugReport
&BR
) override
;
1257 void StoreSiteFinder::Profile(llvm::FoldingSetNodeID
&ID
) const {
1259 ID
.AddPointer(&tag
);
1262 ID
.AddInteger(static_cast<int>(Options
.Kind
));
1263 ID
.AddBoolean(Options
.EnableNullFPSuppression
);
1266 /// Returns true if \p N represents the DeclStmt declaring and initializing
1268 static bool isInitializationOfVar(const ExplodedNode
*N
, const VarRegion
*VR
) {
1269 std::optional
<PostStmt
> P
= N
->getLocationAs
<PostStmt
>();
1273 const DeclStmt
*DS
= P
->getStmtAs
<DeclStmt
>();
1277 if (DS
->getSingleDecl() != VR
->getDecl())
1280 const MemSpaceRegion
*VarSpace
= VR
->getMemorySpace();
1281 const auto *FrameSpace
= dyn_cast
<StackSpaceRegion
>(VarSpace
);
1283 // If we ever directly evaluate global DeclStmts, this assertion will be
1284 // invalid, but this still seems preferable to silently accepting an
1285 // initialization that may be for a path-sensitive variable.
1286 assert(VR
->getDecl()->isStaticLocal() && "non-static stackless VarRegion");
1290 assert(VR
->getDecl()->hasLocalStorage());
1291 const LocationContext
*LCtx
= N
->getLocationContext();
1292 return FrameSpace
->getStackFrame() == LCtx
->getStackFrame();
1295 static bool isObjCPointer(const MemRegion
*R
) {
1296 if (R
->isBoundable())
1297 if (const auto *TR
= dyn_cast
<TypedValueRegion
>(R
))
1298 return TR
->getValueType()->isObjCObjectPointerType();
1303 static bool isObjCPointer(const ValueDecl
*D
) {
1304 return D
->getType()->isObjCObjectPointerType();
1307 /// Show diagnostics for initializing or declaring a region \p R with a bad value.
1308 static void showBRDiagnostics(llvm::raw_svector_ostream
&OS
, StoreInfo SI
) {
1309 const bool HasPrefix
= SI
.Dest
->canPrintPretty();
1312 SI
.Dest
->printPretty(OS
);
1316 const char *Action
= nullptr;
1318 switch (SI
.StoreKind
) {
1319 case StoreInfo::Initialization
:
1320 Action
= HasPrefix
? "initialized to " : "Initializing to ";
1322 case StoreInfo::BlockCapture
:
1323 Action
= HasPrefix
? "captured by block as " : "Captured by block as ";
1326 llvm_unreachable("Unexpected store kind");
1329 if (isa
<loc::ConcreteInt
>(SI
.Value
)) {
1330 OS
<< Action
<< (isObjCPointer(SI
.Dest
) ? "nil" : "a null pointer value");
1332 } else if (auto CVal
= SI
.Value
.getAs
<nonloc::ConcreteInt
>()) {
1333 OS
<< Action
<< CVal
->getValue();
1335 } else if (SI
.Origin
&& SI
.Origin
->canPrintPretty()) {
1336 OS
<< Action
<< "the value of ";
1337 SI
.Origin
->printPretty(OS
);
1339 } else if (SI
.StoreKind
== StoreInfo::Initialization
) {
1340 // We don't need to check here, all these conditions were
1341 // checked by StoreSiteFinder, when it figured out that it is
1344 cast
<DeclStmt
>(SI
.StoreSite
->getLocationAs
<PostStmt
>()->getStmt());
1346 if (SI
.Value
.isUndef()) {
1347 if (isa
<VarRegion
>(SI
.Dest
)) {
1348 const auto *VD
= cast
<VarDecl
>(DS
->getSingleDecl());
1350 if (VD
->getInit()) {
1351 OS
<< (HasPrefix
? "initialized" : "Initializing")
1352 << " to a garbage value";
1354 OS
<< (HasPrefix
? "declared" : "Declaring")
1355 << " without an initial value";
1359 OS
<< (HasPrefix
? "initialized" : "Initialized") << " here";
1364 /// Display diagnostics for passing bad region as a parameter.
1365 static void showBRParamDiagnostics(llvm::raw_svector_ostream
&OS
,
1367 const auto *VR
= cast
<VarRegion
>(SI
.Dest
);
1368 const auto *D
= VR
->getDecl();
1372 if (isa
<loc::ConcreteInt
>(SI
.Value
)) {
1373 OS
<< (isObjCPointer(D
) ? "nil object reference" : "null pointer value");
1375 } else if (SI
.Value
.isUndef()) {
1376 OS
<< "uninitialized value";
1378 } else if (auto CI
= SI
.Value
.getAs
<nonloc::ConcreteInt
>()) {
1379 OS
<< "the value " << CI
->getValue();
1381 } else if (SI
.Origin
&& SI
.Origin
->canPrintPretty()) {
1382 SI
.Origin
->printPretty(OS
);
1388 if (const auto *Param
= dyn_cast
<ParmVarDecl
>(VR
->getDecl())) {
1389 // Printed parameter indexes are 1-based, not 0-based.
1390 unsigned Idx
= Param
->getFunctionScopeIndex() + 1;
1391 OS
<< " via " << Idx
<< llvm::getOrdinalSuffix(Idx
) << " parameter";
1392 if (VR
->canPrintPretty()) {
1394 VR
->printPretty(OS
);
1396 } else if (const auto *ImplParam
= dyn_cast
<ImplicitParamDecl
>(D
)) {
1397 if (ImplParam
->getParameterKind() == ImplicitParamKind::ObjCSelf
) {
1398 OS
<< " via implicit parameter 'self'";
1403 /// Show default diagnostics for storing bad region.
1404 static void showBRDefaultDiagnostics(llvm::raw_svector_ostream
&OS
,
1406 const bool HasSuffix
= SI
.Dest
->canPrintPretty();
1408 if (isa
<loc::ConcreteInt
>(SI
.Value
)) {
1409 OS
<< (isObjCPointer(SI
.Dest
) ? "nil object reference stored"
1410 : (HasSuffix
? "Null pointer value stored"
1411 : "Storing null pointer value"));
1413 } else if (SI
.Value
.isUndef()) {
1414 OS
<< (HasSuffix
? "Uninitialized value stored"
1415 : "Storing uninitialized value");
1417 } else if (auto CV
= SI
.Value
.getAs
<nonloc::ConcreteInt
>()) {
1419 OS
<< "The value " << CV
->getValue() << " is assigned";
1421 OS
<< "Assigning " << CV
->getValue();
1423 } else if (SI
.Origin
&& SI
.Origin
->canPrintPretty()) {
1425 OS
<< "The value of ";
1426 SI
.Origin
->printPretty(OS
);
1427 OS
<< " is assigned";
1429 OS
<< "Assigning the value of ";
1430 SI
.Origin
->printPretty(OS
);
1434 OS
<< (HasSuffix
? "Value assigned" : "Assigning value");
1439 SI
.Dest
->printPretty(OS
);
1443 static bool isTrivialCopyOrMoveCtor(const CXXConstructExpr
*CE
) {
1447 const auto *CtorDecl
= CE
->getConstructor();
1449 return CtorDecl
->isCopyOrMoveConstructor() && CtorDecl
->isTrivial();
1452 static const Expr
*tryExtractInitializerFromList(const InitListExpr
*ILE
,
1453 const MemRegion
*R
) {
1455 const auto *TVR
= dyn_cast_or_null
<TypedValueRegion
>(R
);
1460 const auto ITy
= ILE
->getType().getCanonicalType();
1462 // Push each sub-region onto the stack.
1463 std::stack
<const TypedValueRegion
*> TVRStack
;
1464 while (isa
<FieldRegion
>(TVR
) || isa
<ElementRegion
>(TVR
)) {
1465 // We found a region that matches the type of the init list,
1466 // so we assume this is the outer-most region. This can happen
1467 // if the initializer list is inside a class. If our assumption
1468 // is wrong, we return a nullptr in the end.
1469 if (ITy
== TVR
->getValueType().getCanonicalType())
1473 TVR
= cast
<TypedValueRegion
>(TVR
->getSuperRegion());
1476 // If the type of the outer most region doesn't match the type
1477 // of the ILE, we can't match the ILE and the region.
1478 if (ITy
!= TVR
->getValueType().getCanonicalType())
1481 const Expr
*Init
= ILE
;
1482 while (!TVRStack
.empty()) {
1483 TVR
= TVRStack
.top();
1486 // We hit something that's not an init list before
1487 // running out of regions, so we most likely failed.
1488 if (!isa
<InitListExpr
>(Init
))
1491 ILE
= cast
<InitListExpr
>(Init
);
1492 auto NumInits
= ILE
->getNumInits();
1494 if (const auto *FR
= dyn_cast
<FieldRegion
>(TVR
)) {
1495 const auto *FD
= FR
->getDecl();
1497 if (FD
->getFieldIndex() >= NumInits
)
1500 Init
= ILE
->getInit(FD
->getFieldIndex());
1501 } else if (const auto *ER
= dyn_cast
<ElementRegion
>(TVR
)) {
1502 const auto Ind
= ER
->getIndex();
1504 // If index is symbolic, we can't figure out which expression
1505 // belongs to the region.
1506 if (!Ind
.isConstant())
1509 const auto IndVal
= Ind
.getAsInteger()->getLimitedValue();
1510 if (IndVal
>= NumInits
)
1513 Init
= ILE
->getInit(IndVal
);
1520 PathDiagnosticPieceRef
StoreSiteFinder::VisitNode(const ExplodedNode
*Succ
,
1521 BugReporterContext
&BRC
,
1522 PathSensitiveBugReport
&BR
) {
1526 const ExplodedNode
*StoreSite
= nullptr;
1527 const ExplodedNode
*Pred
= Succ
->getFirstPred();
1528 const Expr
*InitE
= nullptr;
1529 bool IsParam
= false;
1531 // First see if we reached the declaration of the region.
1532 if (const auto *VR
= dyn_cast
<VarRegion
>(R
)) {
1533 if (isInitializationOfVar(Pred
, VR
)) {
1535 InitE
= VR
->getDecl()->getInit();
1539 // If this is a post initializer expression, initializing the region, we
1540 // should track the initializer expression.
1541 if (std::optional
<PostInitializer
> PIP
=
1542 Pred
->getLocationAs
<PostInitializer
>()) {
1543 const MemRegion
*FieldReg
= (const MemRegion
*)PIP
->getLocationValue();
1544 if (FieldReg
== R
) {
1546 InitE
= PIP
->getInitializer()->getInit();
1550 // Otherwise, see if this is the store site:
1551 // (1) Succ has this binding and Pred does not, i.e. this is
1552 // where the binding first occurred.
1553 // (2) Succ has this binding and is a PostStore node for this region, i.e.
1554 // the same binding was re-assigned here.
1556 if (Succ
->getState()->getSVal(R
) != V
)
1559 if (hasVisibleUpdate(Pred
, Pred
->getState()->getSVal(R
), Succ
, V
)) {
1560 std::optional
<PostStore
> PS
= Succ
->getLocationAs
<PostStore
>();
1561 if (!PS
|| PS
->getLocationValue() != R
)
1567 if (std::optional
<PostStmt
> P
= Succ
->getLocationAs
<PostStmt
>()) {
1568 // If this is an assignment expression, we can track the value
1570 if (const BinaryOperator
*BO
= P
->getStmtAs
<BinaryOperator
>()) {
1571 if (BO
->isAssignmentOp())
1572 InitE
= BO
->getRHS();
1574 // If we have a declaration like 'S s{1,2}' that needs special
1575 // handling, we handle it here.
1576 else if (const auto *DS
= P
->getStmtAs
<DeclStmt
>()) {
1577 const auto *Decl
= DS
->getSingleDecl();
1578 if (isa
<VarDecl
>(Decl
)) {
1579 const auto *VD
= cast
<VarDecl
>(Decl
);
1581 // FIXME: Here we only track the inner most region, so we lose
1582 // information, but it's still better than a crash or no information
1585 // E.g.: The region we have is 's.s2.s3.s4.y' and we only track 'y',
1586 // and throw away the rest.
1587 if (const auto *ILE
= dyn_cast
<InitListExpr
>(VD
->getInit()))
1588 InitE
= tryExtractInitializerFromList(ILE
, R
);
1590 } else if (const auto *CE
= P
->getStmtAs
<CXXConstructExpr
>()) {
1592 const auto State
= Succ
->getState();
1594 if (isTrivialCopyOrMoveCtor(CE
) && isa
<SubRegion
>(R
)) {
1595 // Migrate the field regions from the current object to
1596 // the parent object. If we track 'a.y.e' and encounter
1597 // 'S a = b' then we need to track 'b.y.e'.
1599 // Push the regions to a stack, from last to first, so
1600 // considering the example above the stack will look like
1601 // (bottom) 'e' -> 'y' (top).
1603 std::stack
<const SubRegion
*> SRStack
;
1604 const SubRegion
*SR
= cast
<SubRegion
>(R
);
1605 while (isa
<FieldRegion
>(SR
) || isa
<ElementRegion
>(SR
)) {
1607 SR
= cast
<SubRegion
>(SR
->getSuperRegion());
1610 // Get the region for the object we copied/moved from.
1611 const auto *OriginEx
= CE
->getArg(0);
1612 const auto OriginVal
=
1613 State
->getSVal(OriginEx
, Succ
->getLocationContext());
1615 // Pop the stored field regions and apply them to the origin
1616 // object in the same order we had them on the copy.
1617 // OriginField will evolve like 'b' -> 'b.y' -> 'b.y.e'.
1618 SVal OriginField
= OriginVal
;
1619 while (!SRStack
.empty()) {
1620 const auto *TopR
= SRStack
.top();
1623 if (const auto *FR
= dyn_cast
<FieldRegion
>(TopR
)) {
1624 OriginField
= State
->getLValue(FR
->getDecl(), OriginField
);
1625 } else if (const auto *ER
= dyn_cast
<ElementRegion
>(TopR
)) {
1626 OriginField
= State
->getLValue(ER
->getElementType(),
1627 ER
->getIndex(), OriginField
);
1629 // FIXME: handle other region type
1634 getParentTracker().track(V
, OriginField
.getAsRegion(), Options
);
1638 // This branch can occur in cases like `Ctor() : field{ x, y } {}'.
1639 else if (const auto *ILE
= P
->getStmtAs
<InitListExpr
>()) {
1640 // FIXME: Here we only track the top level region, so we lose
1641 // information, but it's still better than a crash or no information
1644 // E.g.: The region we have is 's.s2.s3.s4.y' and we only track 'y', and
1645 // throw away the rest.
1646 InitE
= tryExtractInitializerFromList(ILE
, R
);
1650 // If this is a call entry, the variable should be a parameter.
1651 // FIXME: Handle CXXThisRegion as well. (This is not a priority because
1652 // 'this' should never be NULL, but this visitor isn't just for NULL and
1654 if (std::optional
<CallEnter
> CE
= Succ
->getLocationAs
<CallEnter
>()) {
1655 if (const auto *VR
= dyn_cast
<VarRegion
>(R
)) {
1657 if (const auto *Param
= dyn_cast
<ParmVarDecl
>(VR
->getDecl())) {
1658 ProgramStateManager
&StateMgr
= BRC
.getStateManager();
1659 CallEventManager
&CallMgr
= StateMgr
.getCallEventManager();
1661 CallEventRef
<> Call
= CallMgr
.getCaller(CE
->getCalleeContext(),
1663 InitE
= Call
->getArgExpr(Param
->getFunctionScopeIndex());
1665 // Handle Objective-C 'self'.
1666 assert(isa
<ImplicitParamDecl
>(VR
->getDecl()));
1667 InitE
= cast
<ObjCMessageExpr
>(CE
->getCalleeContext()->getCallSite())
1668 ->getInstanceReceiver()->IgnoreParenCasts();
1674 // If this is a CXXTempObjectRegion, the Expr responsible for its creation
1675 // is wrapped inside of it.
1676 if (const auto *TmpR
= dyn_cast
<CXXTempObjectRegion
>(R
))
1677 InitE
= TmpR
->getExpr();
1685 // If we have an expression that provided the value, try to track where it
1689 InitE
= InitE
->IgnoreParenCasts();
1691 getParentTracker().track(InitE
, StoreSite
, Options
);
1694 // Let's try to find the region where the value came from.
1695 const MemRegion
*OldRegion
= nullptr;
1697 // If we have init expression, it might be simply a reference
1698 // to a variable, so we can use it.
1700 // That region might still be not exactly what we are looking for.
1701 // In situations like `int &ref = val;`, we can't say that
1702 // `ref` is initialized with `val`, rather refers to `val`.
1704 // In order, to mitigate situations like this, we check if the last
1705 // stored value in that region is the value that we track.
1707 // TODO: support other situations better.
1708 if (const MemRegion
*Candidate
=
1709 getLocationRegionIfReference(InitE
, Succ
, false)) {
1710 const StoreManager
&SM
= BRC
.getStateManager().getStoreManager();
1712 // Here we traverse the graph up to find the last node where the
1713 // candidate region is still in the store.
1714 for (const ExplodedNode
*N
= StoreSite
; N
; N
= N
->getFirstPred()) {
1715 if (SM
.includedInBindings(N
->getState()->getStore(), Candidate
)) {
1716 // And if it was bound to the target value, we can use it.
1717 if (N
->getState()->getSVal(Candidate
) == V
) {
1718 OldRegion
= Candidate
;
1726 // Otherwise, if the current region does indeed contain the value
1727 // we are looking for, we can look for a region where this value
1730 // It can be useful for situations like:
1731 // new = identity(old)
1732 // where the analyzer knows that 'identity' returns the value of its
1735 // NOTE: If the region R is not a simple var region, it can contain
1736 // V in one of its subregions.
1737 if (!OldRegion
&& StoreSite
->getState()->getSVal(R
) == V
) {
1738 // Let's go up the graph to find the node where the region is
1740 const ExplodedNode
*NodeWithoutBinding
= StoreSite
->getFirstPred();
1742 NodeWithoutBinding
&& NodeWithoutBinding
->getState()->getSVal(R
) == V
;
1743 NodeWithoutBinding
= NodeWithoutBinding
->getFirstPred()) {
1746 if (NodeWithoutBinding
) {
1747 // Let's try to find a unique binding for the value in that node.
1748 // We want to use this to find unique bindings because of the following
1753 // Telling the user that the value of 'a' is assigned to 'c', while
1754 // correct, can be confusing.
1755 StoreManager::FindUniqueBinding
FB(V
.getAsLocSymbol());
1756 BRC
.getStateManager().iterBindings(NodeWithoutBinding
->getState(), FB
);
1758 OldRegion
= FB
.getRegion();
1762 if (Options
.Kind
== TrackingKind::Condition
&& OriginSFC
&&
1763 !OriginSFC
->isParentOf(StoreSite
->getStackFrame()))
1766 // Okay, we've found the binding. Emit an appropriate message.
1767 SmallString
<256> sbuf
;
1768 llvm::raw_svector_ostream
os(sbuf
);
1770 StoreInfo SI
= {StoreInfo::Assignment
, // default kind
1777 if (std::optional
<PostStmt
> PS
= StoreSite
->getLocationAs
<PostStmt
>()) {
1778 const Stmt
*S
= PS
->getStmt();
1779 const auto *DS
= dyn_cast
<DeclStmt
>(S
);
1780 const auto *VR
= dyn_cast
<VarRegion
>(R
);
1783 SI
.StoreKind
= StoreInfo::Initialization
;
1784 } else if (isa
<BlockExpr
>(S
)) {
1785 SI
.StoreKind
= StoreInfo::BlockCapture
;
1787 // See if we can get the BlockVarRegion.
1788 ProgramStateRef State
= StoreSite
->getState();
1789 SVal V
= StoreSite
->getSVal(S
);
1790 if (const auto *BDR
=
1791 dyn_cast_or_null
<BlockDataRegion
>(V
.getAsRegion())) {
1792 if (const VarRegion
*OriginalR
= BDR
->getOriginalRegion(VR
)) {
1793 getParentTracker().track(State
->getSVal(OriginalR
), OriginalR
,
1794 Options
, OriginSFC
);
1799 } else if (SI
.StoreSite
->getLocation().getAs
<CallEnter
>() &&
1800 isa
<VarRegion
>(SI
.Dest
)) {
1801 SI
.StoreKind
= StoreInfo::CallArgument
;
1804 return getParentTracker().handle(SI
, BRC
, Options
);
1807 //===----------------------------------------------------------------------===//
1808 // Implementation of TrackConstraintBRVisitor.
1809 //===----------------------------------------------------------------------===//
1811 void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID
&ID
) const {
1813 ID
.AddPointer(&tag
);
1814 ID
.AddString(Message
);
1815 ID
.AddBoolean(Assumption
);
1819 /// Return the tag associated with this visitor. This tag will be used
1820 /// to make all PathDiagnosticPieces created by this visitor.
1821 const char *TrackConstraintBRVisitor::getTag() {
1822 return "TrackConstraintBRVisitor";
1825 bool TrackConstraintBRVisitor::isZeroCheck() const {
1826 return !Assumption
&& Constraint
.getAs
<Loc
>();
1829 bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode
*N
) const {
1831 return N
->getState()->isNull(Constraint
).isUnderconstrained();
1832 return (bool)N
->getState()->assume(Constraint
, !Assumption
);
1835 PathDiagnosticPieceRef
TrackConstraintBRVisitor::VisitNode(
1836 const ExplodedNode
*N
, BugReporterContext
&BRC
, PathSensitiveBugReport
&) {
1837 const ExplodedNode
*PrevN
= N
->getFirstPred();
1841 // Start tracking after we see the first state in which the value is
1843 if (!IsTrackingTurnedOn
)
1844 if (!isUnderconstrained(N
))
1845 IsTrackingTurnedOn
= true;
1846 if (!IsTrackingTurnedOn
)
1849 // Check if in the previous state it was feasible for this constraint
1850 // to *not* be true.
1851 if (isUnderconstrained(PrevN
)) {
1854 // At this point, the negation of the constraint should be infeasible. If it
1855 // is feasible, make sure that the negation of the constrainti was
1856 // infeasible in the current state. If it is feasible, we somehow missed
1857 // the transition point.
1858 assert(!isUnderconstrained(N
));
1860 // Construct a new PathDiagnosticPiece.
1861 ProgramPoint P
= N
->getLocation();
1863 // If this node already have a specialized note, it's probably better
1864 // than our generic note.
1865 // FIXME: This only looks for note tags, not for other ways to add a note.
1866 if (isa_and_nonnull
<NoteTag
>(P
.getTag()))
1869 PathDiagnosticLocation L
=
1870 PathDiagnosticLocation::create(P
, BRC
.getSourceManager());
1874 auto X
= std::make_shared
<PathDiagnosticEventPiece
>(L
, Message
);
1875 X
->setTag(getTag());
1876 return std::move(X
);
1882 //===----------------------------------------------------------------------===//
1883 // Implementation of SuppressInlineDefensiveChecksVisitor.
1884 //===----------------------------------------------------------------------===//
1886 SuppressInlineDefensiveChecksVisitor::
1887 SuppressInlineDefensiveChecksVisitor(DefinedSVal Value
, const ExplodedNode
*N
)
1889 // Check if the visitor is disabled.
1890 AnalyzerOptions
&Options
= N
->getState()->getAnalysisManager().options
;
1891 if (!Options
.ShouldSuppressInlinedDefensiveChecks
)
1895 void SuppressInlineDefensiveChecksVisitor::Profile(
1896 llvm::FoldingSetNodeID
&ID
) const {
1902 const char *SuppressInlineDefensiveChecksVisitor::getTag() {
1903 return "IDCVisitor";
1906 PathDiagnosticPieceRef
1907 SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode
*Succ
,
1908 BugReporterContext
&BRC
,
1909 PathSensitiveBugReport
&BR
) {
1910 const ExplodedNode
*Pred
= Succ
->getFirstPred();
1914 // Start tracking after we see the first state in which the value is null.
1915 if (!IsTrackingTurnedOn
)
1916 if (Succ
->getState()->isNull(V
).isConstrainedTrue())
1917 IsTrackingTurnedOn
= true;
1918 if (!IsTrackingTurnedOn
)
1921 // Check if in the previous state it was feasible for this value
1922 // to *not* be null.
1923 if (!Pred
->getState()->isNull(V
).isConstrainedTrue() &&
1924 Succ
->getState()->isNull(V
).isConstrainedTrue()) {
1927 // Check if this is inlined defensive checks.
1928 const LocationContext
*CurLC
= Succ
->getLocationContext();
1929 const LocationContext
*ReportLC
= BR
.getErrorNode()->getLocationContext();
1930 if (CurLC
!= ReportLC
&& !CurLC
->isParentOf(ReportLC
)) {
1931 BR
.markInvalid("Suppress IDC", CurLC
);
1935 // Treat defensive checks in function-like macros as if they were an inlined
1936 // defensive check. If the bug location is not in a macro and the
1937 // terminator for the current location is in a macro then suppress the
1939 auto BugPoint
= BR
.getErrorNode()->getLocation().getAs
<StmtPoint
>();
1944 ProgramPoint CurPoint
= Succ
->getLocation();
1945 const Stmt
*CurTerminatorStmt
= nullptr;
1946 if (auto BE
= CurPoint
.getAs
<BlockEdge
>()) {
1947 CurTerminatorStmt
= BE
->getSrc()->getTerminator().getStmt();
1948 } else if (auto SP
= CurPoint
.getAs
<StmtPoint
>()) {
1949 const Stmt
*CurStmt
= SP
->getStmt();
1950 if (!CurStmt
->getBeginLoc().isMacroID())
1953 CFGStmtMap
*Map
= CurLC
->getAnalysisDeclContext()->getCFGStmtMap();
1954 CurTerminatorStmt
= Map
->getBlock(CurStmt
)->getTerminatorStmt();
1959 if (!CurTerminatorStmt
)
1962 SourceLocation TerminatorLoc
= CurTerminatorStmt
->getBeginLoc();
1963 if (TerminatorLoc
.isMacroID()) {
1964 SourceLocation BugLoc
= BugPoint
->getStmt()->getBeginLoc();
1966 // Suppress reports unless we are in that same macro.
1967 if (!BugLoc
.isMacroID() ||
1968 getMacroName(BugLoc
, BRC
) != getMacroName(TerminatorLoc
, BRC
)) {
1969 BR
.markInvalid("Suppress Macro IDC", CurLC
);
1977 //===----------------------------------------------------------------------===//
1978 // TrackControlDependencyCondBRVisitor.
1979 //===----------------------------------------------------------------------===//
1982 /// Tracks the expressions that are a control dependency of the node that was
1983 /// supplied to the constructor.
1990 /// An error is emitted at line 3. This visitor realizes that the branch
1991 /// on line 2 is a control dependency of line 3, and tracks it's condition via
1992 /// trackExpressionValue().
1993 class TrackControlDependencyCondBRVisitor final
1994 : public TrackingBugReporterVisitor
{
1995 const ExplodedNode
*Origin
;
1996 ControlDependencyCalculator ControlDeps
;
1997 llvm::SmallSet
<const CFGBlock
*, 32> VisitedBlocks
;
2000 TrackControlDependencyCondBRVisitor(TrackerRef ParentTracker
,
2001 const ExplodedNode
*O
)
2002 : TrackingBugReporterVisitor(ParentTracker
), Origin(O
),
2003 ControlDeps(&O
->getCFG()) {}
2005 void Profile(llvm::FoldingSetNodeID
&ID
) const override
{
2010 PathDiagnosticPieceRef
VisitNode(const ExplodedNode
*N
,
2011 BugReporterContext
&BRC
,
2012 PathSensitiveBugReport
&BR
) override
;
2014 } // end of anonymous namespace
2016 static std::shared_ptr
<PathDiagnosticEventPiece
>
2017 constructDebugPieceForTrackedCondition(const Expr
*Cond
,
2018 const ExplodedNode
*N
,
2019 BugReporterContext
&BRC
) {
2021 if (BRC
.getAnalyzerOptions().AnalysisDiagOpt
== PD_NONE
||
2022 !BRC
.getAnalyzerOptions().ShouldTrackConditionsDebug
)
2025 std::string ConditionText
= std::string(Lexer::getSourceText(
2026 CharSourceRange::getTokenRange(Cond
->getSourceRange()),
2027 BRC
.getSourceManager(), BRC
.getASTContext().getLangOpts()));
2029 return std::make_shared
<PathDiagnosticEventPiece
>(
2030 PathDiagnosticLocation::createBegin(
2031 Cond
, BRC
.getSourceManager(), N
->getLocationContext()),
2032 (Twine() + "Tracking condition '" + ConditionText
+ "'").str());
2035 static bool isAssertlikeBlock(const CFGBlock
*B
, ASTContext
&Context
) {
2036 if (B
->succ_size() != 2)
2039 const CFGBlock
*Then
= B
->succ_begin()->getReachableBlock();
2040 const CFGBlock
*Else
= (B
->succ_begin() + 1)->getReachableBlock();
2045 if (Then
->isInevitablySinking() != Else
->isInevitablySinking())
2048 // For the following condition the following CFG would be built:
2052 // [B1] -> [B2] -> [B3] -> [sink]
2053 // assert(A && B || C); \ \
2054 // -----------> [go on with the execution]
2056 // It so happens that CFGBlock::getTerminatorCondition returns 'A' for block
2057 // B1, 'A && B' for B2, and 'A && B || C' for B3. Let's check whether we
2058 // reached the end of the condition!
2059 if (const Stmt
*ElseCond
= Else
->getTerminatorCondition())
2060 if (const auto *BinOp
= dyn_cast
<BinaryOperator
>(ElseCond
))
2061 if (BinOp
->isLogicalOp())
2062 return isAssertlikeBlock(Else
, Context
);
2067 PathDiagnosticPieceRef
2068 TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode
*N
,
2069 BugReporterContext
&BRC
,
2070 PathSensitiveBugReport
&BR
) {
2071 // We can only reason about control dependencies within the same stack frame.
2072 if (Origin
->getStackFrame() != N
->getStackFrame())
2075 CFGBlock
*NB
= const_cast<CFGBlock
*>(N
->getCFGBlock());
2077 // Skip if we already inspected this block.
2078 if (!VisitedBlocks
.insert(NB
).second
)
2081 CFGBlock
*OriginB
= const_cast<CFGBlock
*>(Origin
->getCFGBlock());
2083 // TODO: Cache CFGBlocks for each ExplodedNode.
2084 if (!OriginB
|| !NB
)
2087 if (isAssertlikeBlock(NB
, BRC
.getASTContext()))
2090 if (ControlDeps
.isControlDependent(OriginB
, NB
)) {
2091 // We don't really want to explain for range loops. Evidence suggests that
2092 // the only thing that leads to is the addition of calls to operator!=.
2093 if (llvm::isa_and_nonnull
<CXXForRangeStmt
>(NB
->getTerminatorStmt()))
2096 if (const Expr
*Condition
= NB
->getLastCondition()) {
2098 // If we can't retrieve a sensible condition, just bail out.
2099 const Expr
*InnerExpr
= peelOffOuterExpr(Condition
, N
);
2103 // If the condition was a function call, we likely won't gain much from
2104 // tracking it either. Evidence suggests that it will mostly trigger in
2105 // scenarios like this:
2109 // if (alwaysTrue()) // We don't need a whole lot of explanation
2110 // // here, the function name is good enough.
2114 // Its easy to create a counterexample where this heuristic would make us
2115 // lose valuable information, but we've never really seen one in practice.
2116 if (isa
<CallExpr
>(InnerExpr
))
2119 // Keeping track of the already tracked conditions on a visitor level
2120 // isn't sufficient, because a new visitor is created for each tracked
2121 // expression, hence the BugReport level set.
2122 if (BR
.addTrackedCondition(N
)) {
2123 getParentTracker().track(InnerExpr
, N
,
2124 {bugreporter::TrackingKind::Condition
,
2125 /*EnableNullFPSuppression=*/false});
2126 return constructDebugPieceForTrackedCondition(Condition
, N
, BRC
);
2134 //===----------------------------------------------------------------------===//
2135 // Implementation of trackExpressionValue.
2136 //===----------------------------------------------------------------------===//
2138 static const Expr
*peelOffOuterExpr(const Expr
*Ex
, const ExplodedNode
*N
) {
2140 Ex
= Ex
->IgnoreParenCasts();
2141 if (const auto *FE
= dyn_cast
<FullExpr
>(Ex
))
2142 return peelOffOuterExpr(FE
->getSubExpr(), N
);
2143 if (const auto *OVE
= dyn_cast
<OpaqueValueExpr
>(Ex
))
2144 return peelOffOuterExpr(OVE
->getSourceExpr(), N
);
2145 if (const auto *POE
= dyn_cast
<PseudoObjectExpr
>(Ex
)) {
2146 const auto *PropRef
= dyn_cast
<ObjCPropertyRefExpr
>(POE
->getSyntacticForm());
2147 if (PropRef
&& PropRef
->isMessagingGetter()) {
2148 const Expr
*GetterMessageSend
=
2149 POE
->getSemanticExpr(POE
->getNumSemanticExprs() - 1);
2150 assert(isa
<ObjCMessageExpr
>(GetterMessageSend
->IgnoreParenCasts()));
2151 return peelOffOuterExpr(GetterMessageSend
, N
);
2155 // Peel off the ternary operator.
2156 if (const auto *CO
= dyn_cast
<ConditionalOperator
>(Ex
)) {
2157 // Find a node where the branching occurred and find out which branch
2158 // we took (true/false) by looking at the ExplodedGraph.
2159 const ExplodedNode
*NI
= N
;
2161 ProgramPoint ProgPoint
= NI
->getLocation();
2162 if (std::optional
<BlockEdge
> BE
= ProgPoint
.getAs
<BlockEdge
>()) {
2163 const CFGBlock
*srcBlk
= BE
->getSrc();
2164 if (const Stmt
*term
= srcBlk
->getTerminatorStmt()) {
2166 bool TookTrueBranch
= (*(srcBlk
->succ_begin()) == BE
->getDst());
2168 return peelOffOuterExpr(CO
->getTrueExpr(), N
);
2170 return peelOffOuterExpr(CO
->getFalseExpr(), N
);
2174 NI
= NI
->getFirstPred();
2178 if (auto *BO
= dyn_cast
<BinaryOperator
>(Ex
))
2179 if (const Expr
*SubEx
= peelOffPointerArithmetic(BO
))
2180 return peelOffOuterExpr(SubEx
, N
);
2182 if (auto *UO
= dyn_cast
<UnaryOperator
>(Ex
)) {
2183 if (UO
->getOpcode() == UO_LNot
)
2184 return peelOffOuterExpr(UO
->getSubExpr(), N
);
2186 // FIXME: There's a hack in our Store implementation that always computes
2187 // field offsets around null pointers as if they are always equal to 0.
2188 // The idea here is to report accesses to fields as null dereferences
2189 // even though the pointer value that's being dereferenced is actually
2190 // the offset of the field rather than exactly 0.
2191 // See the FIXME in StoreManager's getLValueFieldOrIvar() method.
2192 // This code interacts heavily with this hack; otherwise the value
2193 // would not be null at all for most fields, so we'd be unable to track it.
2194 if (UO
->getOpcode() == UO_AddrOf
&& UO
->getSubExpr()->isLValue())
2195 if (const Expr
*DerefEx
= bugreporter::getDerefExpr(UO
->getSubExpr()))
2196 return peelOffOuterExpr(DerefEx
, N
);
2202 /// Find the ExplodedNode where the lvalue (the value of 'Ex')
2204 static const ExplodedNode
* findNodeForExpression(const ExplodedNode
*N
,
2205 const Expr
*Inner
) {
2207 if (N
->getStmtForDiagnostics() == Inner
)
2209 N
= N
->getFirstPred();
2214 //===----------------------------------------------------------------------===//
2215 // Tracker implementation
2216 //===----------------------------------------------------------------------===//
2218 PathDiagnosticPieceRef
StoreHandler::constructNote(StoreInfo SI
,
2219 BugReporterContext
&BRC
,
2220 StringRef NodeText
) {
2221 // Construct a new PathDiagnosticPiece.
2222 ProgramPoint P
= SI
.StoreSite
->getLocation();
2223 PathDiagnosticLocation L
;
2224 if (P
.getAs
<CallEnter
>() && SI
.SourceOfTheValue
)
2225 L
= PathDiagnosticLocation(SI
.SourceOfTheValue
, BRC
.getSourceManager(),
2226 P
.getLocationContext());
2228 if (!L
.isValid() || !L
.asLocation().isValid())
2229 L
= PathDiagnosticLocation::create(P
, BRC
.getSourceManager());
2231 if (!L
.isValid() || !L
.asLocation().isValid())
2234 return std::make_shared
<PathDiagnosticEventPiece
>(L
, NodeText
);
2238 class DefaultStoreHandler final
: public StoreHandler
{
2240 using StoreHandler::StoreHandler
;
2242 PathDiagnosticPieceRef
handle(StoreInfo SI
, BugReporterContext
&BRC
,
2243 TrackingOptions Opts
) override
{
2244 // Okay, we've found the binding. Emit an appropriate message.
2245 SmallString
<256> Buffer
;
2246 llvm::raw_svector_ostream
OS(Buffer
);
2248 switch (SI
.StoreKind
) {
2249 case StoreInfo::Initialization
:
2250 case StoreInfo::BlockCapture
:
2251 showBRDiagnostics(OS
, SI
);
2253 case StoreInfo::CallArgument
:
2254 showBRParamDiagnostics(OS
, SI
);
2256 case StoreInfo::Assignment
:
2257 showBRDefaultDiagnostics(OS
, SI
);
2261 if (Opts
.Kind
== bugreporter::TrackingKind::Condition
)
2262 OS
<< WillBeUsedForACondition
;
2264 return constructNote(SI
, BRC
, OS
.str());
2268 class ControlDependencyHandler final
: public ExpressionHandler
{
2270 using ExpressionHandler::ExpressionHandler
;
2272 Tracker::Result
handle(const Expr
*Inner
, const ExplodedNode
*InputNode
,
2273 const ExplodedNode
*LVNode
,
2274 TrackingOptions Opts
) override
{
2275 PathSensitiveBugReport
&Report
= getParentTracker().getReport();
2277 // We only track expressions if we believe that they are important. Chances
2278 // are good that control dependencies to the tracking point are also
2279 // important because of this, let's explain why we believe control reached
2281 // TODO: Shouldn't we track control dependencies of every bug location,
2282 // rather than only tracked expressions?
2283 if (LVNode
->getState()
2284 ->getAnalysisManager()
2285 .getAnalyzerOptions()
2286 .ShouldTrackConditions
) {
2287 Report
.addVisitor
<TrackControlDependencyCondBRVisitor
>(
2288 &getParentTracker(), InputNode
);
2289 return {/*FoundSomethingToTrack=*/true};
2296 class NilReceiverHandler final
: public ExpressionHandler
{
2298 using ExpressionHandler::ExpressionHandler
;
2300 Tracker::Result
handle(const Expr
*Inner
, const ExplodedNode
*InputNode
,
2301 const ExplodedNode
*LVNode
,
2302 TrackingOptions Opts
) override
{
2303 // The message send could be nil due to the receiver being nil.
2304 // At this point in the path, the receiver should be live since we are at
2305 // the message send expr. If it is nil, start tracking it.
2306 if (const Expr
*Receiver
=
2307 NilReceiverBRVisitor::getNilReceiver(Inner
, LVNode
))
2308 return getParentTracker().track(Receiver
, LVNode
, Opts
);
2314 class ArrayIndexHandler final
: public ExpressionHandler
{
2316 using ExpressionHandler::ExpressionHandler
;
2318 Tracker::Result
handle(const Expr
*Inner
, const ExplodedNode
*InputNode
,
2319 const ExplodedNode
*LVNode
,
2320 TrackingOptions Opts
) override
{
2321 // Track the index if this is an array subscript.
2322 if (const auto *Arr
= dyn_cast
<ArraySubscriptExpr
>(Inner
))
2323 return getParentTracker().track(
2324 Arr
->getIdx(), LVNode
,
2325 {Opts
.Kind
, /*EnableNullFPSuppression*/ false});
2331 // TODO: extract it into more handlers
2332 class InterestingLValueHandler final
: public ExpressionHandler
{
2334 using ExpressionHandler::ExpressionHandler
;
2336 Tracker::Result
handle(const Expr
*Inner
, const ExplodedNode
*InputNode
,
2337 const ExplodedNode
*LVNode
,
2338 TrackingOptions Opts
) override
{
2339 ProgramStateRef LVState
= LVNode
->getState();
2340 const StackFrameContext
*SFC
= LVNode
->getStackFrame();
2341 PathSensitiveBugReport
&Report
= getParentTracker().getReport();
2342 Tracker::Result Result
;
2344 // See if the expression we're interested refers to a variable.
2345 // If so, we can track both its contents and constraints on its value.
2346 if (ExplodedGraph::isInterestingLValueExpr(Inner
)) {
2347 SVal LVal
= LVNode
->getSVal(Inner
);
2349 const MemRegion
*RR
= getLocationRegionIfReference(Inner
, LVNode
);
2350 bool LVIsNull
= LVState
->isNull(LVal
).isConstrainedTrue();
2352 // If this is a C++ reference to a null pointer, we are tracking the
2353 // pointer. In addition, we should find the store at which the reference
2355 if (RR
&& !LVIsNull
)
2356 Result
.combineWith(getParentTracker().track(LVal
, RR
, Opts
, SFC
));
2358 // In case of C++ references, we want to differentiate between a null
2359 // reference and reference to null pointer.
2360 // If the LVal is null, check if we are dealing with null reference.
2361 // For those, we want to track the location of the reference.
2362 const MemRegion
*R
=
2363 (RR
&& LVIsNull
) ? RR
: LVNode
->getSVal(Inner
).getAsRegion();
2367 // Mark both the variable region and its contents as interesting.
2368 SVal V
= LVState
->getRawSVal(loc::MemRegionVal(R
));
2369 Report
.addVisitor
<NoStoreFuncVisitor
>(cast
<SubRegion
>(R
), Opts
.Kind
);
2371 // When we got here, we do have something to track, and we will
2373 Result
.FoundSomethingToTrack
= true;
2374 Result
.WasInterrupted
= true;
2376 MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
2377 LVNode
, R
, Opts
.EnableNullFPSuppression
, Report
, V
);
2379 Report
.markInteresting(V
, Opts
.Kind
);
2380 Report
.addVisitor
<UndefOrNullArgVisitor
>(R
);
2382 // If the contents are symbolic and null, find out when they became
2384 if (V
.getAsLocSymbol(/*IncludeBaseRegions=*/true))
2385 if (LVState
->isNull(V
).isConstrainedTrue())
2386 Report
.addVisitor
<TrackConstraintBRVisitor
>(
2387 V
.castAs
<DefinedSVal
>(),
2388 /*Assumption=*/false, "Assuming pointer value is null");
2390 // Add visitor, which will suppress inline defensive checks.
2391 if (auto DV
= V
.getAs
<DefinedSVal
>())
2392 if (!DV
->isZeroConstant() && Opts
.EnableNullFPSuppression
)
2393 // Note that LVNode may be too late (i.e., too far from the
2394 // InputNode) because the lvalue may have been computed before the
2395 // inlined call was evaluated. InputNode may as well be too early
2396 // here, because the symbol is already dead; this, however, is fine
2397 // because we can still find the node in which it collapsed to null
2399 Report
.addVisitor
<SuppressInlineDefensiveChecksVisitor
>(*DV
,
2401 getParentTracker().track(V
, R
, Opts
, SFC
);
2409 /// Adds a ReturnVisitor if the given statement represents a call that was
2412 /// This will search back through the ExplodedGraph, starting from the given
2413 /// node, looking for when the given statement was processed. If it turns out
2414 /// the statement is a call that was inlined, we add the visitor to the
2415 /// bug report, so it can print a note later.
2416 class InlinedFunctionCallHandler final
: public ExpressionHandler
{
2417 using ExpressionHandler::ExpressionHandler
;
2419 Tracker::Result
handle(const Expr
*E
, const ExplodedNode
*InputNode
,
2420 const ExplodedNode
*ExprNode
,
2421 TrackingOptions Opts
) override
{
2422 if (!CallEvent::isCallStmt(E
))
2425 // First, find when we processed the statement.
2426 // If we work with a 'CXXNewExpr' that is going to be purged away before
2427 // its call take place. We would catch that purge in the last condition
2428 // as a 'StmtPoint' so we have to bypass it.
2429 const bool BypassCXXNewExprEval
= isa
<CXXNewExpr
>(E
);
2431 // This is moving forward when we enter into another context.
2432 const StackFrameContext
*CurrentSFC
= ExprNode
->getStackFrame();
2435 // If that is satisfied we found our statement as an inlined call.
2436 if (std::optional
<CallExitEnd
> CEE
=
2437 ExprNode
->getLocationAs
<CallExitEnd
>())
2438 if (CEE
->getCalleeContext()->getCallSite() == E
)
2441 // Try to move forward to the end of the call-chain.
2442 ExprNode
= ExprNode
->getFirstPred();
2446 const StackFrameContext
*PredSFC
= ExprNode
->getStackFrame();
2448 // If that is satisfied we found our statement.
2449 // FIXME: This code currently bypasses the call site for the
2450 // conservatively evaluated allocator.
2451 if (!BypassCXXNewExprEval
)
2452 if (std::optional
<StmtPoint
> SP
= ExprNode
->getLocationAs
<StmtPoint
>())
2453 // See if we do not enter into another context.
2454 if (SP
->getStmt() == E
&& CurrentSFC
== PredSFC
)
2457 CurrentSFC
= PredSFC
;
2458 } while (ExprNode
->getStackFrame() == CurrentSFC
);
2460 // Next, step over any post-statement checks.
2461 while (ExprNode
&& ExprNode
->getLocation().getAs
<PostStmt
>())
2462 ExprNode
= ExprNode
->getFirstPred();
2466 // Finally, see if we inlined the call.
2467 std::optional
<CallExitEnd
> CEE
= ExprNode
->getLocationAs
<CallExitEnd
>();
2471 const StackFrameContext
*CalleeContext
= CEE
->getCalleeContext();
2472 if (CalleeContext
->getCallSite() != E
)
2475 // Check the return value.
2476 ProgramStateRef State
= ExprNode
->getState();
2477 SVal RetVal
= ExprNode
->getSVal(E
);
2479 // Handle cases where a reference is returned and then immediately used.
2480 if (cast
<Expr
>(E
)->isGLValue())
2481 if (std::optional
<Loc
> LValue
= RetVal
.getAs
<Loc
>())
2482 RetVal
= State
->getSVal(*LValue
);
2484 // See if the return value is NULL. If so, suppress the report.
2485 AnalyzerOptions
&Options
= State
->getAnalysisManager().options
;
2487 bool EnableNullFPSuppression
= false;
2488 if (Opts
.EnableNullFPSuppression
&& Options
.ShouldSuppressNullReturnPaths
)
2489 if (std::optional
<Loc
> RetLoc
= RetVal
.getAs
<Loc
>())
2490 EnableNullFPSuppression
= State
->isNull(*RetLoc
).isConstrainedTrue();
2492 PathSensitiveBugReport
&Report
= getParentTracker().getReport();
2493 Report
.addVisitor
<ReturnVisitor
>(&getParentTracker(), CalleeContext
,
2494 EnableNullFPSuppression
, Options
,
2500 class DefaultExpressionHandler final
: public ExpressionHandler
{
2502 using ExpressionHandler::ExpressionHandler
;
2504 Tracker::Result
handle(const Expr
*Inner
, const ExplodedNode
*InputNode
,
2505 const ExplodedNode
*LVNode
,
2506 TrackingOptions Opts
) override
{
2507 ProgramStateRef LVState
= LVNode
->getState();
2508 const StackFrameContext
*SFC
= LVNode
->getStackFrame();
2509 PathSensitiveBugReport
&Report
= getParentTracker().getReport();
2510 Tracker::Result Result
;
2512 // If the expression is not an "lvalue expression", we can still
2513 // track the constraints on its contents.
2514 SVal V
= LVState
->getSValAsScalarOrLoc(Inner
, LVNode
->getLocationContext());
2516 // Is it a symbolic value?
2517 if (auto L
= V
.getAs
<loc::MemRegionVal
>()) {
2518 // FIXME: this is a hack for fixing a later crash when attempting to
2519 // dereference a void* pointer.
2520 // We should not try to dereference pointers at all when we don't care
2521 // what is written inside the pointer.
2522 bool CanDereference
= true;
2523 if (const auto *SR
= L
->getRegionAs
<SymbolicRegion
>()) {
2524 if (SR
->getPointeeStaticType()->isVoidType())
2525 CanDereference
= false;
2526 } else if (L
->getRegionAs
<AllocaRegion
>())
2527 CanDereference
= false;
2529 // At this point we are dealing with the region's LValue.
2530 // However, if the rvalue is a symbolic region, we should track it as
2531 // well. Try to use the correct type when looking up the value.
2533 if (ExplodedGraph::isInterestingLValueExpr(Inner
))
2534 RVal
= LVState
->getRawSVal(*L
, Inner
->getType());
2535 else if (CanDereference
)
2536 RVal
= LVState
->getSVal(L
->getRegion());
2538 if (CanDereference
) {
2539 Report
.addVisitor
<UndefOrNullArgVisitor
>(L
->getRegion());
2540 Result
.FoundSomethingToTrack
= true;
2542 if (auto KV
= RVal
.getAs
<KnownSVal
>())
2544 getParentTracker().track(*KV
, L
->getRegion(), Opts
, SFC
));
2547 const MemRegion
*RegionRVal
= RVal
.getAsRegion();
2548 if (isa_and_nonnull
<SymbolicRegion
>(RegionRVal
)) {
2549 Report
.markInteresting(RegionRVal
, Opts
.Kind
);
2550 Report
.addVisitor
<TrackConstraintBRVisitor
>(
2551 loc::MemRegionVal(RegionRVal
),
2552 /*Assumption=*/false, "Assuming pointer value is null");
2553 Result
.FoundSomethingToTrack
= true;
2561 /// Attempts to add visitors to track an RValue expression back to its point of
2563 class PRValueHandler final
: public ExpressionHandler
{
2565 using ExpressionHandler::ExpressionHandler
;
2567 Tracker::Result
handle(const Expr
*E
, const ExplodedNode
*InputNode
,
2568 const ExplodedNode
*ExprNode
,
2569 TrackingOptions Opts
) override
{
2570 if (!E
->isPRValue())
2573 const ExplodedNode
*RVNode
= findNodeForExpression(ExprNode
, E
);
2577 Tracker::Result CombinedResult
;
2578 Tracker
&Parent
= getParentTracker();
2580 const auto track
= [&CombinedResult
, &Parent
, ExprNode
,
2581 Opts
](const Expr
*Inner
) {
2582 CombinedResult
.combineWith(Parent
.track(Inner
, ExprNode
, Opts
));
2585 // FIXME: Initializer lists can appear in many different contexts
2586 // and most of them needs a special handling. For now let's handle
2587 // what we can. If the initializer list only has 1 element, we track
2589 // This snippet even handles nesting, e.g.: int *x{{{{{y}}}}};
2590 if (const auto *ILE
= dyn_cast
<InitListExpr
>(E
)) {
2591 if (ILE
->getNumInits() == 1) {
2592 track(ILE
->getInit(0));
2594 return CombinedResult
;
2600 ProgramStateRef RVState
= RVNode
->getState();
2601 SVal V
= RVState
->getSValAsScalarOrLoc(E
, RVNode
->getLocationContext());
2602 const auto *BO
= dyn_cast
<BinaryOperator
>(E
);
2604 if (!BO
|| !BO
->isMultiplicativeOp() || !V
.isZeroConstant())
2607 SVal RHSV
= RVState
->getSVal(BO
->getRHS(), RVNode
->getLocationContext());
2608 SVal LHSV
= RVState
->getSVal(BO
->getLHS(), RVNode
->getLocationContext());
2610 // Track both LHS and RHS of a multiplication.
2611 if (BO
->getOpcode() == BO_Mul
) {
2612 if (LHSV
.isZeroConstant())
2613 track(BO
->getLHS());
2614 if (RHSV
.isZeroConstant())
2615 track(BO
->getRHS());
2616 } else { // Track only the LHS of a division or a modulo.
2617 if (LHSV
.isZeroConstant())
2618 track(BO
->getLHS());
2621 return CombinedResult
;
2626 Tracker::Tracker(PathSensitiveBugReport
&Report
) : Report(Report
) {
2627 // Default expression handlers.
2628 addLowPriorityHandler
<ControlDependencyHandler
>();
2629 addLowPriorityHandler
<NilReceiverHandler
>();
2630 addLowPriorityHandler
<ArrayIndexHandler
>();
2631 addLowPriorityHandler
<InterestingLValueHandler
>();
2632 addLowPriorityHandler
<InlinedFunctionCallHandler
>();
2633 addLowPriorityHandler
<DefaultExpressionHandler
>();
2634 addLowPriorityHandler
<PRValueHandler
>();
2635 // Default store handlers.
2636 addHighPriorityHandler
<DefaultStoreHandler
>();
2639 Tracker::Result
Tracker::track(const Expr
*E
, const ExplodedNode
*N
,
2640 TrackingOptions Opts
) {
2644 const Expr
*Inner
= peelOffOuterExpr(E
, N
);
2645 const ExplodedNode
*LVNode
= findNodeForExpression(N
, Inner
);
2649 Result CombinedResult
;
2650 // Iterate through the handlers in the order according to their priorities.
2651 for (ExpressionHandlerPtr
&Handler
: ExpressionHandlers
) {
2652 CombinedResult
.combineWith(Handler
->handle(Inner
, N
, LVNode
, Opts
));
2653 if (CombinedResult
.WasInterrupted
) {
2654 // There is no need to confuse our users here.
2655 // We got interrupted, but our users don't need to know about it.
2656 CombinedResult
.WasInterrupted
= false;
2661 return CombinedResult
;
2664 Tracker::Result
Tracker::track(SVal V
, const MemRegion
*R
, TrackingOptions Opts
,
2665 const StackFrameContext
*Origin
) {
2666 if (auto KV
= V
.getAs
<KnownSVal
>()) {
2667 Report
.addVisitor
<StoreSiteFinder
>(this, *KV
, R
, Opts
, Origin
);
2673 PathDiagnosticPieceRef
Tracker::handle(StoreInfo SI
, BugReporterContext
&BRC
,
2674 TrackingOptions Opts
) {
2675 // Iterate through the handlers in the order according to their priorities.
2676 for (StoreHandlerPtr
&Handler
: StoreHandlers
) {
2677 if (PathDiagnosticPieceRef Result
= Handler
->handle(SI
, BRC
, Opts
))
2678 // If the handler produced a non-null piece, return it.
2679 // There is no need in asking other handlers.
2685 bool bugreporter::trackExpressionValue(const ExplodedNode
*InputNode
,
2688 PathSensitiveBugReport
&Report
,
2689 TrackingOptions Opts
) {
2690 return Tracker::create(Report
)
2691 ->track(E
, InputNode
, Opts
)
2692 .FoundSomethingToTrack
;
2695 void bugreporter::trackStoredValue(KnownSVal V
, const MemRegion
*R
,
2696 PathSensitiveBugReport
&Report
,
2697 TrackingOptions Opts
,
2698 const StackFrameContext
*Origin
) {
2699 Tracker::create(Report
)->track(V
, R
, Opts
, Origin
);
2702 //===----------------------------------------------------------------------===//
2703 // Implementation of NulReceiverBRVisitor.
2704 //===----------------------------------------------------------------------===//
2706 const Expr
*NilReceiverBRVisitor::getNilReceiver(const Stmt
*S
,
2707 const ExplodedNode
*N
) {
2708 const auto *ME
= dyn_cast
<ObjCMessageExpr
>(S
);
2711 if (const Expr
*Receiver
= ME
->getInstanceReceiver()) {
2712 ProgramStateRef state
= N
->getState();
2713 SVal V
= N
->getSVal(Receiver
);
2714 if (state
->isNull(V
).isConstrainedTrue())
2720 PathDiagnosticPieceRef
2721 NilReceiverBRVisitor::VisitNode(const ExplodedNode
*N
, BugReporterContext
&BRC
,
2722 PathSensitiveBugReport
&BR
) {
2723 std::optional
<PreStmt
> P
= N
->getLocationAs
<PreStmt
>();
2727 const Stmt
*S
= P
->getStmt();
2728 const Expr
*Receiver
= getNilReceiver(S
, N
);
2732 llvm::SmallString
<256> Buf
;
2733 llvm::raw_svector_ostream
OS(Buf
);
2735 if (const auto *ME
= dyn_cast
<ObjCMessageExpr
>(S
)) {
2737 ME
->getSelector().print(OS
);
2738 OS
<< "' not called";
2741 OS
<< "No method is called";
2743 OS
<< " because the receiver is nil";
2745 // The receiver was nil, and hence the method was skipped.
2746 // Register a BugReporterVisitor to issue a message telling us how
2747 // the receiver was null.
2748 bugreporter::trackExpressionValue(N
, Receiver
, BR
,
2749 {bugreporter::TrackingKind::Thorough
,
2750 /*EnableNullFPSuppression*/ false});
2751 // Issue a message saying that the method was skipped.
2752 PathDiagnosticLocation
L(Receiver
, BRC
.getSourceManager(),
2753 N
->getLocationContext());
2754 return std::make_shared
<PathDiagnosticEventPiece
>(L
, OS
.str());
2757 //===----------------------------------------------------------------------===//
2758 // Visitor that tries to report interesting diagnostics from conditions.
2759 //===----------------------------------------------------------------------===//
2761 /// Return the tag associated with this visitor. This tag will be used
2762 /// to make all PathDiagnosticPieces created by this visitor.
2763 const char *ConditionBRVisitor::getTag() { return "ConditionBRVisitor"; }
2765 PathDiagnosticPieceRef
2766 ConditionBRVisitor::VisitNode(const ExplodedNode
*N
, BugReporterContext
&BRC
,
2767 PathSensitiveBugReport
&BR
) {
2768 auto piece
= VisitNodeImpl(N
, BRC
, BR
);
2770 piece
->setTag(getTag());
2771 if (auto *ev
= dyn_cast
<PathDiagnosticEventPiece
>(piece
.get()))
2772 ev
->setPrunable(true, /* override */ false);
2777 PathDiagnosticPieceRef
2778 ConditionBRVisitor::VisitNodeImpl(const ExplodedNode
*N
,
2779 BugReporterContext
&BRC
,
2780 PathSensitiveBugReport
&BR
) {
2781 ProgramPoint ProgPoint
= N
->getLocation();
2782 const std::pair
<const ProgramPointTag
*, const ProgramPointTag
*> &Tags
=
2783 ExprEngine::geteagerlyAssumeBinOpBifurcationTags();
2785 // If an assumption was made on a branch, it should be caught
2786 // here by looking at the state transition.
2787 if (std::optional
<BlockEdge
> BE
= ProgPoint
.getAs
<BlockEdge
>()) {
2788 const CFGBlock
*SrcBlock
= BE
->getSrc();
2789 if (const Stmt
*Term
= SrcBlock
->getTerminatorStmt()) {
2790 // If the tag of the previous node is 'Eagerly Assume...' the current
2791 // 'BlockEdge' has the same constraint information. We do not want to
2792 // report the value as it is just an assumption on the predecessor node
2793 // which will be caught in the next VisitNode() iteration as a 'PostStmt'.
2794 const ProgramPointTag
*PreviousNodeTag
=
2795 N
->getFirstPred()->getLocation().getTag();
2796 if (PreviousNodeTag
== Tags
.first
|| PreviousNodeTag
== Tags
.second
)
2799 return VisitTerminator(Term
, N
, SrcBlock
, BE
->getDst(), BR
, BRC
);
2804 if (std::optional
<PostStmt
> PS
= ProgPoint
.getAs
<PostStmt
>()) {
2805 const ProgramPointTag
*CurrentNodeTag
= PS
->getTag();
2806 if (CurrentNodeTag
!= Tags
.first
&& CurrentNodeTag
!= Tags
.second
)
2809 bool TookTrue
= CurrentNodeTag
== Tags
.first
;
2810 return VisitTrueTest(cast
<Expr
>(PS
->getStmt()), BRC
, BR
, N
, TookTrue
);
2816 PathDiagnosticPieceRef
ConditionBRVisitor::VisitTerminator(
2817 const Stmt
*Term
, const ExplodedNode
*N
, const CFGBlock
*srcBlk
,
2818 const CFGBlock
*dstBlk
, PathSensitiveBugReport
&R
,
2819 BugReporterContext
&BRC
) {
2820 const Expr
*Cond
= nullptr;
2822 // In the code below, Term is a CFG terminator and Cond is a branch condition
2823 // expression upon which the decision is made on this terminator.
2825 // For example, in "if (x == 0)", the "if (x == 0)" statement is a terminator,
2826 // and "x == 0" is the respective condition.
2828 // Another example: in "if (x && y)", we've got two terminators and two
2829 // conditions due to short-circuit nature of operator "&&":
2830 // 1. The "if (x && y)" statement is a terminator,
2831 // and "y" is the respective condition.
2832 // 2. Also "x && ..." is another terminator,
2833 // and "x" is its condition.
2835 switch (Term
->getStmtClass()) {
2836 // FIXME: Stmt::SwitchStmtClass is worth handling, however it is a bit
2837 // more tricky because there are more than two branches to account for.
2840 case Stmt::IfStmtClass
:
2841 Cond
= cast
<IfStmt
>(Term
)->getCond();
2843 case Stmt::ConditionalOperatorClass
:
2844 Cond
= cast
<ConditionalOperator
>(Term
)->getCond();
2846 case Stmt::BinaryOperatorClass
:
2847 // When we encounter a logical operator (&& or ||) as a CFG terminator,
2848 // then the condition is actually its LHS; otherwise, we'd encounter
2849 // the parent, such as if-statement, as a terminator.
2850 const auto *BO
= cast
<BinaryOperator
>(Term
);
2851 assert(BO
->isLogicalOp() &&
2852 "CFG terminator is not a short-circuit operator!");
2853 Cond
= BO
->getLHS();
2857 Cond
= Cond
->IgnoreParens();
2859 // However, when we encounter a logical operator as a branch condition,
2860 // then the condition is actually its RHS, because LHS would be
2861 // the condition for the logical operator terminator.
2862 while (const auto *InnerBO
= dyn_cast
<BinaryOperator
>(Cond
)) {
2863 if (!InnerBO
->isLogicalOp())
2865 Cond
= InnerBO
->getRHS()->IgnoreParens();
2869 assert(srcBlk
->succ_size() == 2);
2870 const bool TookTrue
= *(srcBlk
->succ_begin()) == dstBlk
;
2871 return VisitTrueTest(Cond
, BRC
, R
, N
, TookTrue
);
2874 PathDiagnosticPieceRef
2875 ConditionBRVisitor::VisitTrueTest(const Expr
*Cond
, BugReporterContext
&BRC
,
2876 PathSensitiveBugReport
&R
,
2877 const ExplodedNode
*N
, bool TookTrue
) {
2878 ProgramStateRef CurrentState
= N
->getState();
2879 ProgramStateRef PrevState
= N
->getFirstPred()->getState();
2880 const LocationContext
*LCtx
= N
->getLocationContext();
2882 // If the constraint information is changed between the current and the
2883 // previous program state we assuming the newly seen constraint information.
2884 // If we cannot evaluate the condition (and the constraints are the same)
2885 // the analyzer has no information about the value and just assuming it.
2887 !BRC
.getStateManager().haveEqualConstraints(CurrentState
, PrevState
) ||
2888 CurrentState
->getSVal(Cond
, LCtx
).isUnknownOrUndef();
2890 // These will be modified in code below, but we need to preserve the original
2891 // values in case we want to throw the generic message.
2892 const Expr
*CondTmp
= Cond
;
2893 bool TookTrueTmp
= TookTrue
;
2896 CondTmp
= CondTmp
->IgnoreParenCasts();
2897 switch (CondTmp
->getStmtClass()) {
2900 case Stmt::BinaryOperatorClass
:
2901 if (auto P
= VisitTrueTest(Cond
, cast
<BinaryOperator
>(CondTmp
),
2902 BRC
, R
, N
, TookTrueTmp
, IsAssuming
))
2905 case Stmt::DeclRefExprClass
:
2906 if (auto P
= VisitTrueTest(Cond
, cast
<DeclRefExpr
>(CondTmp
),
2907 BRC
, R
, N
, TookTrueTmp
, IsAssuming
))
2910 case Stmt::MemberExprClass
:
2911 if (auto P
= VisitTrueTest(Cond
, cast
<MemberExpr
>(CondTmp
),
2912 BRC
, R
, N
, TookTrueTmp
, IsAssuming
))
2915 case Stmt::UnaryOperatorClass
: {
2916 const auto *UO
= cast
<UnaryOperator
>(CondTmp
);
2917 if (UO
->getOpcode() == UO_LNot
) {
2918 TookTrueTmp
= !TookTrueTmp
;
2919 CondTmp
= UO
->getSubExpr();
2928 // Condition too complex to explain? Just say something so that the user
2929 // knew we've made some path decision at this point.
2930 // If it is too complex and we know the evaluation of the condition do not
2931 // repeat the note from 'BugReporter.cpp'
2935 PathDiagnosticLocation
Loc(Cond
, BRC
.getSourceManager(), LCtx
);
2936 if (!Loc
.isValid() || !Loc
.asLocation().isValid())
2939 return std::make_shared
<PathDiagnosticEventPiece
>(
2940 Loc
, TookTrue
? GenericTrueMessage
: GenericFalseMessage
);
2943 bool ConditionBRVisitor::patternMatch(const Expr
*Ex
, const Expr
*ParentEx
,
2944 raw_ostream
&Out
, BugReporterContext
&BRC
,
2945 PathSensitiveBugReport
&report
,
2946 const ExplodedNode
*N
,
2947 std::optional
<bool> &prunable
,
2948 bool IsSameFieldName
) {
2949 const Expr
*OriginalExpr
= Ex
;
2950 Ex
= Ex
->IgnoreParenCasts();
2952 if (isa
<GNUNullExpr
, ObjCBoolLiteralExpr
, CXXBoolLiteralExpr
, IntegerLiteral
,
2953 FloatingLiteral
>(Ex
)) {
2954 // Use heuristics to determine if the expression is a macro
2955 // expanding to a literal and if so, use the macro's name.
2956 SourceLocation BeginLoc
= OriginalExpr
->getBeginLoc();
2957 SourceLocation EndLoc
= OriginalExpr
->getEndLoc();
2958 if (BeginLoc
.isMacroID() && EndLoc
.isMacroID()) {
2959 const SourceManager
&SM
= BRC
.getSourceManager();
2960 const LangOptions
&LO
= BRC
.getASTContext().getLangOpts();
2961 if (Lexer::isAtStartOfMacroExpansion(BeginLoc
, SM
, LO
) &&
2962 Lexer::isAtEndOfMacroExpansion(EndLoc
, SM
, LO
)) {
2963 CharSourceRange R
= Lexer::getAsCharRange({BeginLoc
, EndLoc
}, SM
, LO
);
2964 Out
<< Lexer::getSourceText(R
, SM
, LO
);
2970 if (const auto *DR
= dyn_cast
<DeclRefExpr
>(Ex
)) {
2971 const bool quotes
= isa
<VarDecl
>(DR
->getDecl());
2974 const LocationContext
*LCtx
= N
->getLocationContext();
2975 const ProgramState
*state
= N
->getState().get();
2976 if (const MemRegion
*R
= state
->getLValue(cast
<VarDecl
>(DR
->getDecl()),
2977 LCtx
).getAsRegion()) {
2978 if (report
.isInteresting(R
))
2981 const ProgramState
*state
= N
->getState().get();
2982 SVal V
= state
->getSVal(R
);
2983 if (report
.isInteresting(V
))
2988 Out
<< DR
->getDecl()->getDeclName().getAsString();
2994 if (const auto *IL
= dyn_cast
<IntegerLiteral
>(Ex
)) {
2995 QualType OriginalTy
= OriginalExpr
->getType();
2996 if (OriginalTy
->isPointerType()) {
2997 if (IL
->getValue() == 0) {
3002 else if (OriginalTy
->isObjCObjectPointerType()) {
3003 if (IL
->getValue() == 0) {
3009 Out
<< IL
->getValue();
3013 if (const auto *ME
= dyn_cast
<MemberExpr
>(Ex
)) {
3014 if (!IsSameFieldName
)
3015 Out
<< "field '" << ME
->getMemberDecl()->getName() << '\'';
3018 << Lexer::getSourceText(
3019 CharSourceRange::getTokenRange(Ex
->getSourceRange()),
3020 BRC
.getSourceManager(), BRC
.getASTContext().getLangOpts(),
3028 PathDiagnosticPieceRef
ConditionBRVisitor::VisitTrueTest(
3029 const Expr
*Cond
, const BinaryOperator
*BExpr
, BugReporterContext
&BRC
,
3030 PathSensitiveBugReport
&R
, const ExplodedNode
*N
, bool TookTrue
,
3032 bool shouldInvert
= false;
3033 std::optional
<bool> shouldPrune
;
3035 // Check if the field name of the MemberExprs is ambiguous. Example:
3036 // " 'a.d' is equal to 'h.d' " in 'test/Analysis/null-deref-path-notes.cpp'.
3037 bool IsSameFieldName
= false;
3038 const auto *LhsME
= dyn_cast
<MemberExpr
>(BExpr
->getLHS()->IgnoreParenCasts());
3039 const auto *RhsME
= dyn_cast
<MemberExpr
>(BExpr
->getRHS()->IgnoreParenCasts());
3043 LhsME
->getMemberDecl()->getName() == RhsME
->getMemberDecl()->getName();
3045 SmallString
<128> LhsString
, RhsString
;
3047 llvm::raw_svector_ostream
OutLHS(LhsString
), OutRHS(RhsString
);
3048 const bool isVarLHS
= patternMatch(BExpr
->getLHS(), BExpr
, OutLHS
, BRC
, R
,
3049 N
, shouldPrune
, IsSameFieldName
);
3050 const bool isVarRHS
= patternMatch(BExpr
->getRHS(), BExpr
, OutRHS
, BRC
, R
,
3051 N
, shouldPrune
, IsSameFieldName
);
3053 shouldInvert
= !isVarLHS
&& isVarRHS
;
3056 BinaryOperator::Opcode Op
= BExpr
->getOpcode();
3058 if (BinaryOperator::isAssignmentOp(Op
)) {
3059 // For assignment operators, all that we care about is that the LHS
3060 // evaluates to "true" or "false".
3061 return VisitConditionVariable(LhsString
, BExpr
->getLHS(), BRC
, R
, N
,
3065 // For non-assignment operations, we require that we can understand
3066 // both the LHS and RHS.
3067 if (LhsString
.empty() || RhsString
.empty() ||
3068 !BinaryOperator::isComparisonOp(Op
) || Op
== BO_Cmp
)
3071 // Should we invert the strings if the LHS is not a variable name?
3072 SmallString
<256> buf
;
3073 llvm::raw_svector_ostream
Out(buf
);
3074 Out
<< (IsAssuming
? "Assuming " : "")
3075 << (shouldInvert
? RhsString
: LhsString
) << " is ";
3077 // Do we need to invert the opcode?
3081 case BO_LT
: Op
= BO_GT
; break;
3082 case BO_GT
: Op
= BO_LT
; break;
3083 case BO_LE
: Op
= BO_GE
; break;
3084 case BO_GE
: Op
= BO_LE
; break;
3089 case BO_EQ
: Op
= BO_NE
; break;
3090 case BO_NE
: Op
= BO_EQ
; break;
3091 case BO_LT
: Op
= BO_GE
; break;
3092 case BO_GT
: Op
= BO_LE
; break;
3093 case BO_LE
: Op
= BO_GT
; break;
3094 case BO_GE
: Op
= BO_LT
; break;
3104 Out
<< "not equal to ";
3107 Out
<< BinaryOperator::getOpcodeStr(Op
) << ' ';
3111 Out
<< (shouldInvert
? LhsString
: RhsString
);
3112 const LocationContext
*LCtx
= N
->getLocationContext();
3113 const SourceManager
&SM
= BRC
.getSourceManager();
3115 if (isVarAnInterestingCondition(BExpr
->getLHS(), N
, &R
) ||
3116 isVarAnInterestingCondition(BExpr
->getRHS(), N
, &R
))
3117 Out
<< WillBeUsedForACondition
;
3119 // Convert 'field ...' to 'Field ...' if it is a MemberExpr.
3120 std::string Message
= std::string(Out
.str());
3121 Message
[0] = toupper(Message
[0]);
3123 // If we know the value create a pop-up note to the value part of 'BExpr'.
3125 PathDiagnosticLocation Loc
;
3126 if (!shouldInvert
) {
3127 if (LhsME
&& LhsME
->getMemberLoc().isValid())
3128 Loc
= PathDiagnosticLocation(LhsME
->getMemberLoc(), SM
);
3130 Loc
= PathDiagnosticLocation(BExpr
->getLHS(), SM
, LCtx
);
3132 if (RhsME
&& RhsME
->getMemberLoc().isValid())
3133 Loc
= PathDiagnosticLocation(RhsME
->getMemberLoc(), SM
);
3135 Loc
= PathDiagnosticLocation(BExpr
->getRHS(), SM
, LCtx
);
3138 return std::make_shared
<PathDiagnosticPopUpPiece
>(Loc
, Message
);
3141 PathDiagnosticLocation
Loc(Cond
, SM
, LCtx
);
3142 auto event
= std::make_shared
<PathDiagnosticEventPiece
>(Loc
, Message
);
3144 event
->setPrunable(*shouldPrune
);
3148 PathDiagnosticPieceRef
ConditionBRVisitor::VisitConditionVariable(
3149 StringRef LhsString
, const Expr
*CondVarExpr
, BugReporterContext
&BRC
,
3150 PathSensitiveBugReport
&report
, const ExplodedNode
*N
, bool TookTrue
) {
3151 // FIXME: If there's already a constraint tracker for this variable,
3152 // we shouldn't emit anything here (c.f. the double note in
3153 // test/Analysis/inlining/path-notes.c)
3154 SmallString
<256> buf
;
3155 llvm::raw_svector_ostream
Out(buf
);
3156 Out
<< "Assuming " << LhsString
<< " is ";
3158 if (!printValue(CondVarExpr
, Out
, N
, TookTrue
, /*IsAssuming=*/true))
3161 const LocationContext
*LCtx
= N
->getLocationContext();
3162 PathDiagnosticLocation
Loc(CondVarExpr
, BRC
.getSourceManager(), LCtx
);
3164 if (isVarAnInterestingCondition(CondVarExpr
, N
, &report
))
3165 Out
<< WillBeUsedForACondition
;
3167 auto event
= std::make_shared
<PathDiagnosticEventPiece
>(Loc
, Out
.str());
3169 if (isInterestingExpr(CondVarExpr
, N
, &report
))
3170 event
->setPrunable(false);
3175 PathDiagnosticPieceRef
ConditionBRVisitor::VisitTrueTest(
3176 const Expr
*Cond
, const DeclRefExpr
*DRE
, BugReporterContext
&BRC
,
3177 PathSensitiveBugReport
&report
, const ExplodedNode
*N
, bool TookTrue
,
3179 const auto *VD
= dyn_cast
<VarDecl
>(DRE
->getDecl());
3183 SmallString
<256> Buf
;
3184 llvm::raw_svector_ostream
Out(Buf
);
3186 Out
<< (IsAssuming
? "Assuming '" : "'") << VD
->getDeclName() << "' is ";
3188 if (!printValue(DRE
, Out
, N
, TookTrue
, IsAssuming
))
3191 const LocationContext
*LCtx
= N
->getLocationContext();
3193 if (isVarAnInterestingCondition(DRE
, N
, &report
))
3194 Out
<< WillBeUsedForACondition
;
3196 // If we know the value create a pop-up note to the 'DRE'.
3198 PathDiagnosticLocation
Loc(DRE
, BRC
.getSourceManager(), LCtx
);
3199 return std::make_shared
<PathDiagnosticPopUpPiece
>(Loc
, Out
.str());
3202 PathDiagnosticLocation
Loc(Cond
, BRC
.getSourceManager(), LCtx
);
3203 auto event
= std::make_shared
<PathDiagnosticEventPiece
>(Loc
, Out
.str());
3205 if (isInterestingExpr(DRE
, N
, &report
))
3206 event
->setPrunable(false);
3208 return std::move(event
);
3211 PathDiagnosticPieceRef
ConditionBRVisitor::VisitTrueTest(
3212 const Expr
*Cond
, const MemberExpr
*ME
, BugReporterContext
&BRC
,
3213 PathSensitiveBugReport
&report
, const ExplodedNode
*N
, bool TookTrue
,
3215 SmallString
<256> Buf
;
3216 llvm::raw_svector_ostream
Out(Buf
);
3218 Out
<< (IsAssuming
? "Assuming field '" : "Field '")
3219 << ME
->getMemberDecl()->getName() << "' is ";
3221 if (!printValue(ME
, Out
, N
, TookTrue
, IsAssuming
))
3224 const LocationContext
*LCtx
= N
->getLocationContext();
3225 PathDiagnosticLocation Loc
;
3227 // If we know the value create a pop-up note to the member of the MemberExpr.
3228 if (!IsAssuming
&& ME
->getMemberLoc().isValid())
3229 Loc
= PathDiagnosticLocation(ME
->getMemberLoc(), BRC
.getSourceManager());
3231 Loc
= PathDiagnosticLocation(Cond
, BRC
.getSourceManager(), LCtx
);
3233 if (!Loc
.isValid() || !Loc
.asLocation().isValid())
3236 if (isVarAnInterestingCondition(ME
, N
, &report
))
3237 Out
<< WillBeUsedForACondition
;
3239 // If we know the value create a pop-up note.
3241 return std::make_shared
<PathDiagnosticPopUpPiece
>(Loc
, Out
.str());
3243 auto event
= std::make_shared
<PathDiagnosticEventPiece
>(Loc
, Out
.str());
3244 if (isInterestingExpr(ME
, N
, &report
))
3245 event
->setPrunable(false);
3249 bool ConditionBRVisitor::printValue(const Expr
*CondVarExpr
, raw_ostream
&Out
,
3250 const ExplodedNode
*N
, bool TookTrue
,
3252 QualType Ty
= CondVarExpr
->getType();
3254 if (Ty
->isPointerType()) {
3255 Out
<< (TookTrue
? "non-null" : "null");
3259 if (Ty
->isObjCObjectPointerType()) {
3260 Out
<< (TookTrue
? "non-nil" : "nil");
3264 if (!Ty
->isIntegralOrEnumerationType())
3267 std::optional
<const llvm::APSInt
*> IntValue
;
3269 IntValue
= getConcreteIntegerValue(CondVarExpr
, N
);
3271 if (IsAssuming
|| !IntValue
) {
3272 if (Ty
->isBooleanType())
3273 Out
<< (TookTrue
? "true" : "false");
3275 Out
<< (TookTrue
? "not equal to 0" : "0");
3277 if (Ty
->isBooleanType())
3278 Out
<< ((*IntValue
)->getBoolValue() ? "true" : "false");
3286 constexpr llvm::StringLiteral
ConditionBRVisitor::GenericTrueMessage
;
3287 constexpr llvm::StringLiteral
ConditionBRVisitor::GenericFalseMessage
;
3289 bool ConditionBRVisitor::isPieceMessageGeneric(
3290 const PathDiagnosticPiece
*Piece
) {
3291 return Piece
->getString() == GenericTrueMessage
||
3292 Piece
->getString() == GenericFalseMessage
;
3295 //===----------------------------------------------------------------------===//
3296 // Implementation of LikelyFalsePositiveSuppressionBRVisitor.
3297 //===----------------------------------------------------------------------===//
3299 void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
3300 BugReporterContext
&BRC
, const ExplodedNode
*N
,
3301 PathSensitiveBugReport
&BR
) {
3302 // Here we suppress false positives coming from system headers. This list is
3303 // based on known issues.
3304 const AnalyzerOptions
&Options
= BRC
.getAnalyzerOptions();
3305 const Decl
*D
= N
->getLocationContext()->getDecl();
3307 if (AnalysisDeclContext::isInStdNamespace(D
)) {
3308 // Skip reports within the 'std' namespace. Although these can sometimes be
3309 // the user's fault, we currently don't report them very well, and
3310 // Note that this will not help for any other data structure libraries, like
3311 // TR1, Boost, or llvm/ADT.
3312 if (Options
.ShouldSuppressFromCXXStandardLibrary
) {
3313 BR
.markInvalid(getTag(), nullptr);
3316 // If the complete 'std' suppression is not enabled, suppress reports
3317 // from the 'std' namespace that are known to produce false positives.
3319 // The analyzer issues a false use-after-free when std::list::pop_front
3320 // or std::list::pop_back are called multiple times because we cannot
3321 // reason about the internal invariants of the data structure.
3322 if (const auto *MD
= dyn_cast
<CXXMethodDecl
>(D
)) {
3323 const CXXRecordDecl
*CD
= MD
->getParent();
3324 if (CD
->getName() == "list") {
3325 BR
.markInvalid(getTag(), nullptr);
3330 // The analyzer issues a false positive when the constructor of
3331 // std::__independent_bits_engine from algorithms is used.
3332 if (const auto *MD
= dyn_cast
<CXXConstructorDecl
>(D
)) {
3333 const CXXRecordDecl
*CD
= MD
->getParent();
3334 if (CD
->getName() == "__independent_bits_engine") {
3335 BR
.markInvalid(getTag(), nullptr);
3340 for (const LocationContext
*LCtx
= N
->getLocationContext(); LCtx
;
3341 LCtx
= LCtx
->getParent()) {
3342 const auto *MD
= dyn_cast
<CXXMethodDecl
>(LCtx
->getDecl());
3346 const CXXRecordDecl
*CD
= MD
->getParent();
3347 // The analyzer issues a false positive on
3348 // std::basic_string<uint8_t> v; v.push_back(1);
3350 // std::u16string s; s += u'a';
3351 // because we cannot reason about the internal invariants of the
3353 if (CD
->getName() == "basic_string") {
3354 BR
.markInvalid(getTag(), nullptr);
3358 // The analyzer issues a false positive on
3359 // std::shared_ptr<int> p(new int(1)); p = nullptr;
3360 // because it does not reason properly about temporary destructors.
3361 if (CD
->getName() == "shared_ptr") {
3362 BR
.markInvalid(getTag(), nullptr);
3369 // Skip reports within the sys/queue.h macros as we do not have the ability to
3370 // reason about data structure shapes.
3371 const SourceManager
&SM
= BRC
.getSourceManager();
3372 FullSourceLoc Loc
= BR
.getLocation().asLocation();
3373 while (Loc
.isMacroID()) {
3374 Loc
= Loc
.getSpellingLoc();
3375 if (SM
.getFilename(Loc
).ends_with("sys/queue.h")) {
3376 BR
.markInvalid(getTag(), nullptr);
3382 //===----------------------------------------------------------------------===//
3383 // Implementation of UndefOrNullArgVisitor.
3384 //===----------------------------------------------------------------------===//
3386 PathDiagnosticPieceRef
3387 UndefOrNullArgVisitor::VisitNode(const ExplodedNode
*N
, BugReporterContext
&BRC
,
3388 PathSensitiveBugReport
&BR
) {
3389 ProgramStateRef State
= N
->getState();
3390 ProgramPoint ProgLoc
= N
->getLocation();
3392 // We are only interested in visiting CallEnter nodes.
3393 std::optional
<CallEnter
> CEnter
= ProgLoc
.getAs
<CallEnter
>();
3397 // Check if one of the arguments is the region the visitor is tracking.
3398 CallEventManager
&CEMgr
= BRC
.getStateManager().getCallEventManager();
3399 CallEventRef
<> Call
= CEMgr
.getCaller(CEnter
->getCalleeContext(), State
);
3401 ArrayRef
<ParmVarDecl
*> parms
= Call
->parameters();
3403 for (const auto ParamDecl
: parms
) {
3404 const MemRegion
*ArgReg
= Call
->getArgSVal(Idx
).getAsRegion();
3407 // Are we tracking the argument or its subregion?
3408 if ( !ArgReg
|| !R
->isSubRegionOf(ArgReg
->StripCasts()))
3411 // Check the function parameter type.
3412 assert(ParamDecl
&& "Formal parameter has no decl?");
3413 QualType T
= ParamDecl
->getType();
3415 if (!(T
->isAnyPointerType() || T
->isReferenceType())) {
3416 // Function can only change the value passed in by address.
3420 // If it is a const pointer value, the function does not intend to
3421 // change the value.
3422 if (T
->getPointeeType().isConstQualified())
3425 // Mark the call site (LocationContext) as interesting if the value of the
3426 // argument is undefined or '0'/'NULL'.
3427 SVal BoundVal
= State
->getSVal(R
);
3428 if (BoundVal
.isUndef() || BoundVal
.isZeroConstant()) {
3429 BR
.markInteresting(CEnter
->getCalleeContext());
3436 //===----------------------------------------------------------------------===//
3437 // Implementation of FalsePositiveRefutationBRVisitor.
3438 //===----------------------------------------------------------------------===//
3440 FalsePositiveRefutationBRVisitor::FalsePositiveRefutationBRVisitor()
3441 : Constraints(ConstraintMap::Factory().getEmptyMap()) {}
3443 void FalsePositiveRefutationBRVisitor::finalizeVisitor(
3444 BugReporterContext
&BRC
, const ExplodedNode
*EndPathNode
,
3445 PathSensitiveBugReport
&BR
) {
3446 // Collect new constraints
3447 addConstraints(EndPathNode
, /*OverwriteConstraintsOnExistingSyms=*/true);
3449 // Create a refutation manager
3450 llvm::SMTSolverRef RefutationSolver
= llvm::CreateZ3Solver();
3451 ASTContext
&Ctx
= BRC
.getASTContext();
3453 // Add constraints to the solver
3454 for (const auto &I
: Constraints
) {
3455 const SymbolRef Sym
= I
.first
;
3456 auto RangeIt
= I
.second
.begin();
3458 llvm::SMTExprRef SMTConstraints
= SMTConv::getRangeExpr(
3459 RefutationSolver
, Ctx
, Sym
, RangeIt
->From(), RangeIt
->To(),
3461 while ((++RangeIt
) != I
.second
.end()) {
3462 SMTConstraints
= RefutationSolver
->mkOr(
3463 SMTConstraints
, SMTConv::getRangeExpr(RefutationSolver
, Ctx
, Sym
,
3464 RangeIt
->From(), RangeIt
->To(),
3468 RefutationSolver
->addConstraint(SMTConstraints
);
3471 // And check for satisfiability
3472 std::optional
<bool> IsSAT
= RefutationSolver
->check();
3477 BR
.markInvalid("Infeasible constraints", EndPathNode
->getLocationContext());
3480 void FalsePositiveRefutationBRVisitor::addConstraints(
3481 const ExplodedNode
*N
, bool OverwriteConstraintsOnExistingSyms
) {
3482 // Collect new constraints
3483 ConstraintMap NewCs
= getConstraintMap(N
->getState());
3484 ConstraintMap::Factory
&CF
= N
->getState()->get_context
<ConstraintMap
>();
3486 // Add constraints if we don't have them yet
3487 for (auto const &C
: NewCs
) {
3488 const SymbolRef
&Sym
= C
.first
;
3489 if (!Constraints
.contains(Sym
)) {
3490 // This symbol is new, just add the constraint.
3491 Constraints
= CF
.add(Constraints
, Sym
, C
.second
);
3492 } else if (OverwriteConstraintsOnExistingSyms
) {
3493 // Overwrite the associated constraint of the Symbol.
3494 Constraints
= CF
.remove(Constraints
, Sym
);
3495 Constraints
= CF
.add(Constraints
, Sym
, C
.second
);
3500 PathDiagnosticPieceRef
FalsePositiveRefutationBRVisitor::VisitNode(
3501 const ExplodedNode
*N
, BugReporterContext
&, PathSensitiveBugReport
&) {
3502 addConstraints(N
, /*OverwriteConstraintsOnExistingSyms=*/false);
3506 void FalsePositiveRefutationBRVisitor::Profile(
3507 llvm::FoldingSetNodeID
&ID
) const {
3509 ID
.AddPointer(&Tag
);
3512 //===----------------------------------------------------------------------===//
3513 // Implementation of TagVisitor.
3514 //===----------------------------------------------------------------------===//
3516 int NoteTag::Kind
= 0;
3518 void TagVisitor::Profile(llvm::FoldingSetNodeID
&ID
) const {
3520 ID
.AddPointer(&Tag
);
3523 PathDiagnosticPieceRef
TagVisitor::VisitNode(const ExplodedNode
*N
,
3524 BugReporterContext
&BRC
,
3525 PathSensitiveBugReport
&R
) {
3526 ProgramPoint PP
= N
->getLocation();
3527 const NoteTag
*T
= dyn_cast_or_null
<NoteTag
>(PP
.getTag());
3531 if (std::optional
<std::string
> Msg
= T
->generateMessage(BRC
, R
)) {
3532 PathDiagnosticLocation Loc
=
3533 PathDiagnosticLocation::create(PP
, BRC
.getSourceManager());
3534 auto Piece
= std::make_shared
<PathDiagnosticEventPiece
>(Loc
, *Msg
);
3535 Piece
->setPrunable(T
->isPrunable());