Source code
Revision control
Copy as Markdown
Other Tools
# 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,
import json
import os
import posixpath
from os import PathLike
# `typing.Literal` not available until Python 3.8;
# `typing_extensions` not generally available here
from typing import Iterable, Set
FIRST_LINE = "// This file was generated by {}. DO NOT EDIT.".format(
# `posixpath` for forward slashes, for presentation purposes
posixpath.relpath(__file__, os.getenv("TOPSRCDIR", "/"))
)
def generate_allowed_items(
which: str, # should be: Literal["files", "names"],
paths: Iterable[PathLike],
) -> str:
def remove_trailing_comment(s: str) -> str:
return s[0 : s.find("#")]
def read_items_from_path(path: PathLike) -> Set[str]:
out = set()
with open(path) as file:
for line in file.readlines():
line = remove_trailing_comment(line).strip()
if not line:
continue # comment or empty line; discard
out.add(line)
return out
allowed = set().union(*(read_items_from_path(path) for path in paths))
# BUG: `json.dumps` may not correctly handle use of the quote character in
# thread names
allowed_list_s = ",\n ".join(json.dumps(elem) for elem in sorted(allowed))
return f"""\
static const char *allow_thread_{which}[] = {{
{allowed_list_s}
}};"""
def generate_allows(
*, allowed_names: Iterable[PathLike], allowed_files: Iterable[PathLike]
) -> str:
"""
This function reads in the specified sets of files -- ordinarily,
["ThreadAllows.txt"] and ["ThreadFileAllows.txt"] -- and generates the text
of a header file containing two arrays with their contents, for inclusion by
the thread-name checker.
The checker will reject the creation of any thread via NS_NewNamedThread
unless either:
- the thread's name is a literal string which is found in the set of
allowed thread names; or
- the thread's creation occurs within a file which is found in the set of
unchecked files.
The latter condition exists mostly for the definition of NS_NewNamedThread,
but there also exist a few cases where the thread name is dynamically
computed (and so can't be checked).
"""
output_string = (
FIRST_LINE
+ "\n\n"
+ generate_allowed_items("files", allowed_files)
+ "\n\n"
+ generate_allowed_items("names", allowed_names)
+ "\n"
)
return output_string
# Entry point used by build/clang-plugin/moz.build (q.v.).
def generate_file(output, allowed_names, allowed_files):
output.write(
generate_allows(allowed_names=[allowed_names], allowed_files=[allowed_files])
)