-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathanalysis.py
126 lines (98 loc) · 3.75 KB
/
analysis.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import typing
from collections import OrderedDict
from typing import Any, Callable
import sys
from z3 import IntSort, ArithSortRef
from cfg import ControlFlowGraph, ControlFlowNode
from symbolic_interp import Signature
class Lattice:
top: Any
bottom: Any
meet: Callable[[Any, Any], Any]
join: Callable[[Any, Any], Any]
def __init__(self, top: Any, bottom: Any, meet: Callable[[Any, Any], Any], join: Callable[[Any, Any], Any]):
self.top = top
self.bottom = bottom
self.meet = meet
self.join = join
def join_all(self, values: list) -> Any:
result = self.bottom
for value in values:
result = self.join(result, value)
return result
def meet_all(self, values: list) -> Any:
result = self.top
for value in values:
result = self.meet(result, value)
return result
class GraphFixedPointAnalysis:
graph: ControlFlowGraph
lattice: Lattice
def __init__(self, graph: ControlFlowGraph, lattice: Lattice):
self.graph = graph
self.lattice = lattice
self.results = {node: None for node in self.graph.nodes}
def get_result(self) -> Any:
return self.results
def analysis_step(self, node: ControlFlowNode):
pass
def iterate(self, max_steps: int = 50) -> Any:
worklist = list(self.graph.nodes)
steps = 0
while worklist and steps < max_steps:
node = worklist.pop()
old_result = self.results[node]
self.analysis_step(node)
if self.results[node] != old_result:
worklist.append(node)
steps += 1
class AbstractSignature:
decls: OrderedDict[str, Lattice]
def __init__(self, decls: typing.Union[dict, typing.List[typing.Tuple[str, Lattice]]]):
self.decls = OrderedDict((name, ty for (name, ty) in decls.items()))
class AbstractState:
sig: AbstractSignature
def __init__(self, sig: AbstractSignature):
self.sig = sig
self.locals = {name: ty.top for (name, ty) in sig.decls.items()}
self.assumptions = []
def assign(self, var: str, abstract_val: Any):
c = self.clone()
c.locals[var] = abstract_val
return c
def eval(self, expr: Any) -> Any:
if callable(expr):
expr = expr(self)
if isinstance(expr, str):
try:
expr = eval(expr)
except Exception as exp:
raise Exception("Failed to evaluate %s (%s)" % (expr, exp))
return expr
def assume(self, cond: Any):
cond = self.eval(cond)
cloned = self.clone()
cloned.assumptions.append((cond.get_id(), cond))
return cloned
def clone(self):
c = type(self)(self.sig)
c.locals = self.locals.copy()
c.assumptions = self.assumptions.copy()
return c
class GraphIntervalAnalysis(GraphFixedPointAnalysis):
MIN_INT = -100
MAX_INT = 100
class IntervalLattice(Lattice):
def __init__(self):
super().__init__((GraphIntervalAnalysis.MIN_INT, GraphIntervalAnalysis.MAX_INT),
(GraphIntervalAnalysis.MAX_INT, GraphIntervalAnalysis.MIN_INT),
lambda a, b: (max(a[0], b[0]), min(a[1], b[1])),
lambda a, b: (min(a[0], b[0]), max(a[1], b[1])))
def __init__(self, graph: ControlFlowGraph):
super().__init__(graph, GraphIntervalAnalysis.IntervalLattice())
self.results = {node: {var: self.lattice.top
for var in graph.types
if isinstance(graph.types[var], ArithSortRef)}
for node in self.graph.nodes}
def analysis_step(self, node: ControlFlowNode):
pass