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
155
156
157
158
|
#!/usr/bin/python3
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
import argparse
import re
from collections import defaultdict
parser = argparse.ArgumentParser(description="Process some integers.")
parser.add_argument("rootingHazards", nargs="?", default="rootingHazards.txt")
parser.add_argument("gcFunctions", nargs="?", default="gcFunctions.txt")
parser.add_argument("hazards", nargs="?", default="hazards.txt")
parser.add_argument("extra", nargs="?", default="unnecessary.txt")
parser.add_argument("refs", nargs="?", default="refs.txt")
args = parser.parse_args()
# Imitate splitFunction from utility.js.
def splitfunc(full):
idx = full.find("$")
if idx == -1:
return (full, full)
return (full[0:idx], full[idx + 1 :])
num_hazards = 0
num_refs = 0
num_missing = 0
try:
with open(args.rootingHazards) as rootingHazards, open(
args.hazards, "w"
) as hazards, open(args.extra, "w") as extra, open(args.refs, "w") as refs:
current_gcFunction = None
# Map from a GC function name to the list of hazards resulting from
# that GC function
hazardousGCFunctions = defaultdict(list)
# List of tuples (gcFunction, index of hazard) used to maintain the
# ordering of the hazards
hazardOrder = []
# Map from a hazardous GC function to the filename containing it.
fileOfFunction = {}
for line in rootingHazards:
m = re.match(r"^Time: (.*)", line)
mm = re.match(r"^Run on:", line)
if m or mm:
print(line, file=hazards)
print(line, file=extra)
print(line, file=refs)
continue
m = re.match(r"^Function.*has unnecessary root", line)
if m:
print(line, file=extra)
continue
m = re.match(r"^Function.*takes unsafe address of unrooted", line)
if m:
num_refs += 1
print(line, file=refs)
continue
m = re.match(
r"^Function.*has unrooted.*of type.*live across GC call '(.*?)' at (\S+):\d+$",
line,
) # NOQA: E501
if m:
# Replace mangled$unmangled with just the unmangled part in the output.
current_gcFunction = m.group(1)
_, readable = splitfunc(current_gcFunction)
hazardousGCFunctions[current_gcFunction].append(
line.replace(current_gcFunction, readable)
)
hazardOrder.append(
(
current_gcFunction,
len(hazardousGCFunctions[current_gcFunction]) - 1,
)
)
num_hazards += 1
fileOfFunction[current_gcFunction] = m.group(2)
continue
m = re.match(r"Function.*expected hazard.*but none were found", line)
if m:
num_missing += 1
print(line + "\n", file=hazards)
continue
if current_gcFunction:
if not line.strip():
# Blank line => end of this hazard
current_gcFunction = None
else:
hazardousGCFunctions[current_gcFunction][-1] += line
mangled2full = {}
with open(args.gcFunctions) as gcFunctions:
gcExplanations = {} # gcFunction => stack showing why it can GC
current_func = None
explanation = None
for line in gcFunctions:
m = re.match(r"^GC Function: (.*)", line)
if m:
if current_func:
gcExplanations[current_func] = explanation
current_func = m.group(1)
mangled, _ = splitfunc(current_func)
mangled2full[mangled] = current_func
explanation = line
elif current_func:
explanation += line
if current_func:
gcExplanations[current_func] = explanation
for gcFunction, index in hazardOrder:
gcHazards = hazardousGCFunctions[gcFunction]
if gcFunction in gcExplanations:
key = gcFunction
else:
# Mangled constructor/destructor names can map to multiple
# unmangled names. We have both here, and the unmangled name
# seen here in the caller may not match the unmangled name in
# the callee, so if we don't find the full function then key
# off of the mangled name instead.
#
# Normally the analysis tries to use the mangled name for
# identity comparison, but here we're processing human-readable
# output. Perhaps a better solution might be to treat the
# rootingHazards.txt input here as internal and only list
# mangled names, expanding them to unmangled names when
# producing hazards.txt and the other output files.
mangled, _ = splitfunc(gcFunction)
key = mangled2full[mangled]
if key in gcExplanations:
print(gcHazards[index] + gcExplanations[key], file=hazards)
else:
print(gcHazards[index], file=hazards)
except IOError as e:
print("Failed: %s" % str(e))
print("Wrote %s" % args.hazards)
print("Wrote %s" % args.extra)
print("Wrote %s" % args.refs)
print(
"Found %d hazards %d unsafe references %d missing"
% (num_hazards, num_refs, num_missing)
)
|