Index: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h +++ clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h @@ -126,6 +126,7 @@ using TrackingKind = bugreporter::TrackingKind; TrackingKind TKind; + const StackFrameContext *OriginSFC; public: /// Creates a visitor for every VarDecl inside a Stmt and registers it with @@ -139,11 +140,19 @@ /// \param EnableNullFPSuppression Whether we should employ false positive /// suppression (inlined defensive checks, returned null). /// \param TKind May limit the amount of notes added to the bug report. + /// \param OriginSFC Only adds notes when the last store happened in a + /// different stackframe to this one. Disregarded if the tracking kind + /// is thorough. + /// This is useful, because for non-tracked regions, notes about + /// changes to its value in a nested stackframe could be pruned, and + /// this visitor can prevent that without polluting the bugpath too + /// much. FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R, bool InEnableNullFPSuppression, - TrackingKind TKind) + TrackingKind TKind, + const StackFrameContext *OriginSFC = nullptr) : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression), - TKind(TKind) { + TKind(TKind), OriginSFC(OriginSFC) { assert(R); } Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -1453,6 +1453,10 @@ trackExpressionValue(StoreSite, InitE, BR, EnableNullFPSuppression, TKind); } + if (TKind == TrackingKind::ConditionTracking && + StoreSite->getStackFrame() == OriginSFC) + return nullptr; + // Okay, we've found the binding. Emit an appropriate message. SmallString<256> sbuf; llvm::raw_svector_ostream os(sbuf); @@ -1478,7 +1482,7 @@ if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) { if (auto KV = State->getSVal(OriginalR).getAs()) BR.addVisitor(llvm::make_unique( - *KV, OriginalR, EnableNullFPSuppression, TKind)); + *KV, OriginalR, EnableNullFPSuppression, TKind, OriginSFC)); } } } @@ -1910,6 +1914,7 @@ return false; ProgramStateRef LVState = LVNode->getState(); + const StackFrameContext *SFC = LVNode->getStackFrame(); // We only track expressions if we believe that they are important. Chances // are good that control dependencies to the tracking point are also improtant @@ -1945,7 +1950,7 @@ if (RR && !LVIsNull) if (auto KV = LVal.getAs()) report.addVisitor(llvm::make_unique( - *KV, RR, EnableNullFPSuppression, TKind)); + *KV, RR, EnableNullFPSuppression, TKind, SFC)); // In case of C++ references, we want to differentiate between a null // reference and reference to null pointer. @@ -1982,7 +1987,7 @@ if (auto KV = V.getAs()) report.addVisitor(llvm::make_unique( - *KV, R, EnableNullFPSuppression, TKind)); + *KV, R, EnableNullFPSuppression, TKind, SFC)); return true; } } @@ -2022,7 +2027,7 @@ if (CanDereference) if (auto KV = RVal.getAs()) report.addVisitor(llvm::make_unique( - *KV, L->getRegion(), EnableNullFPSuppression, TKind)); + *KV, L->getRegion(), EnableNullFPSuppression, TKind, SFC)); const MemRegion *RegionRVal = RVal.getAsRegion(); if (RegionRVal && isa(RegionRVal)) { Index: clang/test/Analysis/track-control-dependency-conditions.cpp =================================================================== --- clang/test/Analysis/track-control-dependency-conditions.cpp +++ clang/test/Analysis/track-control-dependency-conditions.cpp @@ -127,10 +127,9 @@ void test() { int *x = 0; // expected-note{{'x' initialized to a null pointer value}} - if (int flag = foo()) // tracking-note{{'flag' initialized here}} - // debug-note@-1{{Tracking condition 'flag'}} - // expected-note@-2{{Assuming 'flag' is not equal to 0}} - // expected-note@-3{{Taking true branch}} + if (int flag = foo()) // debug-note{{Tracking condition 'flag'}} + // expected-note@-1{{Assuming 'flag' is not equal to 0}} + // expected-note@-2{{Taking true branch}} *x = 5; // expected-warning{{Dereference of null pointer}} // expected-note@-1{{Dereference of null pointer}} @@ -205,7 +204,7 @@ int getInt(); void f() { - int flag = getInt(); // tracking-note{{'flag' initialized here}} + int flag = getInt(); int *x = 0; // expected-note{{'x' initialized to a null pointer value}} if (flag) // expected-note{{Assuming 'flag' is not equal to 0}} // expected-note@-1{{Taking true branch}} @@ -220,8 +219,8 @@ int getInt(); void f(int y) { - y = 1; // tracking-note{{The value 1 is assigned to 'y'}} - flag = y; // tracking-note{{The value 1 is assigned to 'flag'}} + y = 1; + flag = y; int *x = 0; // expected-note{{'x' initialized to a null pointer value}} if (flag) // expected-note{{'flag' is 1}} @@ -238,9 +237,8 @@ void foo() { int y; - y = 1; // tracking-note{{The value 1 is assigned to 'y'}} + y = 1; flag = y; // tracking-note{{The value 1 is assigned to 'flag'}} - } void f(int y) { @@ -271,7 +269,7 @@ foo(); // tracking-note{{Calling 'foo'}} // tracking-note@-1{{Returning from 'foo'}} - y = flag; // tracking-note{{Value assigned to 'y'}} + y = flag; if (y) // expected-note{{Assuming 'y' is not equal to 0}} // expected-note@-1{{Taking true branch}} @@ -320,7 +318,7 @@ void f(int flag) { int *x = 0; // expected-note{{'x' initialized to a null pointer value}} - flag = getInt(); // tracking-note{{Value assigned to 'flag'}} + flag = getInt(); assert(flag); // tracking-note{{Calling 'assert'}} // tracking-note@-1{{Returning from 'assert'}}