#!/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 json import pathlib import re from html import escape
parser = argparse.ArgumentParser(
description="Convert the JSON output of the hazard analysis into various text files describing the results.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument("--verbose", type=bool, default=False, help="verbose output")
inputs = parser.add_argument_group("Input")
inputs.add_argument( "rootingHazards",
nargs="?",
default="rootingHazards.json",
help="JSON input file describing the output of the hazard analysis",
)
outputs = parser.add_argument_group("Output")
outputs.add_argument( "gcFunctions",
nargs="?",
default="gcFunctions.txt",
help="file containing a list of functions that can GC",
)
outputs.add_argument( "hazards",
nargs="?",
default="hazards.txt",
help="file containing the rooting hazards found",
)
outputs.add_argument( "extra",
nargs="?",
default="unnecessary.txt",
help="file containing unnecessary roots",
)
outputs.add_argument( "refs",
nargs="?",
default="refs.txt",
help="file containing a list of unsafe references to unrooted values",
)
outputs.add_argument( "html",
nargs="?",
default="hazards.html",
help="HTML-formatted file with the hazards found",
)
def quoted_dict(d): return {k: escape(v) for k, v in d.items() if type(v) is str}
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, open(
args.html, "w"
) as html:
current_gcFunction = None
when = min((r for r in results if r["record"] == "time"), key=lambda r: r["t"])[ "iso"
]
line = f"Time: {when}"
print(line, file=hazards)
print(line, file=extra)
print(line, file=refs)
checkboxCounter = 0
hazard_results = []
seen_time = False for result in results: if result["record"] == "unrooted":
hazard_results.append(result)
gccall_mangled, _ = splitfunc(result["gccall"])
hazardousGCFunctions.add(gccall_mangled) ifnot result.get("expected"):
num_hazards += 1
elif result["record"] == "unnecessary":
print( "\nFunction '{mangled}' has unnecessary root '{variable}' of type {type} at {loc}".format(
**result
),
file=extra,
)
elif result["record"] == "missing":
print( "\nFunction '{functionName}' expected hazard(s) but none were found at {loc}".format(
**result
),
file=hazards,
)
num_missing += 1
readable2mangled = {} with open(args.gcFunctions) as gcFunctions:
gcExplanations = {} # gcFunction => stack showing why it can GC
current_func = None
explanation = [] for line in gcFunctions: if m := re.match(r"^GC Function: (.*)", line): if current_func:
gcExplanations[splitfunc(current_func)[0]] = explanation
functionName = m.group(1)
mangled, readable = splitfunc(functionName) if mangled notin hazardousGCFunctions:
current_func = None continue
current_func = functionName if readable != mangled:
readable2mangled[readable] = mangled # TODO: store the mangled name here, and change # gcFunctions.txt -> gcFunctions.json and key off of the mangled name.
explanation = [readable] elif current_func:
explanation.append(line.strip()) if current_func:
gcExplanations[splitfunc(current_func)[0]] = explanation
for result in hazard_results:
(result["gccall_mangled"], result["gccall_readable"]) = splitfunc(
result["gccall"]
) # Attempt to extract out the function name. Won't handle `Foo<int, Bar<int>>::Foo()`. if m := re.search(r"((?:\w|:|<[^>]*?>)+)\(", result["gccall_readable"]):
result["gccall_short"] = m.group(1) + "()" else:
result["gccall_short"] = result["gccall_readable"] if result.get("expected"):
print("\nThis is expected, but ", end="", file=hazards) else:
print("\nFunction ", end="", file=hazards)
print( "'{readable}' has unrooted '{variable}'" " of type '{type}' live across GC call '{gccall_readable}' at {loc}".format(
**result
),
file=hazards,
) for edge in result["trace"]:
print(" {lineText}: {edgeText}".format(**edge), file=hazards)
explanation = gcExplanations.get(result["gccall_mangled"])
explanation = explanation or gcExplanations.get(
readable2mangled.get(
result["gccall_readable"], result["gccall_readable"]
),
[],
) if explanation:
print("GC Function: " + explanation[0], file=hazards) for func in explanation[1:]:
print(" " + func, file=hazards)
print(file=hazards)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.