-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathexplore_conditions.py
executable file
·154 lines (137 loc) · 5.64 KB
/
explore_conditions.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/env python3
import argparse
import sys
import os.path as path
import logging
from functools import reduce
from itertools import product
import coloredlogs
import z3
import pefile
import progressbar
log = logging.getLogger(__name__)
coloredlogs.install(level="CRITICAL", logger=log)
alllog = logging.getLogger("")
alllog.setLevel(logging.CRITICAL)
from modelLang import Parser, Z3Backend
def write_testcase(testcase, outdir, cs, n):
testcasename = path.join(outdir, f"testcase_{n}")
conditionsname = path.join(outdir, f"testcase_{n}.cond")
with open(testcasename, "wb") as fp:
fp.write(testcase)
with open(conditionsname, "w") as fp:
for c in cs:
fp.write(f"{c[0][0]} {c[1]}\n")
def update_blacklist(unsat, cs, blacklist):
entry = dict()
for cname in unsat:
for c in cs:
if c[0][0] == str(cname):
entry[c[0][0]] = c[1]
break
else:
log.warning(f"Could not find {cname} among the constraints")
return
blacklist.append(entry)
def isblacklisted(cs, blacklist):
for b in blacklist:
tmp = {cname: False for cname in b}
for cname, value in b.items():
for ((cname2, _), value2) in cs:
if (cname, value) == (cname2, value2):
tmp[cname] = True
if all(tmp.values()):
return True
return False
if __name__ == "__main__":
argparser = argparse.ArgumentParser(description="Explore all combinations of non-terminal conditions to generate different testcases.")
argparser.add_argument('--models', '-M', action="append",
metavar="model", type=str, nargs="+",
help="Models to explore")
argparser.add_argument('--supports', '-S', action="append",
metavar="model", type=str, nargs="*", default=[],
help="Other models to assert")
argparser.add_argument('--outdir', '-O', action="store",
metavar="outfile", type=str,
default="testcase",
help="Output directory file for testcases")
argparser.add_argument('--size', '-B', action="store", metavar="bytes",
type=int, default=None,
help="Size in bytes of the testcase to generate")
argparser.add_argument('--define', '-D', action="store", metavar="define",
type=lambda x: (x.split(":")[0],
int(x.split(":")[1])),
nargs="*",
help="Overwrite constant definition")
argparser.add_argument('--var', '-V', action="store",
metavar="variable", type=str, nargs=1,
default="HEADER",
help="Variable in the model to use for the testcase")
args = argparser.parse_args()
inputs = reduce(lambda x,y: x | {*y}, args.models, set())
supports = reduce(lambda x,y: x | {*y}, args.supports, set())
outdir = args.outdir
size = args.size
voi = args.var
defs = dict(args.define) if args.define else {}
Z3Backend.print_unsat = False
z3models = []
for model in inputs:
modelname = path.basename(model)
parser = Parser(ptype=Parser.ParserType.DIFFERENTIAL_ASSERT,
input_size=size,
custom_defs=defs)
parser.parse_file(model)
backend = Z3Backend(name=modelname, voi=voi)
backend.exec_statements(parser.statements)
z3models.append(backend)
backend = z3models[0]
for m in z3models[1:]:
backend &= m
z3supports = []
for model in supports:
modelname = path.basename(model)
parser = Parser(ptype=Parser.ParserType.DIFFERENTIAL_ASSERT,
input_size=size,
custom_defs=defs)
parser.parse_file(model)
tmp = Z3Backend(name=modelname, voi=voi)
tmp.exec_statements(parser.statements)
z3supports.append(tmp)
for m in z3supports:
backend &= m
nterminal_conds = list(reduce(lambda x, y: x+y,
[[(x, m.conditions[x])
for x in (m.conditions.keys()
- m.terminal_conditions.keys())
] for m in z3models],
[]))
nconds = len(nterminal_conds)
log.info(f"{nconds} found. Generating {2**nconds} testcases")
alltf = product([True, False], repeat=nconds)
n = 0
blacklist = []
for tfs in progressbar.progressbar(alltf, max_value=2**nconds):
progressbar.streams.flush()
# cs = [((name, z3cond), bool), ... ]
cs = list(zip(nterminal_conds, tfs))
if isblacklisted(cs, blacklist):
log.warning("Combination is known to be unsat")
continue
support = Z3Backend()
for c in cs:
if c[1]:
support.terminal_conditions[c[0][0]] = c[0][1]
else:
support.terminal_conditions[c[0][0]] = z3.Not(c[0][1])
if not support.model:
log.warning("Support model is unsat. Checking the unsat core and discarinding conflitting constraints.")
unsat = support.solver.unsat_core()
update_blacklist(unsat, cs, blacklist)
continue
tmpbackend = backend & support
tmpmodel = tmpbackend.model
if tmpmodel:
n += 1
testcase = tmpbackend.generate_testcase()
write_testcase(testcase, outdir, cs, n)