[libc] Enforce standard identifier validation in hdrgen (#198971)
Implemented validation for standard identifiers in the hdrgen tool to catch typos and unknown standards. Aggregated standards from all entity types (macros, types, etc.) for validation, addressing a TODO in header.py. Added llvm_libc_ext, stdc_ext, and llvm_libc_stdfix_ext to the canonical identifiers. Standardised invalid or inconsistently formatted standards in several YAML files. This enforces the correctness of any provided standards field but does not yet require that every entity has one (many entities still inherit standards from the header level). Assisted-by: Automated tooling, human reviewed.
This commit is contained in:
parent
7d65f8e1bb
commit
c20020ea73
10 changed files with 70 additions and 33 deletions
|
|
@ -153,7 +153,7 @@ functions:
|
|||
arguments:
|
||||
- type: float
|
||||
- name: atanhf16
|
||||
standatds:
|
||||
standards:
|
||||
- stdc
|
||||
return_type: _Float16
|
||||
arguments:
|
||||
|
|
@ -765,7 +765,7 @@ functions:
|
|||
guard: LIBC_TYPES_HAS_FLOAT128
|
||||
- name: faddl
|
||||
standards:
|
||||
- faddl
|
||||
- stdc
|
||||
return_type: float
|
||||
arguments:
|
||||
- type: long double
|
||||
|
|
@ -2203,13 +2203,15 @@ functions:
|
|||
- type: float
|
||||
- type: float
|
||||
- name: powi
|
||||
standards: llvm_libc_ext
|
||||
standards:
|
||||
- llvm_libc_ext
|
||||
return_type: double
|
||||
arguments:
|
||||
- type: double
|
||||
- type: int
|
||||
- name: powif
|
||||
standards: llvm_libc_ext
|
||||
standards:
|
||||
- llvm_libc_ext
|
||||
return_type: float
|
||||
arguments:
|
||||
- type: float
|
||||
|
|
|
|||
|
|
@ -218,7 +218,8 @@ functions:
|
|||
arguments:
|
||||
- type: void *
|
||||
- name: pthread_getattr_np
|
||||
standards: gnu
|
||||
standards:
|
||||
- gnu
|
||||
return_type: int
|
||||
arguments:
|
||||
- type: pthread_t
|
||||
|
|
|
|||
|
|
@ -21,13 +21,15 @@ functions:
|
|||
arguments:
|
||||
- type: size_t
|
||||
- name: hcreate_r
|
||||
standards: gnu
|
||||
standards:
|
||||
- gnu
|
||||
return_type: int
|
||||
arguments:
|
||||
- type: size_t
|
||||
- type: struct hsearch_data *
|
||||
- name: hdestroy
|
||||
standards: gnu
|
||||
standards:
|
||||
- gnu
|
||||
return_type: void
|
||||
arguments: []
|
||||
- name: hdestroy_r
|
||||
|
|
@ -44,7 +46,8 @@ functions:
|
|||
- type: ENTRY
|
||||
- type: ACTION
|
||||
- name: hsearch_r
|
||||
standards: gnu
|
||||
standards:
|
||||
- gnu
|
||||
return_type: int
|
||||
arguments:
|
||||
- type: ENTRY
|
||||
|
|
@ -116,14 +119,16 @@ functions:
|
|||
- type: const posix_tnode *
|
||||
- type: __action_fn_t
|
||||
- name: twalk_r
|
||||
standards: gnu
|
||||
standards:
|
||||
- gnu
|
||||
return_type: void
|
||||
arguments:
|
||||
- type: const posix_tnode *
|
||||
- type: __action_closure_fn_t
|
||||
- type: void *
|
||||
- name: tdestroy
|
||||
standards: gnu
|
||||
standards:
|
||||
- gnu
|
||||
return_type: void
|
||||
arguments:
|
||||
- type: posix_tnode *
|
||||
|
|
|
|||
|
|
@ -435,7 +435,8 @@ functions:
|
|||
- type: unsigned accum
|
||||
guard: LIBC_COMPILER_HAS_FIXED_POINT
|
||||
- name: sqrtulk
|
||||
standards: llvm_libc_stdfix_ext
|
||||
standards:
|
||||
- llvm_libc_stdfix_ext
|
||||
return_type: unsigned long accum
|
||||
arguments:
|
||||
- type: unsigned long accum
|
||||
|
|
|
|||
|
|
@ -93,7 +93,8 @@ functions:
|
|||
- type: size_t
|
||||
- type: int
|
||||
- name: munlock
|
||||
standards: POSIX
|
||||
standards:
|
||||
- posix
|
||||
return_type: int
|
||||
arguments:
|
||||
- type: void *
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
header: sys/syscall.h
|
||||
header_template: syscall.h.def
|
||||
standards: Linux
|
||||
standards:
|
||||
- linux
|
||||
macros: []
|
||||
types: []
|
||||
enums: []
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ LIBRARY_DESCRIPTIONS = {
|
|||
"linux": "Linux",
|
||||
"uefi": "UEFI",
|
||||
"svid": "SVID",
|
||||
"stdc_ext": "Standard C Extension",
|
||||
"llvm_libc_ext": "LLVM libc Extension",
|
||||
"llvm_libc_stdfix_ext": "LLVM libc stdfix Extension",
|
||||
}
|
||||
|
||||
HEADER_TEMPLATE = """\
|
||||
|
|
@ -156,11 +159,27 @@ class HeaderFile:
|
|||
)
|
||||
|
||||
def all_standards(self):
|
||||
# FIXME: Only functions have the "standard" field, but all the entity
|
||||
# types should have one too.
|
||||
return set(self.standards).union(
|
||||
*(filter(None, (f.standards for f in self.functions)))
|
||||
)
|
||||
standards = set(self.standards)
|
||||
for collection in [
|
||||
self.macros,
|
||||
self.types,
|
||||
self.enumerations,
|
||||
self.objects,
|
||||
self.functions,
|
||||
]:
|
||||
for item in collection:
|
||||
if item.standards:
|
||||
standards.update(item.standards)
|
||||
descriptions = LIBRARY_DESCRIPTIONS | self.extra_standards
|
||||
for standard in standards:
|
||||
if standard not in descriptions:
|
||||
# Provide a helpful error message with acceptable values.
|
||||
expected = ", ".join(sorted(descriptions.keys()))
|
||||
raise ValueError(
|
||||
f"Standard '{standard}' is not one of the canonical "
|
||||
f"identifiers: {expected}"
|
||||
)
|
||||
return standards
|
||||
|
||||
def includes(self):
|
||||
return (
|
||||
|
|
@ -190,6 +209,8 @@ class HeaderFile:
|
|||
return "_LLVM_LIBC_" + "_".join(words)
|
||||
|
||||
def library_description(self):
|
||||
# This also validates all standards.
|
||||
standards = self.all_standards()
|
||||
descriptions = LIBRARY_DESCRIPTIONS | self.extra_standards
|
||||
# If the header itself is in standard C, just call it that.
|
||||
if "stdc" in self.standards:
|
||||
|
|
@ -198,7 +219,6 @@ class HeaderFile:
|
|||
if "posix" in self.standards:
|
||||
return descriptions["posix"]
|
||||
# Otherwise, consider the standards for each symbol as well.
|
||||
standards = self.all_standards()
|
||||
# Otherwise, it's described by all those that apply, but ignoring
|
||||
# "stdc" and "posix" since this is not a "stdc" or "posix" header.
|
||||
return " / ".join(
|
||||
|
|
@ -340,6 +360,9 @@ class HeaderFile:
|
|||
"includes": sorted(str(file) for file in {COMMON_HEADER} | self.includes()),
|
||||
}
|
||||
|
||||
def validate(self):
|
||||
self.all_standards()
|
||||
|
||||
def emit_guard(self, content, current_guard, new_guard):
|
||||
if current_guard != new_guard:
|
||||
if current_guard is not None:
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ def main():
|
|||
return 2
|
||||
header.merge(merge_from_header)
|
||||
|
||||
header.validate()
|
||||
assert header.name, f"`header: name.h` line is required in {yaml_file}"
|
||||
return header
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class Symbol:
|
|||
def __init__(self, name):
|
||||
assert name
|
||||
self.name = name
|
||||
self.standards = []
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.name == other.name
|
||||
|
|
|
|||
|
|
@ -41,13 +41,13 @@ def yaml_to_classes(yaml_data, header_class, entry_points=None):
|
|||
header.merge_yaml_files = yaml_data.get("merge_yaml_files", [])
|
||||
|
||||
for macro_data in yaml_data.get("macros", []):
|
||||
header.add_macro(
|
||||
Macro(
|
||||
macro_data["macro_name"],
|
||||
macro_data.get("macro_value"),
|
||||
macro_data.get("macro_header"),
|
||||
)
|
||||
macro = Macro(
|
||||
macro_data["macro_name"],
|
||||
macro_data.get("macro_value"),
|
||||
macro_data.get("macro_header"),
|
||||
)
|
||||
macro.standards = macro_data.get("standards", [])
|
||||
header.add_macro(macro)
|
||||
|
||||
types = yaml_data.get("types", [])
|
||||
sorted_types = sorted(types, key=lambda x: x["type_name"])
|
||||
|
|
@ -65,12 +65,14 @@ def yaml_to_classes(yaml_data, header_class, entry_points=None):
|
|||
f"macro_header '{type_guard}' was found in this file."
|
||||
)
|
||||
|
||||
header.add_type(Type(type_name, type_guard))
|
||||
typ = Type(type_name, type_guard)
|
||||
typ.standards = type_data.get("standards", [])
|
||||
header.add_type(typ)
|
||||
|
||||
for enum_data in yaml_data.get("enums", []):
|
||||
header.add_enumeration(
|
||||
Enumeration(enum_data["name"], enum_data.get("value", None))
|
||||
)
|
||||
enum = Enumeration(enum_data["name"], enum_data.get("value", None))
|
||||
enum.standards = enum_data.get("standards", [])
|
||||
header.add_enumeration(enum)
|
||||
|
||||
functions = yaml_data.get("functions", [])
|
||||
if entry_points:
|
||||
|
|
@ -122,10 +124,9 @@ def yaml_to_classes(yaml_data, header_class, entry_points=None):
|
|||
objects = yaml_data.get("objects", [])
|
||||
sorted_objects = sorted(objects, key=lambda x: x["object_name"])
|
||||
for object_data in sorted_objects:
|
||||
header.add_object(
|
||||
Object(object_data["object_name"], object_data["object_type"])
|
||||
)
|
||||
|
||||
obj = Object(object_data["object_name"], object_data["object_type"])
|
||||
obj.standards = object_data.get("standards", [])
|
||||
header.add_object(obj)
|
||||
return header
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue