NoQ created this revision. NoQ added reviewers: dcoughlin, xazax.hun, a_sidorin, rnkovacs, Szelethus, baloghadamsoftware, Charusso. Herald added subscribers: cfe-commits, dkrupp, donat.nagy, mikhail.ramalho, a.sidorin, szepet. Herald added a project: clang.
I need this for the demo at the dev meeting ^.^" Instead of using an allocator-based stable identifier as in D51667 <https://reviews.llvm.org/D51667>, let's make truly stable identifiers. The nodes now identify themselves as 1.,2.,3.,..., etc., which is not only nice to read, but also allows reliably setting conditional breakpoints. Eg., in lldb: (lldb) br s -n inlineCall -c 'Pred->Id == 12345' lets you reliably debug the construction of the `CallEnter` node whose predecessor is node 12345. You could do a similar trick with the current stable IDs but that worked in ~30% of the cases because of slight indeterminism in how immutable sets and maps are allocated in the bump pointer allocator. Now it's fully reliable. The `exploded-graph-rewriter` is updated accordingly. Additionally, because in exploded graph dumps we collapse multiple real exploded nodes into a single dumped graph node when they have the same state and the respective sub-graph is linear, i changed it to dump *each* node's identifier near the program point. Additionally, the "sink node" and "bug report attached" messages are also passed one per point rather than once per visible node. Notice the 1., 2., 3. things on the left: F10279509: Screen Shot 2019-10-15 at 7.26.37 PM.png <https://reviews.llvm.org/F10279509> That's how bug/sink notices now look: F10279512: Screen Shot 2019-10-15 at 7.27.18 PM.png <https://reviews.llvm.org/F10279512> In the worst case this patch may increase memory usage of the static analyzer by around 1MB per process (if all 225000 nodes are constructed, times 4 bytes per unsigned integer on most architectures; note that only one analysis is kept in memory at a time, so the overhead doesn't add up for multiple exploded graphs). So even though i could have hidden the new feature under `#ifndef NDEBUG`, like the whole graph dumping facility, i don't think it's really worth it; i'd much rather enable graph dumping in noassert builds. Repository: rC Clang https://reviews.llvm.org/D69015 Files: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h clang/lib/StaticAnalyzer/Core/BugReporter.cpp clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp clang/lib/StaticAnalyzer/Core/ExprEngine.cpp clang/test/Analysis/dump_egraph.c clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot clang/test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot clang/test/Analysis/exploded-graph-rewriter/constraints.dot clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot clang/test/Analysis/exploded-graph-rewriter/edge.dot clang/test/Analysis/exploded-graph-rewriter/environment.dot clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot clang/test/Analysis/exploded-graph-rewriter/node_labels.dot clang/test/Analysis/exploded-graph-rewriter/program_points.dot clang/test/Analysis/exploded-graph-rewriter/store.dot clang/test/Analysis/exploded-graph-rewriter/store_diff.dot clang/test/Analysis/exploded-graph-rewriter/topology.dot clang/test/Analysis/exploded-graph-rewriter/trimmers.dot clang/utils/analyzer/exploded-graph-rewriter.py
Index: clang/utils/analyzer/exploded-graph-rewriter.py =================================================================== --- clang/utils/analyzer/exploded-graph-rewriter.py +++ clang/utils/analyzer/exploded-graph-rewriter.py @@ -67,6 +67,9 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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: Index: clang/test/Analysis/exploded-graph-rewriter/trimmers.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/trimmers.dot +++ clang/test/Analysis/exploded-graph-rewriter/trimmers.dot @@ -17,20 +17,44 @@ // 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: clang/test/Analysis/exploded-graph-rewriter/topology.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/topology.dot +++ clang/test/Analysis/exploded-graph-rewriter/topology.dot @@ -12,12 +12,16 @@ // 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: clang/test/Analysis/exploded-graph-rewriter/store_diff.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/store_diff.dot +++ clang/test/Analysis/exploded-graph-rewriter/store_diff.dot @@ -10,7 +10,14 @@ "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 @@ // 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 @@ 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: clang/test/Analysis/exploded-graph-rewriter/store.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/store.dot +++ clang/test/Analysis/exploded-graph-rewriter/store.dot @@ -23,12 +23,15 @@ // 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: clang/test/Analysis/exploded-graph-rewriter/program_points.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/program_points.dot +++ clang/test/Analysis/exploded-graph-rewriter/program_points.dot @@ -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 @@ "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 @@ // 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 @@ "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 @@ // 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 @@ "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 @@ // 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 @@ "line": 8, "column": 9 }, - "tag": "ExprEngine : Clean Node" + "tag": "ExprEngine : Clean Node", + "node_id": 5, + "has_report": 0, + "is_sink": 0 } ]} \l}"]; Index: clang/test/Analysis/exploded-graph-rewriter/node_labels.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/node_labels.dot +++ clang/test/Analysis/exploded-graph-rewriter/node_labels.dot @@ -15,30 +15,47 @@ // 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> +// GREY-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: clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot +++ clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot @@ -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 @@ // 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 @@ // 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: clang/test/Analysis/exploded-graph-rewriter/environment.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/environment.dot +++ clang/test/Analysis/exploded-graph-rewriter/environment.dot @@ -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 @@ "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: clang/test/Analysis/exploded-graph-rewriter/edge.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/edge.dot +++ clang/test/Analysis/exploded-graph-rewriter/edge.dot @@ -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: clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot +++ clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot @@ -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 @@ // 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 @@ 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: clang/test/Analysis/exploded-graph-rewriter/constraints.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/constraints.dot +++ clang/test/Analysis/exploded-graph-rewriter/constraints.dot @@ -12,12 +12,16 @@ // 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: clang/test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot +++ clang/test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot @@ -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 @@ // 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 @@ 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: clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot =================================================================== --- clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot +++ clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot @@ -14,7 +14,14 @@ "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: clang/test/Analysis/dump_egraph.c =================================================================== --- clang/test/Analysis/dump_egraph.c +++ clang/test/Analysis/dump_egraph.c @@ -18,7 +18,7 @@ return *x + *y; } -// CHECK: \"program_points\": [\l \{ \"kind\": \"Edge\", \"src_id\": 2, \"dst_id\": 1, \"terminator\": null, \"term_kind\": null, \"tag\": null \}\l ],\l \"program_state\": null +// CHECK: \"program_points\": [\l \{ \"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 ],\l \"program_state\": null // CHECK: \"program_points\": [\l \{ \"kind\": \"BlockEntrance\", \"block_id\": 1 @@ -27,4 +27,4 @@ // CHECK: \"pretty\": \"'\\\\x13'\" -// CHECK: \"has_report\": true +// CHECK: \"has_report\": 1 Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -3058,16 +3058,7 @@ 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"; @@ -3080,9 +3071,12 @@ 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: clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -283,10 +283,6 @@ 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 @@ 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::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 @@ // 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: clang/lib/StaticAnalyzer/Core/BugReporter.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -2566,7 +2566,8 @@ // 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: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -131,10 +131,12 @@ /// 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 @@ } 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 @@ 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 @@ /// ExplodedGraph for further processing. ExplodedNode *createUncachedNode(const ProgramPoint &L, ProgramStateRef State, + int64_t Id, bool IsSink = false); std::unique_ptr<ExplodedGraph> MakeEmptyGraph() const {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits