NoQ created this revision. NoQ added reviewers: dcoughlin, xazax.hun, a.sidorin, george.karpenkov, szepet. Herald added subscribers: cfe-commits, rnkovacs.
`removeUnneededCalls()` is responsible for removing path diagnostic pieces within functions that don't contain "interesting" events. It is the functionality that's controlled by the `-analyzer-config prune-paths and it makes bug reports much tidier (though sometimes it removes too much, and in this case it's great to disable this option when debugging). While relatively simple, it contains a bug: when a stack frame is known to be interesting, the function doesn't descend into it to prune anything within it, even other callees that are totally boring. This is rarely apparent, but in C++ there are a lot of implicit calls that suddenly become visible because of this bug. Repository: rC Clang https://reviews.llvm.org/D45117 Files: lib/StaticAnalyzer/Core/BugReporter.cpp test/Analysis/inlining/path-notes.c
Index: test/Analysis/inlining/path-notes.c =================================================================== --- test/Analysis/inlining/path-notes.c +++ test/Analysis/inlining/path-notes.c @@ -140,6 +140,22 @@ // expected-note@-1 {{Dereference of null pointer}} } +void boringCallee() { +} + +void interestingCallee(int *x) { + *x = 0; // expected-note{{The value 0 is assigned to 'x'}} + boringCallee(); // no-note +} + +int testBoringCalleeOfInterestingCallee() { + int x; + interestingCallee(&x); // expected-note{{Calling 'interestingCallee'}} + // expected-note@-1{{Returning from 'interestingCallee'}} + return 1 / x; // expected-warning{{Division by zero}} + // expected-note@-1{{Division by zero}} +} + // CHECK: <key>diagnostics</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> @@ -3377,4 +3393,290 @@ // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>path</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>control</string> +// CHECK-NEXT: <key>edges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>start</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>152</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>152</integer> +// CHECK-NEXT: <key>col</key><integer>5</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>end</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>153</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>153</integer> +// CHECK-NEXT: <key>col</key><integer>19</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>event</string> +// CHECK-NEXT: <key>location</key> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>153</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <key>ranges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>153</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>153</integer> +// CHECK-NEXT: <key>col</key><integer>23</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>depth</key><integer>0</integer> +// CHECK-NEXT: <key>extended_message</key> +// CHECK-NEXT: <string>Calling 'interestingCallee'</string> +// CHECK-NEXT: <key>message</key> +// CHECK-NEXT: <string>Calling 'interestingCallee'</string> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>event</string> +// CHECK-NEXT: <key>location</key> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>1</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <key>depth</key><integer>1</integer> +// CHECK-NEXT: <key>extended_message</key> +// CHECK-NEXT: <string>Entered call from 'testBoringCalleeOfInterestingCallee'</string> +// CHECK-NEXT: <key>message</key> +// CHECK-NEXT: <string>Entered call from 'testBoringCalleeOfInterestingCallee'</string> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>control</string> +// CHECK-NEXT: <key>edges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>start</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>1</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>146</integer> +// CHECK-NEXT: <key>col</key><integer>4</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>end</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>147</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>147</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>event</string> +// CHECK-NEXT: <key>location</key> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>147</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <key>ranges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>147</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>147</integer> +// CHECK-NEXT: <key>col</key><integer>8</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>depth</key><integer>1</integer> +// CHECK-NEXT: <key>extended_message</key> +// CHECK-NEXT: <string>The value 0 is assigned to 'x'</string> +// CHECK-NEXT: <key>message</key> +// CHECK-NEXT: <string>The value 0 is assigned to 'x'</string> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>control</string> +// CHECK-NEXT: <key>edges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>start</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>147</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>147</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>end</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>148</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>148</integer> +// CHECK-NEXT: <key>col</key><integer>14</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>event</string> +// CHECK-NEXT: <key>location</key> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>153</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <key>ranges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>153</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>153</integer> +// CHECK-NEXT: <key>col</key><integer>23</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>depth</key><integer>0</integer> +// CHECK-NEXT: <key>extended_message</key> +// CHECK-NEXT: <string>Returning from 'interestingCallee'</string> +// CHECK-NEXT: <key>message</key> +// CHECK-NEXT: <string>Returning from 'interestingCallee'</string> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>control</string> +// CHECK-NEXT: <key>edges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>start</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>153</integer> +// CHECK-NEXT: <key>col</key><integer>3</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>153</integer> +// CHECK-NEXT: <key>col</key><integer>19</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>end</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>155</integer> +// CHECK-NEXT: <key>col</key><integer>12</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>155</integer> +// CHECK-NEXT: <key>col</key><integer>12</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>event</string> +// CHECK-NEXT: <key>location</key> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>155</integer> +// CHECK-NEXT: <key>col</key><integer>12</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <key>ranges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>155</integer> +// CHECK-NEXT: <key>col</key><integer>10</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>155</integer> +// CHECK-NEXT: <key>col</key><integer>14</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>depth</key><integer>0</integer> +// CHECK-NEXT: <key>extended_message</key> +// CHECK-NEXT: <string>Division by zero</string> +// CHECK-NEXT: <key>message</key> +// CHECK-NEXT: <string>Division by zero</string> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>description</key><string>Division by zero</string> +// CHECK-NEXT: <key>category</key><string>Logic error</string> +// CHECK-NEXT: <key>type</key><string>Division by zero</string> +// CHECK-NEXT: <key>check_name</key><string>core.DivideZero</string> +// CHECK-NEXT: <!-- This hash is experimental and going to change! --> +// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>fcd480c0f73d071bac6f908387893e26</string> +// CHECK-NEXT: <key>issue_context_kind</key><string>function</string> +// CHECK-NEXT: <key>issue_context</key><string>testBoringCalleeOfInterestingCallee</string> +// CHECK-NEXT: <key>issue_hash_function_offset</key><string>4</string> +// CHECK-NEXT: <key>location</key> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>155</integer> +// CHECK-NEXT: <key>col</key><integer>12</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </dict> // CHECK-NEXT: </array> Index: lib/StaticAnalyzer/Core/BugReporter.cpp =================================================================== --- lib/StaticAnalyzer/Core/BugReporter.cpp +++ lib/StaticAnalyzer/Core/BugReporter.cpp @@ -192,8 +192,9 @@ /// that aren't needed. Return true if afterwards the path contains /// "interesting stuff" which means it shouldn't be pruned from the parent path. static bool removeUnneededCalls(PathPieces &pieces, BugReport *R, - LocationContextMap &LCM) { - bool containsSomethingInteresting = false; + LocationContextMap &LCM, + bool IsInteresting = false) { + bool containsSomethingInteresting = IsInteresting; const unsigned N = pieces.size(); for (unsigned i = 0 ; i < N ; ++i) { @@ -207,20 +208,16 @@ auto &call = cast<PathDiagnosticCallPiece>(*piece); // Check if the location context is interesting. assert(LCM.count(&call.path)); - if (R->isInteresting(LCM[&call.path])) { - containsSomethingInteresting = true; - break; - } - - if (!removeUnneededCalls(call.path, R, LCM)) + if (!removeUnneededCalls(call.path, R, LCM, + R->isInteresting(LCM[&call.path]))) continue; containsSomethingInteresting = true; break; } case PathDiagnosticPiece::Macro: { auto ¯o = cast<PathDiagnosticMacroPiece>(*piece); - if (!removeUnneededCalls(macro.subPieces, R, LCM)) + if (!removeUnneededCalls(macro.subPieces, R, LCM, IsInteresting)) continue; containsSomethingInteresting = true; break;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits