Skip to content

Commit beb85ad

Browse files
committed
[analyzer] exploded-graph-rewriter: Add support for range constraints.
Diff support included. A cheap solution is implemented that treats range constraints as "some sort of key-value map", so it's going to be trivial to add support for other such maps later, such as dynamic type info. Differential Revision: https://reviews.llvm.org/D63685 llvm-svn: 364268
1 parent b9c94f9 commit beb85ad

File tree

7 files changed

+162
-2
lines changed

7 files changed

+162
-2
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %exploded_graph_rewriter %s | FileCheck %s
2+
3+
// FIXME: Substitution doesn't seem to work on Windows.
4+
// UNSUPPORTED: system-windows
5+
6+
// CHECK: <tr><td align="left"><b>Ranges: </b></td></tr>
7+
// CHECK-SAME: <tr><td align="left"><table border="0">
8+
// CHECK-SAME: <tr>
9+
// CHECK-SAME: <td align="left">reg_$0<x></td>
10+
// CHECK-SAME: <td align="left">\{ [0, 0] \}</td>
11+
// CHECK-SAME: </tr>
12+
// CHECK-SAME: </table></td></tr>
13+
Node0x1 [shape=record,label=
14+
"{
15+
{ "node_id": 1,
16+
"pointer": "0x1",
17+
"state_id": 2,
18+
"program_points": [],
19+
"program_state": {
20+
"store": null,
21+
"environment": null,
22+
"constraints": [
23+
{ "symbol": "reg_$0<x>", "range": "{ [0, 0] }" }
24+
]
25+
}
26+
}
27+
\l}"];
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// RUN: %exploded_graph_rewriter -d %s | FileCheck %s
2+
3+
// FIXME: Substitution doesn't seem to work on Windows.
4+
// UNSUPPORTED: system-windows
5+
6+
Node0x1 [shape=record,label=
7+
"{
8+
{ "node_id": 1,
9+
"pointer": "0x1",
10+
"state_id": 2,
11+
"program_points": [],
12+
"program_state": {
13+
"store": null,
14+
"environment": null,
15+
"constraints": [
16+
{ "symbol": "reg_$0<x>", "range": "{ [0, 10] }" }
17+
]
18+
}
19+
}
20+
\l}"];
21+
22+
Node0x1 -> Node0x3;
23+
24+
// CHECK: Node0x3 [
25+
// CHECK-SAME: <tr>
26+
// CHECK-SAME: <td><font color="red">-</font></td>
27+
// CHECK-SAME: <td align="left">reg_$0<x></td>
28+
// CHECK-SAME: <td align="left">\{ [0, 10] \}</td>
29+
// CHECK-SAME: </tr>
30+
// CHECK-SAME: <tr>
31+
// CHECK-SAME: <td><font color="forestgreen">+</font></td>
32+
// CHECK-SAME: <td align="left">reg_$0<x></td>
33+
// CHECK-SAME: <td align="left">\{ [0, 5] \}</td>
34+
// CHECK-SAME: </tr>
35+
Node0x3 [shape=record,label=
36+
"{
37+
{ "node_id": 3,
38+
"pointer": "0x3",
39+
"state_id": 4,
40+
"program_points": [],
41+
"program_state": {
42+
"store": null,
43+
"environment": null,
44+
"constraints": [
45+
{ "symbol": "reg_$0<x>", "range": "{ [0, 5] }" }
46+
]
47+
}
48+
}
49+
\l}"];
50+
51+
Node0x3 -> Node0x5;
52+
53+
Node0x5 [shape=record,label=
54+
"{
55+
{ "node_id": 5,
56+
"pointer": "0x5",
57+
"state_id": 6,
58+
"program_points": [],
59+
"program_state": {
60+
"store": null,
61+
"environment": null,
62+
"constraints": null
63+
}
64+
}
65+
\l}"];

clang/test/Analysis/exploded-graph-rewriter/environment.dot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Node0x1 [shape=record,label=
3333
"program_points": [],
3434
"program_state": {
3535
"store": null,
36+
"constraints": null,
3637
"environment": [
3738
{
3839
"location_context": "#0 Call",

clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Node0x1 [shape=record,label=
1212
"program_points": [],
1313
"program_state": {
1414
"store": null,
15+
"constraints": null,
1516
"environment": [
1617
{
1718
"location_context": "#0 Call",
@@ -54,6 +55,7 @@ Node0x6 [shape=record,label=
5455
"program_points": [],
5556
"program_state": {
5657
"store": null,
58+
"constraints": null,
5759
"environment": [
5860
{
5961
"location_context": "#0 Call",
@@ -90,6 +92,7 @@ Node0x9 [shape=record,label=
9092
"program_points": [],
9193
"program_state": {
9294
"store": null,
95+
"constraints": null,
9396
"environment": [
9497
{
9598
"location_context": "#0 Call",

clang/test/Analysis/exploded-graph-rewriter/store.dot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Node0x1 [shape=record,label=
2828
"program_points": [],
2929
"program_state": {
3030
"environment": null,
31+
"constraints": null,
3132
"store": [
3233
{
3334
"cluster": "x",

clang/test/Analysis/exploded-graph-rewriter/store_diff.dot

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Node0x1 [shape=record,label=
1111
"program_points": [],
1212
"program_state": {
1313
"environment": null,
14+
"constraints": null,
1415
"store": [
1516
{
1617
"cluster": "x",
@@ -52,6 +53,7 @@ Node0x4 [shape=record,label=
5253
"program_points": [],
5354
"program_state": {
5455
"environment": null,
56+
"constraints": null,
5557
"store": [
5658
{
5759
"cluster": "x",

clang/utils/analyzer/exploded-graph-rewriter.py

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ def diff_dicts(curr, prev):
2525
return (removed, added)
2626

2727

28+
# Represents any program state trait that is a dictionary of key-value pairs.
29+
class GenericMap(object):
30+
def __init__(self, generic_map):
31+
self.generic_map = generic_map
32+
33+
def diff(self, prev):
34+
return diff_dicts(self.generic_map, prev.generic_map)
35+
36+
def is_different(self, prev):
37+
removed, added = self.diff(prev)
38+
return len(removed) != 0 or len(added) != 0
39+
40+
2841
# A deserialized source location.
2942
class SourceLocation(object):
3043
def __init__(self, json_loc):
@@ -203,8 +216,10 @@ def __init__(self, state_id, json_ps):
203216
if json_ps['store'] is not None else None
204217
self.environment = Environment(json_ps['environment']) \
205218
if json_ps['environment'] is not None else None
219+
self.constraints = GenericMap(collections.OrderedDict([
220+
(c['symbol'], c['range']) for c in json_ps['constraints']
221+
])) if json_ps['constraints'] is not None else None
206222
# TODO: Objects under construction.
207-
# TODO: Constraint ranges.
208223
# TODO: Dynamic types of objects.
209224
# TODO: Checker messages.
210225

@@ -479,11 +494,57 @@ def visit_store_in_state(self, s, prev_s=None):
479494
else:
480495
self._dump('</td></tr><tr><td align="left">')
481496
self.visit_store(s.store)
482-
self._dump('</td></tr><hr />')
497+
self._dump('</td></tr>')
498+
499+
def visit_generic_map(self, m, prev_m=None):
500+
self._dump('<table border="0">')
501+
502+
def dump_pair(m, k, is_added=None):
503+
self._dump('<tr><td>%s</td>'
504+
'<td align="left">%s</td>'
505+
'<td align="left">%s</td></tr>'
506+
% (self._diff_plus_minus(is_added),
507+
k, m.generic_map[k]))
508+
509+
if prev_m is not None:
510+
removed, added = m.diff(prev_m)
511+
for k in removed:
512+
dump_pair(prev_m, k, False)
513+
for k in added:
514+
dump_pair(m, k, True)
515+
else:
516+
for k in m.generic_map:
517+
dump_pair(m, k, None)
518+
519+
self._dump('</table>')
520+
521+
def visit_generic_map_in_state(self, selector, s, prev_s=None):
522+
self._dump('<tr><td align="left">'
523+
'<b>Ranges: </b>')
524+
m = getattr(s, selector)
525+
if m is None:
526+
self._dump('<i> Nothing!</i>')
527+
else:
528+
prev_m = None
529+
if prev_s is not None:
530+
prev_m = getattr(prev_s, selector)
531+
if prev_m is not None:
532+
if m.is_different(prev_m):
533+
self._dump('</td></tr><tr><td align="left">')
534+
self.visit_generic_map(m, prev_m)
535+
else:
536+
self._dump('<i> No changes!</i>')
537+
if prev_m is None:
538+
self._dump('</td></tr><tr><td align="left">')
539+
self.visit_generic_map(m)
540+
self._dump('</td></tr>')
483541

484542
def visit_state(self, s, prev_s):
485543
self.visit_store_in_state(s, prev_s)
544+
self._dump('<hr />')
486545
self.visit_environment_in_state(s, prev_s)
546+
self._dump('<hr />')
547+
self.visit_generic_map_in_state('constraints', s, prev_s)
487548

488549
def visit_node(self, node):
489550
self._dump('%s [shape=record,label=<<table border="0">'

0 commit comments

Comments
 (0)