Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/js/src/devtools/rootAnalysis/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 10 kB image not shown  

Quelle  explain.py   Sprache: Python

 
#!/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

SRCDIR = pathlib.Path(__file__).parent.parent.parent.absolute()

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",
)

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 :])


def print_header(outfh):
    print(
        """\
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<style>
input {
  position: absolute;
  opacity: 0;
  z-index: -1;
}
tt {
  background: #eee;
}
.tab-label {
  cursor: s-resize;
}
.tab-label a {
  color: #222;
}
.tab-label:hover {
  background: #eee;
}
.tab-label::after {
  content: " \\25B6";
  width: 1em;
  height: 1em;
  color: #75f;
  text-align: center;
  transition: all 0.35s;
}
.accorntent {
  max-height: 0;
  padding: 0 1em;
  color: #2c3e50;
  overflow: hidden;
  background: white;
  transition: all 0.35s;
}

input:checked + .tab-label::after {
  transform: rotate(90deg);
  content: " \\25BC";
}
input:checked + .tab-label {
  cursor: n-resize;
}
input:checked ~ .accorntent {
  max-height: 100vh;
}
</style>
</head>
<body>""",
        file=outfh,
    )


def print_footer(outfh):
    print("", file=outfh)


def sourcelink(symbol=None, loc=None, range=None):
    if symbol:
        return f"https://searchfox.org/mozilla-central/search?q=symbol:{symbol}"
    elif range:
        filename, lineno = loc.split(":")
        [f0, l0] = range[0]
        [f1, l1] = range[1]
        if f0 == f1 and l1 > l0:
            return f"../{filename}?L={l0}-{l1 - 1}#{l0}"
        else:
            return f"../{filename}?L={l0}#{l0}"
    elif loc:
        filename, lineno = loc.split(":")
        return f"../{filename}?L={lineno}#{lineno}"
    else:
        raise Exception("missing argument to sourcelink()")


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

        hazardousGCFunctions = set()

        results = json.load(rootingHazards)
        print_header(html)

        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)
                if not 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"] == "address":
                print(
                    (
                        "\nFunction '{functionName}'"
                        " takes unsafe address of unrooted '{variable}'"
                        " at {loc}"
                    ).format(**result),
                    file=refs,
                )
                num_refs += 1

            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 not in 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

        print(
            "Found %d hazards, %d unsafe references, %d missing."
            % (num_hazards, num_refs, num_missing),
            file=html,
        )
        print("
    ", file=html)

            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)

                if result.get("expected"):
                    continue

                cfgid = f"CFG_{checkboxCounter}"
                gcid = f"GC_{checkboxCounter}"
                checkboxCounter += 1
                print(
                    (
                        "
    • \n"
                          "
    • Function {readable}\n"
                          "
    • has unrooted {variable} of type '{type}'\n"
                          "
    • \n"
                          "
      \n"
                      ).format(
                          **quoted_dict(result),
                          symbol_url=sourcelink(symbol=result["mangled"]),
                          cfgid=cfgid,
                      ),
                      file=html,
                  )
                  for edge in result["trace"]:
                      print(
                          "
          {lineText}: {edgeText}
      "
      .format(**quoted_dict(edge)),
                          file=html,
                      )
                  print("
      "
      , file=html)
                  print(
                      "
    • \n"
                      "
      ".format(
                          **quoted_dict(result),
                          loc_url=sourcelink(range=result["gcrange"], loc=result["loc"]),
                          gcid=gcid,
                      ),
                      file=html,
                  )
                  for func in explanation:
                      print(f"
      {escape(func)}
      "
      , file=html)
                  print("

    ", file=html)

            print_footer(html)

    except IOError as e:
        print("Failed: %s" % str(e))

    if args.verbose:
        print("Wrote %s" % args.hazards)
        print("Wrote %s" % args.extra)
        print("Wrote %s" % args.refs)
        print("Wrote %s" % args.html)

    print(
        "Found %d hazards %d unsafe references %d missing"
        % (num_hazards, num_refs, num_missing)
    )

Messung V0.5
C=91 H=84 G=87

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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 und die Messung sind noch experimentell.