]> granicus.if.org Git - clang/commitdiff
[analyzer] Assign truly stable identifiers to exploded nodes.
authorArtem Dergachev <artem.dergachev@gmail.com>
Thu, 17 Oct 2019 23:10:09 +0000 (23:10 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Thu, 17 Oct 2019 23:10:09 +0000 (23:10 +0000)
ExplodedGraph nodes will now have a numeric identifier stored in them
which will keep track of the order in which the nodes were created
and it will be fully deterministic both accross runs and across machines.

This is extremely useful for debugging as it allows reliably setting
conditional breakpoints by node IDs.

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

19 files changed:
include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
lib/StaticAnalyzer/Core/BugReporter.cpp
lib/StaticAnalyzer/Core/ExplodedGraph.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/Analysis/dump_egraph.c
test/Analysis/exploded-graph-rewriter/checker_messages.dot
test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot
test/Analysis/exploded-graph-rewriter/constraints.dot
test/Analysis/exploded-graph-rewriter/constraints_diff.dot
test/Analysis/exploded-graph-rewriter/edge.dot
test/Analysis/exploded-graph-rewriter/environment.dot
test/Analysis/exploded-graph-rewriter/environment_diff.dot
test/Analysis/exploded-graph-rewriter/node_labels.dot
test/Analysis/exploded-graph-rewriter/program_points.dot
test/Analysis/exploded-graph-rewriter/store.dot
test/Analysis/exploded-graph-rewriter/store_diff.dot
test/Analysis/exploded-graph-rewriter/topology.dot
test/Analysis/exploded-graph-rewriter/trimmers.dot
utils/analyzer/exploded-graph-rewriter.py

index 9773a552bf9e2d3c1efa87d31e3e5a7aeaa8dc2c..e87772c04b9be1679cca53a3d0e96153a2a64a98 100644 (file)
@@ -131,10 +131,12 @@ class ExplodedNode : public llvm::FoldingSetNode {
   /// Succs - The successors of this node.
   NodeGroup Succs;
 
+  int64_t Id;
+
 public:
   explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state,
-                        bool IsSink)
-      : Location(loc), State(std::move(state)), Succs(IsSink) {
+                        int64_t Id, bool IsSink)
+      : Location(loc), State(std::move(state)), Succs(IsSink), Id(Id) {
     assert(isSink() == IsSink);
   }
 
@@ -258,7 +260,7 @@ public:
   }
   const_succ_range succs() const { return {Succs.begin(), Succs.end()}; }
 
-  int64_t getID(ExplodedGraph *G) const;
+  int64_t getID() const { return Id; }
 
   /// The node is trivial if it has only one successor, only one predecessor,
   /// it's predecessor has only one successor,
@@ -324,7 +326,7 @@ protected:
   BumpVectorContext BVC;
 
   /// NumNodes - The number of nodes in the graph.
-  unsigned NumNodes = 0;
+  int64_t NumNodes = 0;
 
   /// A list of recently allocated nodes that can potentially be recycled.
   NodeVector ChangedNodes;
@@ -358,6 +360,7 @@ public:
   ///  ExplodedGraph for further processing.
   ExplodedNode *createUncachedNode(const ProgramPoint &L,
     ProgramStateRef State,
+    int64_t Id,
     bool IsSink = false);
 
   std::unique_ptr<ExplodedGraph> MakeEmptyGraph() const {
index f689d8e76af3fa5f3abc56e949371a7206ce9b61..1864bcef9b8733619b5901541defb04c03e3b9d2 100644 (file)
@@ -2566,7 +2566,8 @@ BugPathInfo *BugPathGetter::getNextBugPath() {
     // Create the equivalent node in the new graph with the same state
     // and location.
     ExplodedNode *NewN = GNew->createUncachedNode(
-        OrigN->getLocation(), OrigN->getState(), OrigN->isSink());
+        OrigN->getLocation(), OrigN->getState(),
+        OrigN->getID(), OrigN->isSink());
 
     // Link up the new node with the previous node.
     if (Succ)
index a8fa7ad2d98c53e60525f4299534b67071331d69..c4838492271cde6642871bb90cba5a30e4467166 100644 (file)
@@ -283,10 +283,6 @@ ExplodedNode * const *ExplodedNode::NodeGroup::end() const {
   return Storage.getAddrOfPtr1() + 1;
 }
 
-int64_t ExplodedNode::getID(ExplodedGraph *G) const {
-  return G->getAllocator().identifyKnownAlignedObject<ExplodedNode>(this);
-}
-
 bool ExplodedNode::isTrivial() const {
   return pred_size() == 1 && succ_size() == 1 &&
          getFirstPred()->getState()->getID() == getState()->getID() &&
@@ -417,14 +413,14 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
       V = (NodeTy*) getAllocator().Allocate<NodeTy>();
     }
 
-    new (V) NodeTy(L, State, IsSink);
+    ++NumNodes;
+    new (V) NodeTy(L, State, NumNodes, IsSink);
 
     if (ReclaimNodeInterval)
       ChangedNodes.push_back(V);
 
     // Insert the node into the node set and return it.
     Nodes.InsertNode(V, InsertPos);
-    ++NumNodes;
 
     if (IsNew) *IsNew = true;
   }
@@ -436,9 +432,10 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
 
 ExplodedNode *ExplodedGraph::createUncachedNode(const ProgramPoint &L,
                                                 ProgramStateRef State,
+                                                int64_t Id,
                                                 bool IsSink) {
   NodeTy *V = (NodeTy *) getAllocator().Allocate<NodeTy>();
-  new (V) NodeTy(L, State, IsSink);
+  new (V) NodeTy(L, State, Id, IsSink);
   return V;
 }
 
@@ -498,7 +495,8 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
 
     // Create the corresponding node in the new graph and record the mapping
     // from the old node to the new node.
-    ExplodedNode *NewN = G->createUncachedNode(N->getLocation(), N->State, N->isSink());
+    ExplodedNode *NewN = G->createUncachedNode(N->getLocation(), N->State,
+                                               N->getID(), N->isSink());
     Pass2[N] = NewN;
 
     // Also record the reverse mapping from the new node to the old node.
index 8629fd98db5d7ec13834791dedfde9c0415f181e..ea1df1b0df8ab57e168f7a9a38960a7708bbb956 100644 (file)
@@ -3061,16 +3061,7 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
     const unsigned int Space = 1;
     ProgramStateRef State = N->getState();
 
-    auto Noop = [](const ExplodedNode*){};
-    bool HasReport = traverseHiddenNodes(
-        N, Noop, Noop, &nodeHasBugReport);
-    bool IsSink = traverseHiddenNodes(
-        N, Noop, Noop, [](const ExplodedNode *N) { return N->isSink(); });
-
-    Out << "{ \"node_id\": " << N->getID(G) << ", \"pointer\": \""
-        << (const void *)N << "\", \"state_id\": " << State->getID()
-        << ", \"has_report\": " << (HasReport ? "true" : "false")
-        << ", \"is_sink\": " << (IsSink ? "true" : "false")
+    Out << "{ \"state_id\": " << State->getID()
         << ",\\l";
 
     Indent(Out, Space, IsDot) << "\"program_points\": [\\l";
@@ -3083,9 +3074,12 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
           OtherNode->getLocation().printJson(Out, /*NL=*/"\\l");
           Out << ", \"tag\": ";
           if (const ProgramPointTag *Tag = OtherNode->getLocation().getTag())
-            Out << '\"' << Tag->getTagDescription() << "\" }";
+            Out << '\"' << Tag->getTagDescription() << "\"";
           else
-            Out << "null }";
+            Out << "null";
+          Out << ", \"node_id\": " << OtherNode->getID() <<
+                 ", \"is_sink\": " << OtherNode->isSink() <<
+                 ", \"has_report\": " << nodeHasBugReport(OtherNode) << " }";
         },
         // Adds a comma and a new-line between each program point.
         [&](const ExplodedNode *) { Out << ",\\l"; },
index 99463da3e798e236c626435658964903b6465a1e..4ad04002c404f52944b1c539aed9c6d1bb088a6b 100644 (file)
@@ -18,7 +18,7 @@ int foo() {
   return *x + *y;
 }
 
-// CHECK: \"program_points\": [\l&nbsp;&nbsp;&nbsp;&nbsp;\{ \"kind\": \"Edge\", \"src_id\": 2, \"dst_id\": 1, \"terminator\": null, \"term_kind\": null, \"tag\": null \}\l&nbsp;&nbsp;],\l&nbsp;&nbsp;\"program_state\": null
+// CHECK: \"program_points\": [\l&nbsp;&nbsp;&nbsp;&nbsp;\{ \"kind\": \"Edge\", \"src_id\": 2, \"dst_id\": 1, \"terminator\": null, \"term_kind\": null, \"tag\": null, \"node_id\": 1, \"is_sink\":0, \"has_report\": 0 \}\l&nbsp;&nbsp;],\l&nbsp;&nbsp;\"program_state\": null
 
 // CHECK: \"program_points\": [\l&nbsp;&nbsp;&nbsp;&nbsp;\{ \"kind\": \"BlockEntrance\", \"block_id\": 1
 
@@ -27,4 +27,4 @@ int foo() {
 
 // CHECK: \"pretty\": \"'\\\\x13'\"
 
-// CHECK: \"has_report\": true
+// CHECK: \"has_report\": 1
index 84185db5af617c1b99781085eb1c6dad4144c9c9..2d054a8d48bdb77ee5bad26e9ba1f84cd61097a1 100644 (file)
@@ -14,7 +14,14 @@ Node0x1 [shape=record,label=
       "has_report": false,
       "is_sink": false,
       "state_id": 2,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "store": null,
         "constraints": null,
index 2f0bcbd4e5f2fe0b178dbc8de4158c62f964beed..898f79600b8ae38baf07139081423f4d3e4860d7 100644 (file)
@@ -5,12 +5,15 @@
 
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1,
-      "pointer": "0x1",
-      "has_report": false,
-      "is_sink": false,
-      "state_id": 2,
-      "program_points": [],
+    { "state_id": 2,
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "environment": null,
         "store": null,
@@ -59,12 +62,16 @@ Node0x1 -> Node0x4;
 // CHECK-SAME: </tr>
 Node0x4 [shape=record,label=
  "{
-    { "node_id": 4,
-      "pointer": "0x4",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 5,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "environment": null,
         "store": null,
@@ -88,12 +95,15 @@ Node0x4 -> Node0x6;
 
 Node0x6 [shape=record,label=
  "{
-    { "node_id": 6,
-      "pointer": "0x6",
-      "has_report": false,
-      "is_sink": false,
-      "state_id": 7,
-      "program_points": [],
+    { "state_id": 7,
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": null
     }
 \l}"];
index 075df98ce942e5d7b291b6b0dd5b49d009d0b2e4..f5ebcf1a606e2aefb358259fb81de63cc578aa3a 100644 (file)
 // CHECK-SAME: </table></td></tr>
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1,
-      "pointer": "0x1",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 2,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "store": null,
         "environment": null,
index 00b2f1456f31392398e40a46805199b7abc21622..53a87aa66755b2c8f0d6cb0b467f85c3f5355aa2 100644 (file)
@@ -5,12 +5,16 @@
 
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1,
-      "pointer": "0x1",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 2,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "store": null,
         "environment": null,
@@ -39,12 +43,16 @@ Node0x1 -> Node0x3;
 // CHECK-SAME: </tr>
 Node0x3 [shape=record,label=
  "{
-    { "node_id": 3,
-      "pointer": "0x3",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 4,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "store": null,
         "environment": null,
@@ -62,12 +70,16 @@ Node0x3 -> Node0x5;
 
 Node0x5 [shape=record,label=
  "{
-    { "node_id": 5,
-      "pointer": "0x5",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 6,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "store": null,
         "environment": null,
index 15e55612b803710e0c8c0ff89a28939617879bdf..3923f1f8ee5b55d414871767926b4dac488e0e31 100644 (file)
@@ -5,13 +5,25 @@
 // UNSUPPORTED: system-windows
 
 Node0x1 [shape=record,label=
- "{{ "node_id": 1, "pointer": "0x1", "has_report": false, "is_sink": false,
-     "program_state": null, "program_points": []}\l}"];
+ "{{ "program_state": null, "program_points": [
+    {
+      "kind": "BlockEntrance", "block_id": 1,
+      "terminator": null, "term_kind": null,
+      "tag": null, "node_id": 1,
+      "has_report": 0, "is_sink": 0
+    }
+  ]}\l}"];
 
 // LIGHT: Node0x1 -> Node0x2;
 // DARK:  Node0x1 -> Node0x2 [color="white"];
 Node0x1 -> Node0x2;
 
 Node0x2 [shape=record,label=
- "{{ "node_id": 2, "pointer": "0x2", "has_report": false, "is_sink": false,
-     "program_state": null, "program_points": []}\l}"];
+ "{{ "program_state": null, "program_points": [
+    {
+      "kind": "BlockEntrance", "block_id": 1,
+      "terminator": null, "term_kind": null,
+      "tag": null, "node_id": 1,
+      "has_report": 0, "is_sink": 0
+    }
+ ]}\l}"];
index 399484a7eece276a163a97c301569114e76702de..733aae3036c8822318c009e5ae5aa6cd456e356b 100644 (file)
@@ -11,7 +11,7 @@
 // CHECK-SAME:     </td>
 // CHECK-SAME:     <td align="left" colspan="2">
 // CHECK-SAME:       <font color="gray60">foo </font>
-// CHECK-SAME:       (environment.cpp:<b>4</b>:<b>6</b> 
+// CHECK-SAME:       (environment.cpp:<b>4</b>:<b>6</b>
 // CHECK-SAME:       <font color="royalblue1">
 // CHECK-SAME:         (<i>spelling at </i> environment.h:<b>7</b>:<b>8</b>)
 // CHECK-SAME:       </font>)
@@ -36,7 +36,14 @@ Node0x1 [shape=record,label=
       "has_report": false,
       "is_sink": false,
       "state_id": 2,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "store": null,
         "constraints": null,
index 475247bb98917c1179b74faa99dfc8cc85b698a9..05e8d4eef50fd8b0c1f65fa48404d9287dd2c42b 100644 (file)
@@ -6,12 +6,16 @@
 // No diffs on the first node, nothing to check.
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1,
-      "pointer": "0x1",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 2,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "store": null,
         "constraints": null,
@@ -57,12 +61,16 @@ Node0x1 -> Node0x6;
 // CHECK-SAME: </tr>
 Node0x6 [shape=record,label=
  "{
-    { "node_id": 6,
-      "pointer": "0x6",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 7,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "store": null,
         "constraints": null,
@@ -102,12 +110,16 @@ Node0x6 -> Node0x9;
 // CHECK-SAME: </tr>
 Node0x9 [shape=record,label=
  "{
-    { "node_id": 9,
-      "pointer": "0x9",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 7,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "store": null,
         "constraints": null,
index a434cd23071ee89e7f16432c8f767fcaa72830c2..a3d7420fed834c98e922958ba0df5f4bad682392 100644 (file)
 // CHECK-SAME:   <tr>
 // LIGHT-SAME:     <td bgcolor="gray70">
 // DARK-SAME:      <td bgcolor="gray20">
-// CHECK-SAME:       <b>Node 1 (0x1) - State Unspecified</b>
+// CHECK-SAME:       <b>State Unspecified</b>
 // CHECK-SAME:     </td>
 // CHECK-SAME:   </tr>
 Node0x1 [shape=record,label=
  "{
     { "node_id": 1, "pointer": "0x1", "has_report": false, "is_sink": false,
       "program_state": null,
-      "program_points": []
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ]
     }
 \l}"];
 
 // CHECK: Node0x2 [
-// CHECK-SAME: <tr><td>
-// COLOR-SAME:   <font color="red"><b>Bug Report Attached</b></font>
-// GRAY-SAME:    <b>Bug Report Attached</b>
-// CHECK-SAME: </td></tr>
-// CHECK-SAME: <tr><td>
-// COLOR-SAME:   <font color="cornflowerblue"><b>Sink Node</b></font>
-// GRAY-SAME:    <b>Sink Node</b>
-// CHECK-SAME: </td></tr>
+// CHECK-SAME: <tr>
+// CHECK-SAME:   <td colspan="3" align="left">
+// COLOR-SAME:     <font color="red"><b>Bug Report Attached</b></font>
+// GRAY-SAME:      <b>Bug Report Attached</b>
+// CHECK-SAME:   </td>
+// CHECK-SAME: </tr>
+// CHECK-SAME: <tr>
+// CHECK-SAME:   <td colspan="3" align="left">
+// COLOR-SAME:     <font color="cornflowerblue"><b>Sink Node</b></font>
+// GRAY-SAME:      <b>Sink Node</b>
+// CHECK-SAME:   </td>
+// CHECK-SAME: </tr>
 Node0x2 [shape=record,label=
  "{
-    { "node_id": 2, "pointer": "0x2", "has_report": true, "is_sink": true,
-      "program_state": null,
-      "program_points": []
+    { "program_state": null,
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 2,
+          "has_report": 1, "is_sink": 1
+        }
+      ]
     }
 \l}"];
index c27c230ebfb370f84fae799ecc09c098c7c55910..c9492757c3affc48eaa2901ffb42808cc8a2442d 100644 (file)
@@ -28,7 +28,7 @@
 // CHECK-SAME: </table>
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1, "pointer": "0x1", "has_report": false, "is_sink": false,
+    {
       "program_state": null, "program_points": [
       {
         "kind": "Edge",
@@ -36,14 +36,20 @@ Node0x1 [shape=record,label=
         "dst_id": 1,
         "terminator": null,
         "term_kind": null,
-        "tag": null
+        "tag": null,
+        "node_id": 1,
+        "has_report": 0,
+        "is_sink": 0
       },
       {
         "kind": "BlockEntrance",
         "block_id": 1,
         "terminator": null,
         "term_kind": null,
-        "tag": null
+        "tag": null,
+        "node_id": 2,
+        "has_report": 0,
+        "is_sink": 0
       }
     ]}
 \l}"];
@@ -72,10 +78,9 @@ Node0x1 [shape=record,label=
 // CHECK-SAME:     </td>
 // CHECK-SAME:   </tr>
 // CHECK-SAME: </table>
-Node0x2 [shape=record,label=
+Node0x3 [shape=record,label=
  "{
-    { "node_id": 2, "pointer": "0x2", "has_report": false, "is_sink": false,
-      "program_state": null, "program_points": [
+    { "program_state": null, "program_points": [
       {
         "kind": "Statement",
         "stmt_kind": "DeclRefExpr",
@@ -88,7 +93,11 @@ Node0x2 [shape=record,label=
           "line": 4,
           "column": 5
         },
-        "tag": "ExprEngine : Clean Node"
+        "tag": "ExprEngine : Clean Node",
+        "node_id": 3,
+        "pointer": "0x3",
+        "has_report": 0,
+        "is_sink": 0
       }
     ]}
 \l}"];
@@ -97,9 +106,9 @@ Node0x2 [shape=record,label=
 
 // CHECK-NEXT: <b>Program point:</b>
 // CHECK-SAME: <td align="left">\{ ... \}</td>
-Node0x3 [shape=record,label=
+Node0x4 [shape=record,label=
  "{
-    { "node_id": 3, "pointer": "0x3", "has_report": false, "is_sink": false,
+    {
       "program_state": null, "program_points": [
       {
         "kind": "Statement",
@@ -112,7 +121,10 @@ Node0x3 [shape=record,label=
           "line": 7,
           "column": 8
         },
-        "tag": "ExprEngine : Clean Node"
+        "tag": "ExprEngine : Clean Node",
+        "node_id": 4,
+        "has_report": 0,
+        "is_sink": 0
       }
     ]}
 \l}"];
@@ -143,10 +155,9 @@ Node0x3 [shape=record,label=
 // CHECK-SAME:     </td>
 // CHECK-SAME:   </tr>
 // CHECK-SAME: </table>
-Node0x4 [shape=record,label=
+Node0x5 [shape=record,label=
  "{
-    { "node_id": 4, "pointer": "0x4", "has_report": false, "is_sink": false,
-      "program_state": null, "program_points": [
+    { "program_state": null, "program_points": [
       {
         "kind": "Statement",
         "stmt_kind": "ImplicitCastExpr",
@@ -160,7 +171,10 @@ Node0x4 [shape=record,label=
           "line": 8,
           "column": 9
         },
-        "tag": "ExprEngine : Clean Node"
+        "tag": "ExprEngine : Clean Node",
+        "node_id": 5,
+        "has_report": 0,
+        "is_sink": 0
       }
     ]}
 \l}"];
index 7267dd43e8984e17f20379df9b7c82abad1ae964..c92901cbd7a349ed09f6df1e11006fd5d91334bd 100644 (file)
 // CHECK-SAME: </table>
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1,
-      "pointer": "0x1",
-      "has_report": false,
-      "is_sink": false,
-      "state_id": 2,
-      "program_points": [],
+    { "state_id": 2,
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "environment": null,
         "constraints": null,
index 94d1d8d9f1f5bf318fa08caea6e0942b59f1581d..8dd5fb44cd7476bc67c26ba70ef980830bc036e3 100644 (file)
@@ -10,7 +10,14 @@ Node0x1 [shape=record,label=
       "has_report": false,
       "is_sink": false,
       "state_id": 2,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "environment": null,
         "constraints": null,
@@ -55,12 +62,16 @@ Node0x1 -> Node0x4;
 // CHECK-SAME: </tr>
 Node0x4 [shape=record,label=
  "{
-    { "node_id": 4,
-      "pointer": "0x4",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 5,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "environment": null,
         "constraints": null,
@@ -91,12 +102,16 @@ Node0x4 -> Node0x6;
 
 Node0x6 [shape=record,label=
  "{
-    { "node_id": 6,
-      "pointer": "0x6",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 7,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": null
     }
 \l}"];
index fa1b10f68b94fd1a675037f6c8065870aa506b6d..b85115ebeac72a2b23c2c8d27ac1638969172963 100644 (file)
 // TOPOLOGY-NOT: Checker State
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1,
-      "pointer": "0x1",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 2,
-      "program_points": [],
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ],
       "program_state": {
         "environment": null,
         "constraints": null,
index 8bdef649e0df6361d094abaa613ee0e715da7030..2c441e02c72d964373773cc2be898ea83ef06f88 100644 (file)
 // UNSUPPORTED: system-windows
 
 Node0x1 [shape=record,label=
- "{{ "node_id": 1, "pointer": "0x1", "has_report": false, "is_sink": false,
-      "program_state": null, "program_points": []}\l}"];
+ "{{ "program_state": null, "program_points": [
+       {
+         "kind": "BlockEntrance", "block_id": 1,
+         "terminator": null, "term_kind": null,
+         "tag": null, "node_id": 1,
+         "has_report": 0, "is_sink": 0
+       }
+     ]}\l}"];
 
 Node0x2 [shape=record,label=
- "{{ "node_id": 2, "pointer": "0x2", "has_report": false, "is_sink": false,
-      "program_state": null, "program_points": []}\l}"];
+ "{{ "program_state": null, "program_points": [
+       {
+         "kind": "BlockEntrance", "block_id": 1,
+         "terminator": null, "term_kind": null,
+         "tag": null, "node_id": 2,
+         "has_report": 0, "is_sink": 0
+       }
+     ]}\l}"];
 
 Node0x3 [shape=record,label=
- "{{ "node_id": 3, "pointer": "0x3", "has_report": false, "is_sink": false,
-      "program_state": null, "program_points": []}\l}"];
+ "{{ "program_state": null, "program_points": [
+       {
+         "kind": "BlockEntrance", "block_id": 1,
+         "terminator": null, "term_kind": null,
+         "tag": null, "node_id": 3,
+         "has_report": 0, "is_sink": 0
+       }
+     ]}\l}"];
 
 Node0x4 [shape=record,label=
- "{{ "node_id": 4, "pointer": "0x4", "has_report": false, "is_sink": false,
-      "program_state": null, "program_points": []}\l}"];
+ "{{ "program_state": null, "program_points": [
+       {
+         "kind": "BlockEntrance", "block_id": 1,
+         "terminator": null, "term_kind": null,
+         "tag": null, "node_id": 4,
+         "has_report": 0, "is_sink": 0
+       }
+     ]}\l}"];
 
 Node0x1 -> Node0x2;
 Node0x1 -> Node0x3;
index 77da7392e36055351fc9633767622588fb9567a1..79222bdbe95dd64d5233c69918f64f58fe5ca8f0 100755 (executable)
@@ -67,6 +67,9 @@ class ProgramPoint(object):
         super(ProgramPoint, self).__init__()
         self.kind = json_pp['kind']
         self.tag = json_pp['tag']
+        self.node_id = json_pp['node_id']
+        self.is_sink = bool(json_pp['is_sink'])
+        self.has_report = bool(json_pp['has_report'])
         if self.kind == 'Edge':
             self.src_id = json_pp['src_id']
             self.dst_id = json_pp['dst_id']
@@ -309,11 +312,9 @@ class ExplodedNode(object):
 
     def construct(self, node_id, json_node):
         logging.debug('Adding ' + node_id)
-        self.node_id = json_node['node_id']
-        self.ptr = json_node['pointer']
-        self.has_report = json_node['has_report']
-        self.is_sink = json_node['is_sink']
+        self.ptr = node_id[4:]
         self.points = [ProgramPoint(p) for p in json_node['program_points']]
+        self.node_id = self.points[-1].node_id
         self.state = ProgramState(json_node['state_id'],
                                   json_node['program_state']) \
             if json_node['program_state'] is not None else None
@@ -488,12 +489,14 @@ class DotDumpVisitor(object):
         else:
             color = 'forestgreen'
 
+        self._dump('<tr><td align="left">%s.</td>' % p.node_id)
+
         if p.kind == 'Statement':
             # This avoids pretty-printing huge statements such as CompoundStmt.
             # Such statements show up only at [Pre|Post]StmtPurgeDeadSymbols
             skip_pretty = 'PurgeDeadSymbols' in p.stmt_point_kind
             stmt_color = 'cyan3'
-            self._dump('<tr><td align="left" width="0">%s:</td>'
+            self._dump('<td align="left" width="0">%s:</td>'
                        '<td align="left" width="0"><font color="%s">'
                        '%s</font> </td>'
                        '<td align="left"><i>S%s</i></td>'
@@ -506,30 +509,41 @@ class DotDumpVisitor(object):
                           self._short_pretty(p.pretty)
                           if not skip_pretty else ''))
         elif p.kind == 'Edge':
-            self._dump('<tr><td width="0"></td>'
+            self._dump('<td width="0"></td>'
                        '<td align="left" width="0">'
                        '<font color="%s">%s</font></td><td align="left">'
                        '[B%d] -\\> [B%d]</td></tr>'
                        % (color, 'BlockEdge', p.src_id, p.dst_id))
         elif p.kind == 'BlockEntrance':
-            self._dump('<tr><td width="0"></td>'
+            self._dump('<td width="0"></td>'
                        '<td align="left" width="0">'
                        '<font color="%s">%s</font></td>'
                        '<td align="left">[B%d]</td></tr>'
                        % (color, p.kind, p.block_id))
         else:
             # TODO: Print more stuff for other kinds of points.
-            self._dump('<tr><td width="0"></td>'
+            self._dump('<td width="0"></td>'
                        '<td align="left" width="0" colspan="2">'
                        '<font color="%s">%s</font></td></tr>'
                        % (color, p.kind))
 
         if p.tag is not None:
-            self._dump('<tr><td width="0"></td>'
+            self._dump('<tr><td width="0"></td><td width="0"></td>'
                        '<td colspan="3" align="left">'
                        '<b>Tag: </b> <font color="crimson">'
                        '%s</font></td></tr>' % p.tag)
 
+        if p.has_report:
+            self._dump('<tr><td width="0"></td><td width="0"></td>'
+                       '<td colspan="3" align="left">'
+                       '<font color="red"><b>Bug Report Attached'
+                       '</b></font></td></tr>')
+        if p.is_sink:
+            self._dump('<tr><td width="0"></td><td width="0"></td>'
+                       '<td colspan="3" align="left">'
+                       '<font color="cornflowerblue"><b>Sink Node'
+                       '</b></font></td></tr>')
+
     def visit_environment(self, e, prev_e=None):
         self._dump('<table border="0">')
 
@@ -786,17 +800,10 @@ class DotDumpVisitor(object):
             self._dump('color="white",fontcolor="gray80",')
         self._dump('label=<<table border="0">')
 
-        self._dump('<tr><td bgcolor="%s"><b>Node %d (%s) - '
-                   'State %s</b></td></tr>'
+        self._dump('<tr><td bgcolor="%s"><b>State %s</b></td></tr>'
                    % ("gray20" if self._dark_mode else "gray70",
-                      node.node_id, node.ptr, node.state.state_id
+                      node.state.state_id
                       if node.state is not None else 'Unspecified'))
-        if node.has_report:
-            self._dump('<tr><td><font color="red"><b>Bug Report Attached'
-                       '</b></font></td></tr>')
-        if node.is_sink:
-            self._dump('<tr><td><font color="cornflowerblue"><b>Sink Node'
-                       '</b></font></td></tr>')
         if not self._topo_mode:
             self._dump('<tr><td align="left" width="0">')
             if len(node.points) > 1: