1
0
mirror of https://github.com/Mbed-TLS/mbedtls.git synced 2025-07-29 11:41:15 +03:00

Clean up not-implemented detection

Move hack_dependencies_not_implemented into a class to make the file
structure easier to understand and reduce the visibility of the
_implemented_dependencies cache. Rename it because it's no longer a
temporary hack (originally intended to work around the fact that not all
PSA_WANT symbols were implemented), it's now a way to detect test cases for
cryptographic mechanisms that are declared but not implemented.

Internal refactoring only. No behavior change.

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
This commit is contained in:
Gilles Peskine
2024-04-10 20:41:51 +02:00
parent 995d7d4c15
commit 519762b7e6

View File

@ -6,7 +6,7 @@
import re
from typing import Dict, FrozenSet, List, Optional, Set
from typing import Dict, FrozenSet, Iterator, List, Optional, Set
from . import macro_collector
from . import test_case
@ -54,30 +54,6 @@ def automatic_dependencies(*expressions: str) -> List[str]:
used.difference_update(SYMBOLS_WITHOUT_DEPENDENCY)
return sorted(psa_want_symbol(name) for name in used)
# Skip test cases for which the dependency symbols are not defined.
# We assume that this means that a required mechanism is not implemented.
# Note that if we erroneously skip generating test cases for
# mechanisms that are not implemented, this should be caught
# by the NOT_SUPPORTED test cases generated by generate_psa_tests.py
# in test_suite_psa_crypto_not_supported and test_suite_psa_crypto_op_fail:
# those emit negative tests, which will not be skipped here.
def read_implemented_dependencies(filename: str) -> FrozenSet[str]:
return frozenset(symbol
for line in open(filename)
for symbol in re.findall(r'\bPSA_WANT_\w+\b', line))
_implemented_dependencies = None #type: Optional[FrozenSet[str]] #pylint: disable=invalid-name
def hack_dependencies_not_implemented(dependencies: List[str]) -> None:
global _implemented_dependencies #pylint: disable=global-statement,invalid-name
if _implemented_dependencies is None:
_implemented_dependencies = \
read_implemented_dependencies('include/psa/crypto_config.h')
_implemented_dependencies = _implemented_dependencies.union(
read_implemented_dependencies('include/mbedtls/config_psa.h'))
for dep in dependencies:
if dep.startswith('PSA_WANT') and dep not in _implemented_dependencies:
dependencies.append('DEPENDENCY_NOT_IMPLEMENTED_YET_' + dep)
dependencies.sort()
class Information:
"""Gather information about PSA constructors."""
@ -119,6 +95,47 @@ class TestCase(test_case.TestCase):
involved in a given test case.
"""
# Use a class variable to cache the set of implemented dependencies.
# Call read_implemented_dependencies() to fill the cache.
_implemented_dependencies = None #type: Optional[FrozenSet[str]]
DEPENDENCY_SYMBOL_RE = re.compile(r'\bPSA_WANT_\w+\b')
@classmethod
def _yield_implemented_dependencies(cls) -> Iterator[str]:
for filename in ['include/psa/crypto_config.h',
'include/mbedtls/config_psa.h']:
with open(filename) as inp:
content = inp.read()
yield from cls.DEPENDENCY_SYMBOL_RE.findall(content)
@classmethod
def read_implemented_dependencies(cls) -> FrozenSet[str]:
if cls._implemented_dependencies is None:
cls._implemented_dependencies = \
frozenset(cls._yield_implemented_dependencies())
# Redundant return to reassure pylint (mypy is fine without it).
# Known issue: https://github.com/pylint-dev/pylint/issues/3045
return cls._implemented_dependencies
return cls._implemented_dependencies
# We skip test cases for which the dependency symbols are not defined.
# We assume that this means that a required mechanism is not implemented.
# Note that if we erroneously skip generating test cases for
# mechanisms that are not implemented, this should be caught
# by the NOT_SUPPORTED test cases generated by generate_psa_tests.py
# in test_suite_psa_crypto_not_supported and test_suite_psa_crypto_op_fail:
# those emit negative tests, which will not be skipped here.
def detect_not_implemented_dependencies(self) -> None:
"""Detect dependencies that are not implemented."""
all_implemented_dependencies = self.read_implemented_dependencies()
not_implemented = set()
for dep in self.dependencies:
if (dep.startswith('PSA_WANT') and
dep not in all_implemented_dependencies):
not_implemented.add('DEPENDENCY_NOT_IMPLEMENTED_YET_' + dep)
self.dependencies = sorted(not_implemented) + self.dependencies
self.dependencies.sort()
def __init__(self) -> None:
super().__init__()
self.key_bits = None #type: Optional[int]
@ -157,5 +174,5 @@ class TestCase(test_case.TestCase):
dependencies[i] = '!' + dependencies[i]
if self.key_bits is not None:
dependencies = finish_family_dependencies(dependencies, self.key_bits)
hack_dependencies_not_implemented(dependencies)
self.dependencies += dependencies
self.dependencies += sorted(dependencies)
self.detect_not_implemented_dependencies()