]> granicus.if.org Git - clang/commitdiff
[analyzer] Improved diagnostic pruning for calls initializing values.
authorAnna Zaks <ganna@apple.com>
Wed, 29 Aug 2012 21:22:37 +0000 (21:22 +0000)
committerAnna Zaks <ganna@apple.com>
Wed, 29 Aug 2012 21:22:37 +0000 (21:22 +0000)
This heuristic addresses the case when a pointer (or ref) is passed
to a function, which initializes the variable (or sets it to something
other than '0'). On the branch where the inlined function does not
set the value, we report use of undefined value (or NULL pointer
dereference). The access happens in the caller and the path
through the callee would get pruned away with regular path pruning. To
solve this issue, we previously disabled diagnostic pruning completely
on undefined and null pointer dereference checks, which entailed very
verbose diagnostics in most cases. Furthermore, not all of the
undef value checks had the diagnostic pruning disabled.

This patch implements the following heuristic: if we pass a pointer (or
ref) to the region (on which the error is reported) into a function and
it's value is either undef or 'NULL' (and is a pointer), do not prune
the function.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162863 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/Analysis/ProgramPoint.h
include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
lib/StaticAnalyzer/Core/BugReporter.cpp
lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
test/Analysis/diagnostics/undef-value-caller.c
test/Analysis/diagnostics/undef-value-param.c [new file with mode: 0644]
test/Analysis/diagnostics/undef-value-param.m [new file with mode: 0644]

index 5de06cd3a54d5e79140332c7d6deee50f64350c0..e66022c876d0f323b473a22f99def8926a456ebb 100644 (file)
@@ -461,6 +461,7 @@ public:
 };
 
 /// Represents a point when we begin processing an inlined call.
+/// CallEnter uses the caller's location context.
 class CallEnter : public ProgramPoint {
 public:
   CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, 
index 48393a379b39e227a6d2890a3b44fae527c0413f..c8581e2e23188e0e2f872d44751dee56ab950660 100644 (file)
@@ -24,6 +24,7 @@
 #include "llvm/ADT/ilist_node.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallSet.h"
 
 namespace clang {
 
@@ -95,6 +96,10 @@ protected:
   /// for multiple PathDiagnosticConsumers.
   llvm::SmallVector<Regions *, 2> interestingRegions;
 
+  /// A set of location contexts that correspoind to call sites which should be
+  /// considered "interesting".
+  llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts;
+
   /// A set of custom visitors which generate "event" diagnostics at
   /// interesting points in the path.
   VisitorList Callbacks;
@@ -172,10 +177,12 @@ public:
   void markInteresting(SymbolRef sym);
   void markInteresting(const MemRegion *R);
   void markInteresting(SVal V);
+  void markInteresting(const LocationContext *LC);
   
   bool isInteresting(SymbolRef sym);
   bool isInteresting(const MemRegion *R);
   bool isInteresting(SVal V);
+  bool isInteresting(const LocationContext *LC);
 
   unsigned getConfigurationChangeToken() const {
     return ConfigurationChangeToken;
@@ -342,6 +349,11 @@ private:
   /// A vector of BugReports for tracking the allocated pointers and cleanup.
   std::vector<BugReportEquivClass *> EQClassesVector;
 
+  /// A map from PathDiagnosticPiece to the LocationContext of the inlined
+  /// function call it represents.
+  llvm::DenseMap<const PathDiagnosticCallPiece*,
+                 const LocationContext*> LocationContextMap;
+
 protected:
   BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
                                             D(d) {}
@@ -382,6 +394,8 @@ public:
                                       PathDiagnosticConsumer &PC,
                                       ArrayRef<BugReport *> &bugReports) {}
 
+  bool RemoveUneededCalls(PathPieces &pieces, BugReport *R);
+
   void Register(BugType *BT);
 
   /// \brief Add the given report to the set of reports tracked by BugReporter.
@@ -411,6 +425,10 @@ public:
 
   static bool classof(const BugReporter* R) { return true; }
 
+  void addCallPieceLocationContextPair(const PathDiagnosticCallPiece *C,
+                                       const LocationContext *LC) {
+    LocationContextMap[C] = LC;
+  }
 private:
   llvm::StringMap<BugType *> StrBugTypes;
 
index e82b5233d7198f7a5c5723e8682c43b262ec34a5..f3206964e3a2d93e97f2131e7f7fc6d128e52612 100644 (file)
@@ -222,7 +222,33 @@ public:
                     const ExplodedNode *N,
                     llvm::Optional<bool> &prunable);
 };
-  
+
+/// \brief When a region containing undefined value or '0' value is passed 
+/// as an argument in a call, marks the call as interesting.
+///
+/// As a result, BugReporter will not prune the path through the function even
+/// if the region's contents are not modified/accessed by the call.
+class UndefOrNullArgVisitor
+  : public BugReporterVisitorImpl<UndefOrNullArgVisitor> {
+
+  /// The interesting memory region this visitor is tracking.
+  const MemRegion *R;
+
+public:
+  UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
+
+  virtual void Profile(llvm::FoldingSetNodeID &ID) const {
+    static int Tag = 0;
+    ID.AddPointer(&Tag);
+    ID.AddPointer(R);
+  }
+
+  PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+                                 const ExplodedNode *PrevN,
+                                 BugReporterContext &BRC,
+                                 BugReport &BR);
+};
+
 namespace bugreporter {
 
 void trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R);
index cb0a3ce3e3784f78d37b94404b65d838c686ef88..00128de2b6d79c895e9c4881046e15ffba267529 100644 (file)
@@ -192,7 +192,6 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
         new BugReport(*BT_undef, BT_undef->getDescription(), N);
       bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N),
                                          *report);
-      report->disablePathPruning();
       C.EmitReport(report);
     }
     return;
index 4abda42dd3cb4e3fd447251bbc6e6c647dca51b6..7e9519968591cd615c517524b69170d35e6c3f17 100644 (file)
@@ -53,7 +53,6 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
   BugReport *report = 
     new BugReport(*BT, BT->getDescription(), N);
 
-  report->disablePathPruning();
   report->addRange(RetE->getSourceRange());
   bugreporter::trackNullOrUndefValue(N, RetE, *report);
 
index 8a97b057b51433f30308a50cd45bc037da091164..a50152eb5ab0e472d8317950e7750a690c4d6b08 100644 (file)
@@ -101,7 +101,6 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
       BugReport *R = new BugReport(*BT, BT->getDescription(), N);
       bugreporter::trackNullOrUndefValue(N, Ex, *R);
       R->addRange(Ex->getSourceRange());
-      R->disablePathPruning();
 
       Ctx.EmitReport(R);
     }
index 605f6775f97053125790b00d0121f04a125ca5f9..bbfff0cdc3b26b4b4f901e0d055515031ddc599a 100644 (file)
@@ -81,7 +81,6 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
     else
       bugreporter::trackNullOrUndefValue(N, B, *report);
     
-    report->disablePathPruning();
     C.EmitReport(report);
   }
 }
index 8ae75eaaea6191a74f7887690f77165eaa38eee2..021364bde85d17f52bb7566f6ba43db45215b21d 100644 (file)
@@ -80,7 +80,6 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
     R->addRange(ex->getSourceRange());
     bugreporter::trackNullOrUndefValue(N, ex, *R);
   }
-  R->disablePathPruning();
   C.EmitReport(R);
 }
 
index 571baecd729dfcaf9261bb4d8b797f1c5ee9481b..1866a27f728b5346631dfc0d6d32866b1f5441af 100644 (file)
@@ -121,7 +121,7 @@ GetCurrentOrNextStmt(const ExplodedNode *N) {
 /// Recursively scan through a path and prune out calls and macros pieces
 /// that aren't needed.  Return true if afterwards the path contains
 /// "interesting stuff" which means it should be pruned from the parent path.
-static bool RemoveUneededCalls(PathPieces &pieces) {
+bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R) {
   bool containsSomethingInteresting = false;
   const unsigned N = pieces.size();
   
@@ -134,16 +134,22 @@ static bool RemoveUneededCalls(PathPieces &pieces) {
     switch (piece->getKind()) {
       case PathDiagnosticPiece::Call: {
         PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece);
+        // Check if the location context is interesting.
+        assert(LocationContextMap.count(call));
+        if (R->isInteresting(LocationContextMap[call])) {
+          containsSomethingInteresting = true;
+          break;
+        }
         // Recursively clean out the subclass.  Keep this call around if
         // it contains any informative diagnostics.
-        if (!RemoveUneededCalls(call->path))
+        if (!RemoveUneededCalls(call->path, R))
           continue;
         containsSomethingInteresting = true;
         break;
       }
       case PathDiagnosticPiece::Macro: {
         PathDiagnosticMacroPiece *macro = cast<PathDiagnosticMacroPiece>(piece);
-        if (!RemoveUneededCalls(macro->subPieces))
+        if (!RemoveUneededCalls(macro->subPieces, R))
           continue;
         containsSomethingInteresting = true;
         break;
@@ -430,55 +436,60 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
     NextNode = GetPredecessorNode(N);
 
     ProgramPoint P = N->getLocation();
-    
-    if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) {
-      PathDiagnosticCallPiece *C =
-        PathDiagnosticCallPiece::construct(N, *CE, SMgr);
-      PD.getActivePath().push_front(C);
-      PD.pushActivePath(&C->path);
-      CallStack.push_back(StackDiagPair(C, N));
-      continue;      
-    }
-    
-    if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
-      // Flush all locations, and pop the active path.
-      bool VisitedEntireCall = PD.isWithinCall();
-      PD.popActivePath();
-
-      // Either we just added a bunch of stuff to the top-level path, or
-      // we have a previous CallExitEnd.  If the former, it means that the
-      // path terminated within a function call.  We must then take the
-      // current contents of the active path and place it within
-      // a new PathDiagnosticCallPiece.
-      PathDiagnosticCallPiece *C;
-      if (VisitedEntireCall) {
-        C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front());
-      } else {
-        const Decl *Caller = CE->getLocationContext()->getDecl();
-        C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+
+    do {
+      if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) {
+        PathDiagnosticCallPiece *C =
+            PathDiagnosticCallPiece::construct(N, *CE, SMgr);
+        GRBugReporter& BR = PDB.getBugReporter();
+        BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
+        PD.getActivePath().push_front(C);
+        PD.pushActivePath(&C->path);
+        CallStack.push_back(StackDiagPair(C, N));
+        break;
       }
 
-      C->setCallee(*CE, SMgr);
-      if (!CallStack.empty()) {
-        assert(CallStack.back().first == C);
-        CallStack.pop_back();
+      if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
+        // Flush all locations, and pop the active path.
+        bool VisitedEntireCall = PD.isWithinCall();
+        PD.popActivePath();
+
+        // Either we just added a bunch of stuff to the top-level path, or
+        // we have a previous CallExitEnd.  If the former, it means that the
+        // path terminated within a function call.  We must then take the
+        // current contents of the active path and place it within
+        // a new PathDiagnosticCallPiece.
+        PathDiagnosticCallPiece *C;
+        if (VisitedEntireCall) {
+          C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front());
+        } else {
+          const Decl *Caller = CE->getLocationContext()->getDecl();
+          C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+          GRBugReporter& BR = PDB.getBugReporter();
+          BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
+        }
+
+        C->setCallee(*CE, SMgr);
+        if (!CallStack.empty()) {
+          assert(CallStack.back().first == C);
+          CallStack.pop_back();
+        }
+        break;
       }
-      continue;
-    }
 
-    if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
-      const CFGBlock *Src = BE->getSrc();
-      const CFGBlock *Dst = BE->getDst();
-      const Stmt *T = Src->getTerminator();
+      if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+        const CFGBlock *Src = BE->getSrc();
+        const CFGBlock *Dst = BE->getDst();
+        const Stmt *T = Src->getTerminator();
 
-      if (!T)
-        continue;
+        if (!T)
+          break;
 
-      PathDiagnosticLocation Start =
-        PathDiagnosticLocation::createBegin(T, SMgr,
-                                                N->getLocationContext());
+        PathDiagnosticLocation Start =
+            PathDiagnosticLocation::createBegin(T, SMgr,
+                N->getLocationContext());
 
-      switch (T->getStmtClass()) {
+        switch (T->getStmtClass()) {
         default:
           break;
 
@@ -487,16 +498,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
           const Stmt *S = GetNextStmt(N);
 
           if (!S)
-            continue;
+            break;
 
           std::string sbuf;
           llvm::raw_string_ostream os(sbuf);
           const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S);
 
           os << "Control jumps to line "
-          << End.asLocation().getExpansionLineNumber();
-          PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                                os.str()));
+              << End.asLocation().getExpansionLineNumber();
+          PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+              Start, End, os.str()));
           break;
         }
 
@@ -509,52 +520,52 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
             PathDiagnosticLocation End(S, SMgr, LC);
 
             switch (S->getStmtClass()) {
-              default:
-                os << "No cases match in the switch statement. "
-                "Control jumps to line "
-                << End.asLocation().getExpansionLineNumber();
-                break;
-              case Stmt::DefaultStmtClass:
-                os << "Control jumps to the 'default' case at line "
-                << End.asLocation().getExpansionLineNumber();
-                break;
-
-              case Stmt::CaseStmtClass: {
-                os << "Control jumps to 'case ";
-                const CaseStmt *Case = cast<CaseStmt>(S);
-                const Expr *LHS = Case->getLHS()->IgnoreParenCasts();
-
-                // Determine if it is an enum.
-                bool GetRawInt = true;
-
-                if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
-                  // FIXME: Maybe this should be an assertion.  Are there cases
-                  // were it is not an EnumConstantDecl?
-                  const EnumConstantDecl *D =
+            default:
+              os << "No cases match in the switch statement. "
+              "Control jumps to line "
+              << End.asLocation().getExpansionLineNumber();
+              break;
+            case Stmt::DefaultStmtClass:
+              os << "Control jumps to the 'default' case at line "
+              << End.asLocation().getExpansionLineNumber();
+              break;
+
+            case Stmt::CaseStmtClass: {
+              os << "Control jumps to 'case ";
+              const CaseStmt *Case = cast<CaseStmt>(S);
+              const Expr *LHS = Case->getLHS()->IgnoreParenCasts();
+
+              // Determine if it is an enum.
+              bool GetRawInt = true;
+
+              if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
+                // FIXME: Maybe this should be an assertion.  Are there cases
+                // were it is not an EnumConstantDecl?
+                const EnumConstantDecl *D =
                     dyn_cast<EnumConstantDecl>(DR->getDecl());
 
-                  if (D) {
-                    GetRawInt = false;
-                    os << *D;
-                  }
+                if (D) {
+                  GetRawInt = false;
+                  os << *D;
                 }
+              }
 
-                if (GetRawInt)
-                  os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
+              if (GetRawInt)
+                os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
 
-                os << ":'  at line "
-                << End.asLocation().getExpansionLineNumber();
-                break;
-              }
+              os << ":'  at line "
+                  << End.asLocation().getExpansionLineNumber();
+              break;
             }
-            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                             os.str()));
+            }
+            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+                Start, End, os.str()));
           }
           else {
             os << "'Default' branch taken. ";
             const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N);
-            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                             os.str()));
+            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+                Start, End, os.str()));
           }
 
           break;
@@ -565,12 +576,12 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
           std::string sbuf;
           llvm::raw_string_ostream os(sbuf);
           PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
-          PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                           os.str()));
+          PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+              Start, End, os.str()));
           break;
         }
 
-          // Determine control-flow for ternary '?'.
+        // Determine control-flow for ternary '?'.
         case Stmt::BinaryConditionalOperatorClass:
         case Stmt::ConditionalOperatorClass: {
           std::string sbuf;
@@ -587,12 +598,12 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
           if (const Stmt *S = End.asStmt())
             End = PDB.getEnclosingStmtLocation(S);
 
-          PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                           os.str()));
+          PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+              Start, End, os.str()));
           break;
         }
 
-          // Determine control-flow for short-circuited '&&' and '||'.
+        // Determine control-flow for short-circuited '&&' and '||'.
         case Stmt::BinaryOperatorClass: {
           if (!PDB.supportsLogicalOpControlFlow())
             break;
@@ -609,16 +620,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
               os << "false";
               PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
               PathDiagnosticLocation Start =
-                PathDiagnosticLocation::createOperatorLoc(B, SMgr);
-              PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                               os.str()));
+                  PathDiagnosticLocation::createOperatorLoc(B, SMgr);
+              PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+                  Start, End, os.str()));
             }
             else {
               os << "true";
               PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
               PathDiagnosticLocation End = PDB.ExecutionContinues(N);
-              PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                               os.str()));
+              PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+                  Start, End, os.str()));
             }
           }
           else {
@@ -629,16 +640,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
               os << "false";
               PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
               PathDiagnosticLocation End = PDB.ExecutionContinues(N);
-              PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                               os.str()));
+              PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+                  Start, End, os.str()));
             }
             else {
               os << "true";
               PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
               PathDiagnosticLocation Start =
-                PathDiagnosticLocation::createOperatorLoc(B, SMgr);
-              PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                               os.str()));
+                  PathDiagnosticLocation::createOperatorLoc(B, SMgr);
+              PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+                  Start, End, os.str()));
             }
           }
 
@@ -656,8 +667,8 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
             if (const Stmt *S = End.asStmt())
               End = PDB.getEnclosingStmtLocation(S);
 
-            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                             os.str()));
+            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+                Start, End, os.str()));
           }
           else {
             PathDiagnosticLocation End = PDB.ExecutionContinues(N);
@@ -665,8 +676,8 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
             if (const Stmt *S = End.asStmt())
               End = PDB.getEnclosingStmtLocation(S);
 
-            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                              "Loop condition is false.  Exiting loop"));
+            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+                Start, End, "Loop condition is false.  Exiting loop"));
           }
 
           break;
@@ -683,16 +694,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
             if (const Stmt *S = End.asStmt())
               End = PDB.getEnclosingStmtLocation(S);
 
-            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                             os.str()));
+            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+                Start, End, os.str()));
           }
           else {
             PathDiagnosticLocation End = PDB.ExecutionContinues(N);
             if (const Stmt *S = End.asStmt())
               End = PDB.getEnclosingStmtLocation(S);
 
-            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                            "Loop condition is true.  Entering loop body"));
+            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+                Start, End, "Loop condition is true.  Entering loop body"));
           }
 
           break;
@@ -705,16 +716,17 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
             End = PDB.getEnclosingStmtLocation(S);
 
           if (*(Src->succ_begin()+1) == Dst)
-            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                        "Taking false branch"));
+            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+                Start, End, "Taking false branch"));
           else
-            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                         "Taking true branch"));
+            PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+                Start, End, "Taking true branch"));
 
           break;
         }
+        }
       }
-    }
+    } while(0);
 
     if (NextNode) {
       // Add diagnostic pieces from custom visitors.
@@ -1166,6 +1178,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
         
         PathDiagnosticCallPiece *C =
           PathDiagnosticCallPiece::construct(N, *CE, SM);
+        GRBugReporter& BR = PDB.getBugReporter();
+        BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
 
         EB.addEdge(C->callReturn, true);
         EB.flushLocations();
@@ -1202,6 +1216,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
         } else {
           const Decl *Caller = CE->getLocationContext()->getDecl();
           C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+          GRBugReporter& BR = PDB.getBugReporter();
+          BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
         }
 
         C->setCallee(*CE, SM);
@@ -1414,6 +1430,12 @@ void BugReport::markInteresting(SVal V) {
   markInteresting(V.getAsSymbol());
 }
 
+void BugReport::markInteresting(const LocationContext *LC) {
+  if (!LC)
+    return;
+  InterestingLocationContexts.insert(LC);
+}
+
 bool BugReport::isInteresting(SVal V) {
   return isInteresting(V.getAsRegion()) || isInteresting(V.getAsSymbol());
 }
@@ -1438,6 +1460,12 @@ bool BugReport::isInteresting(const MemRegion *R) {
   return false;
 }
 
+bool BugReport::isInteresting(const LocationContext *LC) {
+  if (!LC)
+    return false;
+  return InterestingLocationContexts.count(LC);
+}
+
 void BugReport::lazyInitializeInterestingSets() {
   if (interestingSymbols.empty()) {
     interestingSymbols.push_back(new Symbols());
@@ -1911,7 +1939,7 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
 
   // Finally, prune the diagnostic path of uninteresting stuff.
   if (R->shouldPrunePath()) {
-    bool hasSomethingInteresting = RemoveUneededCalls(PD.getMutablePieces());
+    bool hasSomethingInteresting = RemoveUneededCalls(PD.getMutablePieces(), R);
     assert(hasSomethingInteresting);
     (void) hasSomethingInteresting;
   }
index a1b7e305e1a8d3a9c5573181dc5506ff56f45328..521b727395dc2d1ddbe1215f8a1548bcb9c83325 100644 (file)
@@ -17,6 +17,7 @@
 #include "clang/AST/ExprObjC.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
@@ -478,6 +479,7 @@ void bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
         SVal V = state->getRawSVal(loc::MemRegionVal(R));
         report.markInteresting(R);
         report.markInteresting(V);
+        report.addVisitor(new UndefOrNullArgVisitor(R));
 
         // If the contents are symbolic, find out when they became null.
         if (V.getAsLocSymbol()) {
@@ -503,6 +505,8 @@ void bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
   // Is it a symbolic value?
   if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
     const MemRegion *Base = L->getRegion()->getBaseRegion();
+    report.addVisitor(new UndefOrNullArgVisitor(Base));
+    
     if (isa<SymbolicRegion>(Base)) {
       report.markInteresting(Base);
       report.addVisitor(new TrackConstraintBRVisitor(loc::MemRegionVal(Base),
@@ -950,3 +954,54 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
   return event;
 }
 
+PathDiagnosticPiece *
+UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
+                                  const ExplodedNode *PrevN,
+                                  BugReporterContext &BRC,
+                                  BugReport &BR) {
+
+  ProgramStateRef State = N->getState();
+  ProgramPoint ProgLoc = N->getLocation();
+
+  // We are only interested in visiting CallEnter nodes.
+  CallEnter *CEnter = dyn_cast<CallEnter>(&ProgLoc);
+  if (!CEnter)
+    return 0;
+
+  // Check if one of the arguments is the region the visitor is tracking.
+  CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
+  CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State);
+  unsigned Idx = 0;
+  for (CallEvent::param_iterator I = Call->param_begin(),
+                                 E = Call->param_end(); I != E; ++I, ++Idx) {
+    const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion();
+
+    // Are we tracking the argument?
+    if ( !ArgReg || ArgReg != R)
+      return 0;
+
+    // Check the function parameter type.
+    const ParmVarDecl *ParamDecl = *I;
+    assert(ParamDecl && "Formal parameter has no decl?");
+    QualType T = ParamDecl->getType();
+
+    if (!(T->isAnyPointerType() || T->isReferenceType())) {
+      // Function can only change the value passed in by address.
+      return 0;
+    }
+    
+    // If it is a const pointer value, the function does not intend to
+    // change the value.
+    if (T->getPointeeType().isConstQualified())
+      return 0;
+
+    // Mark the call site (LocationContext) as interesting if the value of the 
+    // argument is undefined or '0'/'NULL'.
+    SVal BoundVal = State->getSVal(ArgReg);
+    if (BoundVal.isUndef() || BoundVal.isZeroConstant()) {
+      BR.markInteresting(CEnter->getCalleeContext());
+      return 0;
+    }
+  }
+  return 0;
+}
index 928839d0404da850df7ffe3f2df3c0b015d9f8e9..627b334971b6ff7c3388d4708375162cfcdb5d3b 100644 (file)
 #include "undef-value-callee.h"
 
 // This code used to cause a crash since we were not adding fileID of the header to the plist diagnostic.
-// Note, in the future, we do not even need to step into this callee since it does not influence the result.
+
 int test_calling_unimportant_callee(int argc, char *argv[]) {
   int x;
   callee();
   return x; // expected-warning {{Undefined or garbage value returned to caller}}
 }
 
-// CHECK: <?xml version="1.0" encoding="UTF-8"?>
-// CHECK: <plist version="1.0">
-// CHECK: <dict>
-// CHECK:  <key>files</key>
-// CHECK:  <array>
-// CHECK:  </array>
-// CHECK:  <key>diagnostics</key>
-// CHECK:  <array>
-// CHECK:   <dict>
-// CHECK:    <key>path</key>
-// CHECK:    <array>
-// CHECK:     <dict>
-// CHECK:      <key>kind</key><string>event</string>
-// CHECK:      <key>location</key>
-// CHECK:      <dict>
-// CHECK:       <key>line</key><integer>9</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>9</integer>
-// CHECK:          <key>col</key><integer>3</integer>
-// CHECK:          <key>file</key><integer>0</integer>
-// CHECK:         </dict>
-// CHECK:         <dict>
-// CHECK:          <key>line</key><integer>9</integer>
-// CHECK:          <key>col</key><integer>7</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>Variable &apos;x&apos; declared without an initial value</string>
-// CHECK:      <key>message</key>
-// CHECK: <string>Variable &apos;x&apos; declared without an initial 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>9</integer>
-// CHECK:            <key>col</key><integer>3</integer>
-// CHECK:            <key>file</key><integer>0</integer>
-// CHECK:           </dict>
-// CHECK:           <dict>
-// CHECK:            <key>line</key><integer>9</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>10</integer>
-// CHECK:            <key>col</key><integer>3</integer>
-// CHECK:            <key>file</key><integer>0</integer>
-// CHECK:           </dict>
-// CHECK:           <dict>
-// CHECK:            <key>line</key><integer>10</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>10</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>10</integer>
-// CHECK:          <key>col</key><integer>3</integer>
-// CHECK:          <key>file</key><integer>0</integer>
-// CHECK:         </dict>
-// CHECK:         <dict>
-// CHECK:          <key>line</key><integer>10</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>0</integer>
-// CHECK:      <key>extended_message</key>
-// CHECK:      <string>Calling &apos;callee&apos;</string>
-// CHECK:      <key>message</key>
-// CHECK: <string>Calling &apos;callee&apos;</string>
-// CHECK:     </dict>
-// CHECK:     <dict>
-// CHECK:      <key>kind</key><string>event</string>
-// CHECK:      <key>location</key>
-// CHECK:      <dict>
-// CHECK:       <key>line</key><integer>2</integer>
-// CHECK:       <key>col</key><integer>1</integer>
-// CHECK:       <key>file</key><integer>1</integer>
-// CHECK:      </dict>
-// CHECK:      <key>depth</key><integer>1</integer>
-// CHECK:      <key>extended_message</key>
-// CHECK:      <string>Entered call from &apos;test_calling_unimportant_callee&apos;</string>
-// CHECK:      <key>message</key>
-// CHECK: <string>Entered call from &apos;test_calling_unimportant_callee&apos;</string>
-// CHECK:     </dict>
-// CHECK:     <dict>
-// CHECK:      <key>kind</key><string>event</string>
-// CHECK:      <key>location</key>
-// CHECK:      <dict>
-// CHECK:       <key>line</key><integer>10</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>10</integer>
-// CHECK:          <key>col</key><integer>3</integer>
-// CHECK:          <key>file</key><integer>0</integer>
-// CHECK:         </dict>
-// CHECK:         <dict>
-// CHECK:          <key>line</key><integer>10</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 from &apos;callee&apos;</string>
-// CHECK:      <key>message</key>
-// CHECK: <string>Returning from &apos;callee&apos;</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>10</integer>
-// CHECK:            <key>col</key><integer>3</integer>
-// CHECK:            <key>file</key><integer>0</integer>
-// CHECK:           </dict>
-// CHECK:           <dict>
-// CHECK:            <key>line</key><integer>10</integer>
-// CHECK:            <key>col</key><integer>8</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>11</integer>
-// CHECK:            <key>col</key><integer>3</integer>
-// CHECK:            <key>file</key><integer>0</integer>
-// CHECK:           </dict>
-// CHECK:           <dict>
-// CHECK:            <key>line</key><integer>11</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>11</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>11</integer>
-// CHECK:          <key>col</key><integer>10</integer>
-// CHECK:          <key>file</key><integer>0</integer>
-// CHECK:         </dict>
-// CHECK:         <dict>
-// CHECK:          <key>line</key><integer>11</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>0</integer>
-// CHECK:      <key>extended_message</key>
-// CHECK:      <string>Undefined or garbage value returned to caller</string>
-// CHECK:      <key>message</key>
-// CHECK: <string>Undefined or garbage value returned to caller</string>
-// CHECK:     </dict>
-// CHECK:    </array>
-// CHECK:    <key>description</key><string>Undefined or garbage value returned to caller</string>
-// CHECK:    <key>category</key><string>Logic error</string>
-// CHECK:    <key>type</key><string>Garbage return value</string>
-// CHECK:   <key>issue_context_kind</key><string>function</string>
-// CHECK:   <key>issue_context</key><string>test_calling_unimportant_callee</string>
-// CHECK:   <key>location</key>
-// CHECK:   <dict>
-// CHECK:    <key>line</key><integer>11</integer>
-// CHECK:    <key>col</key><integer>3</integer>
-// CHECK:    <key>file</key><integer>0</integer>
-// CHECK:   </dict>
-// CHECK:   </dict>
-// CHECK:  </array>
-// CHECK: </dict>
-// CHECK: </plist>
+//CHECK: <dict>
+//CHECK:  <key>files</key>
+//CHECK:  <array>
+//CHECK:  </array>
+//CHECK:  <key>diagnostics</key>
+//CHECK:  <array>
+//CHECK:   <dict>
+//CHECK:    <key>path</key>
+//CHECK:    <array>
+//CHECK:     <dict>
+//CHECK:      <key>kind</key><string>event</string>
+//CHECK:      <key>location</key>
+//CHECK:      <dict>
+//CHECK:       <key>line</key><integer>9</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>9</integer>
+//CHECK:          <key>col</key><integer>3</integer>
+//CHECK:          <key>file</key><integer>0</integer>
+//CHECK:         </dict>
+//CHECK:         <dict>
+//CHECK:          <key>line</key><integer>9</integer>
+//CHECK:          <key>col</key><integer>7</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>Variable &apos;x&apos; declared without an initial value</string>
+//CHECK:      <key>message</key>
+//CHECK: <string>Variable &apos;x&apos; declared without an initial 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>9</integer>
+//CHECK:            <key>col</key><integer>3</integer>
+//CHECK:            <key>file</key><integer>0</integer>
+//CHECK:           </dict>
+//CHECK:           <dict>
+//CHECK:            <key>line</key><integer>9</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>10</integer>
+//CHECK:            <key>col</key><integer>3</integer>
+//CHECK:            <key>file</key><integer>0</integer>
+//CHECK:           </dict>
+//CHECK:           <dict>
+//CHECK:            <key>line</key><integer>10</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>control</string>
+//CHECK:      <key>edges</key>
+//CHECK:       <array>
+//CHECK:        <dict>
+//CHECK:         <key>start</key>
+//CHECK:          <array>
+//CHECK:           <dict>
+//CHECK:            <key>line</key><integer>10</integer>
+//CHECK:            <key>col</key><integer>3</integer>
+//CHECK:            <key>file</key><integer>0</integer>
+//CHECK:           </dict>
+//CHECK:           <dict>
+//CHECK:            <key>line</key><integer>10</integer>
+//CHECK:            <key>col</key><integer>8</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>11</integer>
+//CHECK:            <key>col</key><integer>3</integer>
+//CHECK:            <key>file</key><integer>0</integer>
+//CHECK:           </dict>
+//CHECK:           <dict>
+//CHECK:            <key>line</key><integer>11</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>11</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>11</integer>
+//CHECK:          <key>col</key><integer>10</integer>
+//CHECK:          <key>file</key><integer>0</integer>
+//CHECK:         </dict>
+//CHECK:         <dict>
+//CHECK:          <key>line</key><integer>11</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>0</integer>
+//CHECK:      <key>extended_message</key>
+//CHECK:      <string>Undefined or garbage value returned to caller</string>
+//CHECK:      <key>message</key>
+//CHECK: <string>Undefined or garbage value returned to caller</string>
+//CHECK:     </dict>
+//CHECK:    </array>
+//CHECK:    <key>description</key><string>Undefined or garbage value returned to caller</string>
+//CHECK:    <key>category</key><string>Logic error</string>
+//CHECK:    <key>type</key><string>Garbage return value</string>
+//CHECK:   <key>issue_context_kind</key><string>function</string>
+//CHECK:   <key>issue_context</key><string>test_calling_unimportant_callee</string>
+//CHECK:   <key>issue_hash</key><integer>3</integer>
+//CHECK:   <key>location</key>
+//CHECK:   <dict>
+//CHECK:    <key>line</key><integer>11</integer>
+//CHECK:    <key>col</key><integer>3</integer>
+//CHECK:    <key>file</key><integer>0</integer>
+//CHECK:   </dict>
+//CHECK:   </dict>
+//CHECK:  </array>
+//CHECK: </dict>
+//CHECK: </plist>
diff --git a/test/Analysis/diagnostics/undef-value-param.c b/test/Analysis/diagnostics/undef-value-param.c
new file mode 100644 (file)
index 0000000..94fbb11
--- /dev/null
@@ -0,0 +1,451 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file %s -o - | FileCheck %s
+
+void foo_irrelevant(int c) {
+    if (c)
+        return;
+    c++;
+    return;
+}
+void foo(int *x, int c) {
+    if (c)
+           //expected-note@-1{{Assuming 'c' is not equal to 0}}
+           //expected-note@-2{{Taking true branch}}
+        return;
+    *x = 5;
+}
+
+int use(int c) {
+    int xx; //expected-note{{Variable 'xx' declared without an initial value}}
+    int *y = &xx;
+    foo (y, c);
+                //expected-note@-1{{Calling 'foo'}}
+                //expected-note@-2{{Returning from 'foo'}}
+    foo_irrelevant(c);
+    return xx+3; //expected-warning{{The left operand of '+' is a garbage value}}
+                 //expected-note@-1{{The left operand of '+' is a garbage value}}
+}
+
+//CHECK:  <dict>
+//CHECK:   <key>files</key>
+//CHECK:   <array>
+//CHECK:   </array>
+//CHECK:   <key>diagnostics</key>
+//CHECK:   <array>
+//CHECK:    <dict>
+//CHECK:     <key>path</key>
+//CHECK:     <array>
+//CHECK:      <dict>
+//CHECK:       <key>kind</key><string>event</string>
+//CHECK:       <key>location</key>
+//CHECK:       <dict>
+//CHECK:        <key>line</key><integer>19</integer>
+//CHECK:        <key>col</key><integer>5</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>19</integer>
+//CHECK:           <key>col</key><integer>5</integer>
+//CHECK:           <key>file</key><integer>0</integer>
+//CHECK:          </dict>
+//CHECK:          <dict>
+//CHECK:           <key>line</key><integer>19</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>0</integer>
+//CHECK:       <key>extended_message</key>
+//CHECK:       <string>Variable &apos;xx&apos; declared without an initial value</string>
+//CHECK:       <key>message</key>
+//CHECK:  <string>Variable &apos;xx&apos; declared without an initial 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>19</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>19</integer>
+//CHECK:             <key>col</key><integer>7</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>21</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>21</integer>
+//CHECK:             <key>col</key><integer>7</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>21</integer>
+//CHECK:        <key>col</key><integer>5</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>21</integer>
+//CHECK:           <key>col</key><integer>5</integer>
+//CHECK:           <key>file</key><integer>0</integer>
+//CHECK:          </dict>
+//CHECK:          <dict>
+//CHECK:           <key>line</key><integer>21</integer>
+//CHECK:           <key>col</key><integer>14</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 &apos;foo&apos;</string>
+//CHECK:       <key>message</key>
+//CHECK:  <string>Calling &apos;foo&apos;</string>
+//CHECK:      </dict>
+//CHECK:      <dict>
+//CHECK:       <key>kind</key><string>event</string>
+//CHECK:       <key>location</key>
+//CHECK:       <dict>
+//CHECK:        <key>line</key><integer>10</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 &apos;use&apos;</string>
+//CHECK:       <key>message</key>
+//CHECK:  <string>Entered call from &apos;use&apos;</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>10</integer>
+//CHECK:             <key>col</key><integer>1</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>10</integer>
+//CHECK:             <key>col</key><integer>4</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>11</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>11</integer>
+//CHECK:             <key>col</key><integer>6</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>control</string>
+//CHECK:       <key>edges</key>
+//CHECK:        <array>
+//CHECK:         <dict>
+//CHECK:          <key>start</key>
+//CHECK:           <array>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>11</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>11</integer>
+//CHECK:             <key>col</key><integer>6</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>11</integer>
+//CHECK:             <key>col</key><integer>9</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>11</integer>
+//CHECK:             <key>col</key><integer>9</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>11</integer>
+//CHECK:        <key>col</key><integer>9</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>11</integer>
+//CHECK:           <key>col</key><integer>9</integer>
+//CHECK:           <key>file</key><integer>0</integer>
+//CHECK:          </dict>
+//CHECK:          <dict>
+//CHECK:           <key>line</key><integer>11</integer>
+//CHECK:           <key>col</key><integer>9</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>Assuming &apos;c&apos; is not equal to 0</string>
+//CHECK:       <key>message</key>
+//CHECK:  <string>Assuming &apos;c&apos; is not equal to 0</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>11</integer>
+//CHECK:             <key>col</key><integer>9</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>11</integer>
+//CHECK:             <key>col</key><integer>9</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>14</integer>
+//CHECK:             <key>col</key><integer>9</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>14</integer>
+//CHECK:             <key>col</key><integer>14</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>21</integer>
+//CHECK:        <key>col</key><integer>5</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>21</integer>
+//CHECK:           <key>col</key><integer>5</integer>
+//CHECK:           <key>file</key><integer>0</integer>
+//CHECK:          </dict>
+//CHECK:          <dict>
+//CHECK:           <key>line</key><integer>21</integer>
+//CHECK:           <key>col</key><integer>14</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 &apos;foo&apos;</string>
+//CHECK:       <key>message</key>
+//CHECK:  <string>Returning from &apos;foo&apos;</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>21</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>21</integer>
+//CHECK:             <key>col</key><integer>7</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>24</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>24</integer>
+//CHECK:             <key>col</key><integer>18</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>control</string>
+//CHECK:       <key>edges</key>
+//CHECK:        <array>
+//CHECK:         <dict>
+//CHECK:          <key>start</key>
+//CHECK:           <array>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>24</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>24</integer>
+//CHECK:             <key>col</key><integer>18</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>25</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>25</integer>
+//CHECK:             <key>col</key><integer>10</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>control</string>
+//CHECK:       <key>edges</key>
+//CHECK:        <array>
+//CHECK:         <dict>
+//CHECK:          <key>start</key>
+//CHECK:           <array>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>25</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>25</integer>
+//CHECK:             <key>col</key><integer>10</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>25</integer>
+//CHECK:             <key>col</key><integer>12</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>25</integer>
+//CHECK:             <key>col</key><integer>13</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>25</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>25</integer>
+//CHECK:           <key>col</key><integer>12</integer>
+//CHECK:           <key>file</key><integer>0</integer>
+//CHECK:          </dict>
+//CHECK:          <dict>
+//CHECK:           <key>line</key><integer>25</integer>
+//CHECK:           <key>col</key><integer>13</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>The left operand of &apos;+&apos; is a garbage value</string>
+//CHECK:       <key>message</key>
+//CHECK:  <string>The left operand of &apos;+&apos; is a garbage value</string>
+//CHECK:      </dict>
+//CHECK:     </array>
+//CHECK:     <key>description</key><string>The left operand of &apos;+&apos; is a garbage value</string>
+//CHECK:     <key>category</key><string>Logic error</string>
+//CHECK:     <key>type</key><string>Result of operation is garbage or undefined</string>
+//CHECK:    <key>issue_context_kind</key><string>function</string>
+//CHECK:    <key>issue_context</key><string>use</string>
+//CHECK:    <key>issue_hash</key><integer>7</integer>
+//CHECK:    <key>location</key>
+//CHECK:    <dict>
+//CHECK:     <key>line</key><integer>25</integer>
+//CHECK:     <key>col</key><integer>12</integer>
+//CHECK:     <key>file</key><integer>0</integer>
+//CHECK:    </dict>
+//CHECK:    </dict>
+//CHECK:   </array>
+//CHECK:  </dict>
+//CHECK:  </plist>
diff --git a/test/Analysis/diagnostics/undef-value-param.m b/test/Analysis/diagnostics/undef-value-param.m
new file mode 100644 (file)
index 0000000..ae82839
--- /dev/null
@@ -0,0 +1,476 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-output=plist-multi-file %s -o - | FileCheck %s
+
+typedef signed char BOOL;
+@protocol NSObject  - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {}
++(id)alloc;
++(id)new;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+@end
+typedef const void * CFTypeRef;
+extern void CFRelease(CFTypeRef cf);
+
+@interface Cell : NSObject
+- (void)test;
+@end
+
+@interface SpecialString
++ (id)alloc;
+- (oneway void)release;
+@end
+
+typedef SpecialString* SCDynamicStoreRef;
+static void CreateRef(SCDynamicStoreRef *storeRef, unsigned x);
+SCDynamicStoreRef anotherCreateRef(unsigned *err, unsigned x);
+
+@implementation Cell
+- (void) test {
+    SCDynamicStoreRef storeRef = 0; //expected-note{{Variable 'storeRef' initialized to nil}}
+    CreateRef(&storeRef, 4); 
+                             //expected-note@-1{{Calling 'CreateRef'}}
+                             //expected-note@-2{{Returning from 'CreateRef'}}
+    CFRelease(storeRef); //expected-warning {{Null pointer argument in call to CFRelease}}
+                         //expected-note@-1{{Null pointer argument in call to CFRelease}}
+}
+@end
+
+static void CreateRef(SCDynamicStoreRef *storeRef, unsigned x) {
+    unsigned err = 0;
+    SCDynamicStoreRef ref = anotherCreateRef(&err, x); // why this is being inlined?
+    if (err) { 
+               //expected-note@-1{{Assuming 'err' is not equal to 0}}
+               //expected-note@-2{{Taking true branch}}
+        CFRelease(ref);
+        ref = 0;
+    }
+    *storeRef = ref;
+}
+
+//CHECK:  <dict>
+//CHECK:   <key>files</key>
+//CHECK:   <array>
+//CHECK:   </array>
+//CHECK:   <key>diagnostics</key>
+//CHECK:   <array>
+//CHECK:    <dict>
+//CHECK:     <key>path</key>
+//CHECK:     <array>
+//CHECK:      <dict>
+//CHECK:       <key>kind</key><string>event</string>
+//CHECK:       <key>location</key>
+//CHECK:       <dict>
+//CHECK:        <key>line</key><integer>33</integer>
+//CHECK:        <key>col</key><integer>5</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>33</integer>
+//CHECK:           <key>col</key><integer>5</integer>
+//CHECK:           <key>file</key><integer>0</integer>
+//CHECK:          </dict>
+//CHECK:          <dict>
+//CHECK:           <key>line</key><integer>33</integer>
+//CHECK:           <key>col</key><integer>30</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>Variable &apos;storeRef&apos; initialized to nil</string>
+//CHECK:       <key>message</key>
+//CHECK:  <string>Variable &apos;storeRef&apos; initialized to nil</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>33</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>33</integer>
+//CHECK:             <key>col</key><integer>21</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>34</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>34</integer>
+//CHECK:             <key>col</key><integer>13</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>34</integer>
+//CHECK:        <key>col</key><integer>5</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>34</integer>
+//CHECK:           <key>col</key><integer>5</integer>
+//CHECK:           <key>file</key><integer>0</integer>
+//CHECK:          </dict>
+//CHECK:          <dict>
+//CHECK:           <key>line</key><integer>34</integer>
+//CHECK:           <key>col</key><integer>27</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 &apos;CreateRef&apos;</string>
+//CHECK:       <key>message</key>
+//CHECK:  <string>Calling &apos;CreateRef&apos;</string>
+//CHECK:      </dict>
+//CHECK:      <dict>
+//CHECK:       <key>kind</key><string>event</string>
+//CHECK:       <key>location</key>
+//CHECK:       <dict>
+//CHECK:        <key>line</key><integer>42</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 &apos;test&apos;</string>
+//CHECK:       <key>message</key>
+//CHECK:  <string>Entered call from &apos;test&apos;</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>42</integer>
+//CHECK:             <key>col</key><integer>1</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>42</integer>
+//CHECK:             <key>col</key><integer>6</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>43</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>43</integer>
+//CHECK:             <key>col</key><integer>12</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>control</string>
+//CHECK:       <key>edges</key>
+//CHECK:        <array>
+//CHECK:         <dict>
+//CHECK:          <key>start</key>
+//CHECK:           <array>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>43</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>43</integer>
+//CHECK:             <key>col</key><integer>12</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>45</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>45</integer>
+//CHECK:             <key>col</key><integer>6</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>control</string>
+//CHECK:       <key>edges</key>
+//CHECK:        <array>
+//CHECK:         <dict>
+//CHECK:          <key>start</key>
+//CHECK:           <array>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>45</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>45</integer>
+//CHECK:             <key>col</key><integer>6</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>45</integer>
+//CHECK:             <key>col</key><integer>9</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>45</integer>
+//CHECK:             <key>col</key><integer>11</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>45</integer>
+//CHECK:        <key>col</key><integer>9</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>45</integer>
+//CHECK:           <key>col</key><integer>9</integer>
+//CHECK:           <key>file</key><integer>0</integer>
+//CHECK:          </dict>
+//CHECK:          <dict>
+//CHECK:           <key>line</key><integer>45</integer>
+//CHECK:           <key>col</key><integer>11</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>Assuming &apos;err&apos; is not equal to 0</string>
+//CHECK:       <key>message</key>
+//CHECK:  <string>Assuming &apos;err&apos; is not equal to 0</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>45</integer>
+//CHECK:             <key>col</key><integer>9</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>45</integer>
+//CHECK:             <key>col</key><integer>11</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>48</integer>
+//CHECK:             <key>col</key><integer>9</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>48</integer>
+//CHECK:             <key>col</key><integer>17</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>control</string>
+//CHECK:       <key>edges</key>
+//CHECK:        <array>
+//CHECK:         <dict>
+//CHECK:          <key>start</key>
+//CHECK:           <array>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>48</integer>
+//CHECK:             <key>col</key><integer>9</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>48</integer>
+//CHECK:             <key>col</key><integer>17</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>51</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>51</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>34</integer>
+//CHECK:        <key>col</key><integer>5</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>34</integer>
+//CHECK:           <key>col</key><integer>5</integer>
+//CHECK:           <key>file</key><integer>0</integer>
+//CHECK:          </dict>
+//CHECK:          <dict>
+//CHECK:           <key>line</key><integer>34</integer>
+//CHECK:           <key>col</key><integer>27</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 &apos;CreateRef&apos;</string>
+//CHECK:       <key>message</key>
+//CHECK:  <string>Returning from &apos;CreateRef&apos;</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>34</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>34</integer>
+//CHECK:             <key>col</key><integer>13</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>37</integer>
+//CHECK:             <key>col</key><integer>5</integer>
+//CHECK:             <key>file</key><integer>0</integer>
+//CHECK:            </dict>
+//CHECK:            <dict>
+//CHECK:             <key>line</key><integer>37</integer>
+//CHECK:             <key>col</key><integer>13</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>37</integer>
+//CHECK:        <key>col</key><integer>5</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>37</integer>
+//CHECK:           <key>col</key><integer>15</integer>
+//CHECK:           <key>file</key><integer>0</integer>
+//CHECK:          </dict>
+//CHECK:          <dict>
+//CHECK:           <key>line</key><integer>37</integer>
+//CHECK:           <key>col</key><integer>22</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>Null pointer argument in call to CFRelease</string>
+//CHECK:       <key>message</key>
+//CHECK:  <string>Null pointer argument in call to CFRelease</string>
+//CHECK:      </dict>
+//CHECK:     </array>
+//CHECK:     <key>description</key><string>Null pointer argument in call to CFRelease</string>
+//CHECK:     <key>category</key><string>API Misuse (Apple)</string>
+//CHECK:     <key>type</key><string>null passed to CFRetain/CFRelease</string>
+//CHECK:    <key>issue_context_kind</key><string>Objective-C method</string>
+//CHECK:    <key>issue_context</key><string>test</string>
+//CHECK:    <key>issue_hash</key><integer>5</integer>
+//CHECK:    <key>location</key>
+//CHECK:    <dict>
+//CHECK:     <key>line</key><integer>37</integer>
+//CHECK:     <key>col</key><integer>5</integer>
+//CHECK:     <key>file</key><integer>0</integer>
+//CHECK:    </dict>
+//CHECK:    </dict>
+//CHECK:   </array>
+//CHECK:  </dict>
+//CHECK:  </plist>