diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-08-28 00:50:42 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-08-28 00:50:42 +0000 |
commit | 7aba1171b32265b2206f3fa8f8886953051b58f5 (patch) | |
tree | 32f82e0239c92dbc73032a6d2fb19c9e088abf35 | |
parent | 6062334cc388bce69fb3978c4ecb26c6485a5c2b (diff) |
[analyzer] If the last store into a region came from a function, step into it.
Previously, if we were tracking stores to a variable 'x', and came across this:
x = foo();
...we would simply emit a note here and stop. Now, we'll step into 'foo' and
continue tracking the returned value from there.
<rdar://problem/12114689>
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162718 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 231 | ||||
-rw-r--r-- | test/Analysis/inlining/path-notes.c | 468 |
2 files changed, 586 insertions, 113 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index d17777714a..ae8ed00783 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -20,6 +20,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "llvm/ADT/SmallString.h" using namespace clang; @@ -110,6 +111,133 @@ BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC, } +namespace { +/// Emits an extra note at the return statement of an interesting stack frame. +/// +/// The returned value is marked as an interesting value, and if it's null, +/// adds a visitor to track where it became null. +/// +/// This visitor is intended to be used when another visitor discovers that an +/// interesting value comes from an inlined function call. +class ReturnVisitor : public BugReporterVisitorImpl<ReturnVisitor> { + const StackFrameContext *StackFrame; + bool Satisfied; +public: + ReturnVisitor(const StackFrameContext *Frame) + : StackFrame(Frame), Satisfied(false) {} + + virtual void Profile(llvm::FoldingSetNodeID &ID) const { + static int Tag = 0; + ID.AddPointer(&Tag); + ID.AddPointer(StackFrame); + } + + /// Adds a ReturnVisitor if the given statement represents a call that was + /// inlined. + /// + /// This will search back through the ExplodedGraph, starting from the given + /// node, looking for when the given statement was processed. If it turns out + /// the statement is a call that was inlined, we add the visitor to the + /// bug report, so it can print a note later. + static void addVisitorIfNecessary(const ExplodedNode *Node, const Stmt *S, + BugReport &BR) { + if (!CallEvent::isCallStmt(S)) + return; + + // First, find when we processed the statement. + do { + if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>()) + if (CEE->getCalleeContext()->getCallSite() == S) + break; + if (const StmtPoint *SP = Node->getLocationAs<StmtPoint>()) + if (SP->getStmt() == S) + break; + + Node = Node->getFirstPred(); + } while (Node); + + // Next, step over any post-statement checks. + while (Node && isa<PostStmt>(Node->getLocation())) + Node = Node->getFirstPred(); + + // Finally, see if we inlined the call. + if (Node) + if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>()) + if (CEE->getCalleeContext()->getCallSite() == S) + BR.addVisitor(new ReturnVisitor(CEE->getCalleeContext())); + + } + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { + if (Satisfied) + return 0; + + // Only print a message at the interesting return statement. + if (N->getLocationContext() != StackFrame) + return 0; + + const StmtPoint *SP = N->getLocationAs<StmtPoint>(); + if (!SP) + return 0; + + const ReturnStmt *Ret = dyn_cast<ReturnStmt>(SP->getStmt()); + if (!Ret) + return 0; + + // Okay, we're at the right return statement, but do we have the return + // value available? + ProgramStateRef State = N->getState(); + SVal V = State->getSVal(Ret, StackFrame); + if (V.isUnknownOrUndef()) + return 0; + + // Don't print any more notes after this one. + Satisfied = true; + + // Build an appropriate message based on the return value. + SmallString<64> Msg; + llvm::raw_svector_ostream Out(Msg); + + const Expr *RetE = Ret->getRetValue(); + assert(RetE && "Tracking a return value for a void function"); + RetE = RetE->IgnoreParenCasts(); + + // See if we know that the return value is 0. + ProgramStateRef StNonZero, StZero; + llvm::tie(StNonZero, StZero) = State->assume(cast<DefinedSVal>(V)); + if (StZero && !StNonZero) { + // If we're returning 0, we should track where that 0 came from. + bugreporter::addTrackNullOrUndefValueVisitor(N, RetE, &BR); + + if (isa<Loc>(V)) { + if (RetE->getType()->isObjCObjectPointerType()) + Out << "Returning nil"; + else + Out << "Returning null pointer"; + } else { + Out << "Returning zero"; + } + } else { + // FIXME: We can probably do better than this. + BR.markInteresting(V); + Out << "Value returned here"; + } + + // FIXME: We should have a more generalized location printing mechanism. + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE)) + if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl())) + Out << " (loaded from '" << *DD << "')"; + + PathDiagnosticLocation L(Ret, BRC.getSourceManager(), StackFrame); + return new PathDiagnosticEventPiece(L, Out.str()); + } +}; +} // end anonymous namespace + + void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const { static int tag = 0; ID.AddPointer(&tag); @@ -133,6 +261,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N, return NULL; const ExplodedNode *Node = N, *Last = N; + const Expr *InitE = 0; // Now look for the store of V. for ( ; Node ; Node = Node->getFirstPred()) { @@ -142,14 +271,26 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N, if (DS->getSingleDecl() == VR->getDecl()) { // Record the last seen initialization point. Last = Node; + InitE = VR->getDecl()->getInit(); break; } } // Does the region still bind to value V? If not, we are done // looking for store sites. - if (Node->getState()->getSVal(R) != V) + SVal Current = Node->getState()->getSVal(R); + if (Current != V) { + // If this is an assignment expression, we can track the value + // being assigned. + if (const StmtPoint *SP = Last->getLocationAs<StmtPoint>()) { + const Stmt *S = SP->getStmt(); + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) + if (BO->isAssignmentOp()) + InitE = BO->getRHS(); + } + break; + } Last = Node; } @@ -160,6 +301,13 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N, } StoreSite = Last; + + // If the value that was stored came from an inlined call, make sure we + // step into the call. + if (InitE) { + InitE = InitE->IgnoreParenCasts(); + ReturnVisitor::addVisitorIfNecessary(StoreSite, InitE, BR); + } } if (StoreSite != N) @@ -303,50 +451,6 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, return NULL; } -namespace { -class ReturnNullVisitor : public BugReporterVisitorImpl<ReturnNullVisitor> { - const ExplodedNode *ReturnNode; -public: - ReturnNullVisitor(const ExplodedNode *N) : ReturnNode(N) {} - - virtual void Profile(llvm::FoldingSetNodeID &ID) const { - static int Tag = 0; - ID.AddPointer(&Tag); - ID.Add(*ReturnNode); - } - - PathDiagnosticPiece *VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext &BRC, - BugReport &BR) { - // Only print a message at the interesting return statement. - if (ReturnNode != BRC.getNodeResolver().getOriginalNode(N)) - return 0; - - StmtPoint SP = cast<StmtPoint>(ReturnNode->getLocation()); - const ReturnStmt *Ret = cast<ReturnStmt>(SP.getStmt()); - PathDiagnosticLocation L(Ret, BRC.getSourceManager(), - N->getLocationContext()); - - SmallString<64> Msg; - llvm::raw_svector_ostream Out(Msg); - - if (Loc::isLocType(Ret->getRetValue()->getType())) - Out << "Returning null pointer"; - else - Out << "Returning zero"; - - // FIXME: We should have a more generalized printing mechanism. - const Expr *RetE = Ret->getRetValue()->IgnoreParenCasts(); - if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE)) - if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl())) - Out << " (loaded from '" << *DD << "')"; - - return new PathDiagnosticEventPiece(L, Out.str()); - } -}; -} // end anonymous namespace - void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N, const Stmt *S, BugReport *report) { @@ -421,39 +525,10 @@ void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N, report->addVisitor(new TrackConstraintBRVisitor(loc::MemRegionVal(Base), false)); } - } else if (isa<loc::ConcreteInt>(V)) { - // Otherwise, if it's a null constant, we want to know where it came from. - // In particular, if it came from an inlined function call, - // we need to make sure that function isn't pruned in our output. - - // Walk backwards to just before the post-statement checks. - ProgramPoint PP = N->getLocation(); - while (N && isa<PostStmt>(PP = N->getLocation())) - N = N->getFirstPred(); - - // If we found an inlined call before the post-statement checks, look - // for a return statement within the call. - if (N && isa<CallExitEnd>(PP)) { - // Walk backwards within the inlined function until we find a statement. - // This will look through multiple levels of inlining, but stop if the - // last thing that happened was an empty function being inlined. - // FIXME: This may not work in the presence of destructors. - do { - N = N->getFirstPred(); - PP = N->getLocation(); - } while (!isa<StmtPoint>(PP) && !isa<CallEnter>(PP)); - - // If the last statement we found is a 'return <expr>', make sure we - // show this return...and recursively track the value being returned. - if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) { - if (const ReturnStmt *Ret = SP->getStmtAs<ReturnStmt>()) { - if (const Expr *RetE = Ret->getRetValue()) { - report->addVisitor(new ReturnNullVisitor(N)); - addTrackNullOrUndefValueVisitor(N, RetE, report); - } - } - } - } + } else { + // Otherwise, if the value came from an inlined function call, + // we should at least make sure that function isn't pruned in our output. + ReturnVisitor::addVisitorIfNecessary(N, S, *report); } } diff --git a/test/Analysis/inlining/path-notes.c b/test/Analysis/inlining/path-notes.c index c1b03ff693..07b7dc6b0f 100644 --- a/test/Analysis/inlining/path-notes.c +++ b/test/Analysis/inlining/path-notes.c @@ -80,17 +80,19 @@ int testReturnZero2() { } void testInitZero() { - // FIXME: <rdar://problem/12114689> Diagnostics: Need to step into the function whose result is assigned to an interesting region int *a = getZero(); - // expected-note@-1 {{Variable 'a' initialized to a null pointer value}} + // expected-note@-1 {{Calling 'getZero'}} + // expected-note@-2 {{Returning from 'getZero'}} + // expected-note@-3 {{Variable 'a' initialized to a null pointer value}} *a = 1; // expected-warning{{Dereference of null pointer}} // expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}} } void testStoreZero(int *a) { - // FIXME: <rdar://problem/12114689> Diagnostics: Need to step into the function whose result is assigned to an interesting region a = getZero(); - // expected-note@-1 {{Null pointer value stored to 'a'}} + // expected-note@-1 {{Calling 'getZero'}} + // expected-note@-2 {{Returning from 'getZero'}} + // expected-note@-3 {{Null pointer value stored to 'a'}} *a = 1; // expected-warning{{Dereference of null pointer}} // expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}} } @@ -2028,12 +2030,12 @@ void testStoreZero(int *a) { // CHECK: <key>start</key> // CHECK: <array> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>3</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>5</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2041,12 +2043,12 @@ void testStoreZero(int *a) { // CHECK: <key>end</key> // CHECK: <array> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>12</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>18</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2055,6 +2057,49 @@ void testStoreZero(int *a) { // CHECK: </array> // CHECK: </dict> // CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>83</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>83</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>83</integer> +// CHECK: <key>col</key><integer>20</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Calling 'getZero'</string> +// CHECK: <key>message</key> +// CHECK: <string>Calling 'getZero'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Entered call from 'testInitZero'</string> +// CHECK: <key>message</key> +// CHECK: <string>Entered call from 'testInitZero'</string> +// CHECK: </dict> +// CHECK: <dict> // CHECK: <key>kind</key><string>control</string> // CHECK: <key>edges</key> // CHECK: <array> @@ -2062,12 +2107,75 @@ void testStoreZero(int *a) { // CHECK: <key>start</key> // CHECK: <array> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> // CHECK: <key>col</key><integer>3</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Variable 'p' initialized to a null pointer value</string> +// CHECK: <key>message</key> +// CHECK: <string>Variable 'p' initialized to a null pointer value</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> // CHECK: <key>col</key><integer>5</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2075,12 +2183,104 @@ void testStoreZero(int *a) { // CHECK: <key>end</key> // CHECK: <array> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>64</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>64</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>64</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>64</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>64</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Returning null pointer (loaded from 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Returning null pointer (loaded from 'p')</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>83</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>83</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>83</integer> +// CHECK: <key>col</key><integer>20</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Returning from 'getZero'</string> +// CHECK: <key>message</key> +// CHECK: <string>Returning from 'getZero'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>83</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>83</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>12</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>18</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2096,12 +2296,12 @@ void testStoreZero(int *a) { // CHECK: <key>start</key> // CHECK: <array> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>12</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>18</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2109,12 +2309,12 @@ void testStoreZero(int *a) { // CHECK: <key>end</key> // CHECK: <array> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>3</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>5</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2126,7 +2326,7 @@ void testStoreZero(int *a) { // CHECK: <key>kind</key><string>event</string> // CHECK: <key>location</key> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>3</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2134,12 +2334,12 @@ void testStoreZero(int *a) { // CHECK: <array> // CHECK: <array> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>3</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>8</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2159,12 +2359,12 @@ void testStoreZero(int *a) { // CHECK: <key>start</key> // CHECK: <array> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>3</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> // CHECK: <dict> -// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>line</key><integer>83</integer> // CHECK: <key>col</key><integer>5</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2172,12 +2372,12 @@ void testStoreZero(int *a) { // CHECK: <key>end</key> // CHECK: <array> // CHECK: <dict> -// CHECK: <key>line</key><integer>86</integer> +// CHECK: <key>line</key><integer>87</integer> // CHECK: <key>col</key><integer>3</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> // CHECK: <dict> -// CHECK: <key>line</key><integer>86</integer> +// CHECK: <key>line</key><integer>87</integer> // CHECK: <key>col</key><integer>3</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2189,7 +2389,7 @@ void testStoreZero(int *a) { // CHECK: <key>kind</key><string>event</string> // CHECK: <key>location</key> // CHECK: <dict> -// CHECK: <key>line</key><integer>86</integer> +// CHECK: <key>line</key><integer>87</integer> // CHECK: <key>col</key><integer>3</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2197,12 +2397,12 @@ void testStoreZero(int *a) { // CHECK: <array> // CHECK: <array> // CHECK: <dict> -// CHECK: <key>line</key><integer>86</integer> +// CHECK: <key>line</key><integer>87</integer> // CHECK: <key>col</key><integer>4</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> // CHECK: <dict> -// CHECK: <key>line</key><integer>86</integer> +// CHECK: <key>line</key><integer>87</integer> // CHECK: <key>col</key><integer>4</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2220,10 +2420,10 @@ void testStoreZero(int *a) { // CHECK: <key>type</key><string>Dereference of null pointer</string> // CHECK: <key>issue_context_kind</key><string>function</string> // CHECK: <key>issue_context</key><string>testInitZero</string> -// CHECK: <key>issue_hash</key><integer>4</integer> +// CHECK: <key>issue_hash</key><integer>5</integer> // CHECK: <key>location</key> // CHECK: <dict> -// CHECK: <key>line</key><integer>86</integer> +// CHECK: <key>line</key><integer>87</integer> // CHECK: <key>col</key><integer>3</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> @@ -2266,6 +2466,204 @@ void testStoreZero(int *a) { // CHECK: </array> // CHECK: </dict> // CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>15</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Calling 'getZero'</string> +// CHECK: <key>message</key> +// CHECK: <string>Calling 'getZero'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Entered call from 'testStoreZero'</string> +// CHECK: <key>message</key> +// CHECK: <string>Entered call from 'testStoreZero'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// |