Implement symbol namespace check using new Python testing framework.
This commit is contained in:
parent
ff61e1d51d
commit
e4c368ee49
14
Makefile
14
Makefile
@ -121,8 +121,6 @@ help:
|
||||
@echo "make run-testvectors SCHEME=scheme Run testvector checks for SCHEME"
|
||||
@echo "make run-testvectors-all Run all testvector checks"
|
||||
@echo "make run-sanitizer-all Run address sanitizer for all schemes"
|
||||
@echo "make run-symbol-namespace SCHEME=scheme Run symbol namespace checks for SCHEME"
|
||||
@echo "make run-symbol-namespace-all Run all symbol namespace checks"
|
||||
@echo "make run-valgrind SCHEME=scheme Run valgrind checks for SCHEME"
|
||||
@echo "make run-valgrind-all Run valgrind checks all schemes"
|
||||
@echo "make clean Clean up the bin/ folder"
|
||||
@ -155,22 +153,12 @@ run-valgrind-all:
|
||||
run-testvectors: test/check_tvectors.py | require_scheme
|
||||
python3 test/check_tvectors.py $(SCHEME) || exit 1; \
|
||||
|
||||
.PHONY: run-symbol-namespace
|
||||
run-symbol-namespace: test/check_symbol_namespace.py | require_scheme
|
||||
python3 test/check_symbol_namespace.py $(SCHEME) || exit 1; \
|
||||
|
||||
.PHONY: run-testvectors-all
|
||||
run-testvectors-all: test/check_tvectors.py
|
||||
@for scheme in $(ALL_SCHEMES); do \
|
||||
python3 test/check_tvectors.py $$scheme || exit 1; \
|
||||
done
|
||||
|
||||
.PHONY: run-symbol-namespace-all
|
||||
run-symbol-namespace-all:
|
||||
@for scheme in $(ALL_SCHEMES); do \
|
||||
python3 test/check_symbol_namespace.py $$scheme || exit 1; \
|
||||
done
|
||||
|
||||
.PHONY: run-functest-all
|
||||
run-functest-all: functest-all
|
||||
@for functest in $$(find bin/ -maxdepth 1 -name 'functest_*' -not -type d) ; do \
|
||||
@ -196,7 +184,7 @@ check-license-files:
|
||||
done
|
||||
|
||||
.PHONY: test-all
|
||||
test-all: run-functest-all run-valgrind-all run-sanitizer-all run-testvectors-all run-symbol-namespace-all
|
||||
test-all: run-functest-all run-valgrind-all run-sanitizer-all run-testvectors-all
|
||||
|
||||
.PHONY: tidy-all
|
||||
tidy-all:
|
||||
|
@ -1,43 +0,0 @@
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
"""
|
||||
For a given SCHEME, this script verifies that all exported symbols are properly
|
||||
namespaced, i.e., all start with "PQCLEAN_SCHEMENAME_"
|
||||
"""
|
||||
|
||||
if sys.platform != 'linux':
|
||||
print("This test is not supported on non-Linux platforms")
|
||||
exit(0)
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print("Provide a scheme name (e.g. crypto_kem/kyber768) as argv[1]")
|
||||
exit(1)
|
||||
|
||||
SCHEME = sys.argv[1]
|
||||
SCHEMEFULL = SCHEME.replace('/', '_') # e.g. crypto_kem_kyber768
|
||||
SCHEMESHORT = SCHEME.split('/')[1].upper()
|
||||
namespace = "PQCLEAN_{}_".format(SCHEMESHORT).replace('-', '')
|
||||
|
||||
# TODO can we do this using object files instead, to preserve file origin?
|
||||
sharedlib = "bin/shared_{}_clean.so".format(SCHEMEFULL)
|
||||
subprocess.run(["make", sharedlib, "SCHEME={}".format(SCHEME)])
|
||||
p = subprocess.run(["nm", "-D", sharedlib], stdout=subprocess.PIPE)
|
||||
|
||||
symbols = p.stdout.decode('utf-8').strip().split("\n")
|
||||
non_namespaced = []
|
||||
|
||||
for symbolstr in symbols:
|
||||
*_, symtype, symbol = symbolstr.split()
|
||||
if symtype in 'TR':
|
||||
if not symbol.startswith(namespace):
|
||||
non_namespaced.append(symbol)
|
||||
|
||||
if non_namespaced:
|
||||
print("! Not all symbols were properly namespaced.", file=sys.stderr)
|
||||
print("! Missing namespace literal {}".format(namespace), file=sys.stderr)
|
||||
for symbol in non_namespaced:
|
||||
print("\t{}".format(symbol), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("Checking {} succeeded".format(SCHEME))
|
@ -11,3 +11,4 @@ def run_subprocess(command, working_dir, expected_returncode = 0):
|
||||
)
|
||||
print(result.stdout.decode('utf-8'))
|
||||
assert(result.returncode == expected_returncode)
|
||||
return result.stdout.decode('utf-8')
|
||||
|
@ -10,6 +10,9 @@ class Scheme:
|
||||
def path(self, base='..'):
|
||||
return os.path.join(base, 'crypto_' + self.type, self.name)
|
||||
|
||||
def namespace_prefix(self):
|
||||
return 'PQCLEAN_{}_'.format(self.name.upper()).replace('-', '')
|
||||
|
||||
@staticmethod
|
||||
def by_name(scheme_name):
|
||||
for scheme in Scheme.all_schemes():
|
||||
|
50
test/test_symbol_namespace.py
Normal file
50
test/test_symbol_namespace.py
Normal file
@ -0,0 +1,50 @@
|
||||
"""
|
||||
Checks that the all exported symbols are properly namespaced, i.e., all start with "PQCLEAN_SCHEMENAME_".
|
||||
"""
|
||||
|
||||
import os
|
||||
import pqclean
|
||||
import helpers
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
def test_symbol_namespace():
|
||||
if sys.platform not in ['linux', 'darwin']: raise unittest.SkipTest()
|
||||
for scheme in pqclean.Scheme.all_schemes():
|
||||
for implementation in scheme.implementations:
|
||||
yield check_symbol_namespace, scheme.name, implementation.name
|
||||
|
||||
def check_symbol_namespace(scheme_name, implementation_name):
|
||||
implementation = pqclean.Implementation.by_name(scheme_name, implementation_name)
|
||||
helpers.run_subprocess(
|
||||
['make', 'clean'],
|
||||
implementation.path()
|
||||
)
|
||||
helpers.run_subprocess(
|
||||
['make'],
|
||||
implementation.path()
|
||||
)
|
||||
out = helpers.run_subprocess(
|
||||
['nm', '-g', 'lib{}_{}.a'.format(scheme_name, implementation_name)],
|
||||
implementation.path()
|
||||
)
|
||||
|
||||
lines = out.strip().split("\n")
|
||||
symbols = []
|
||||
for line in lines:
|
||||
if ' T ' in line or ' D ' in line or ' S ' in line:
|
||||
symbols.append(line)
|
||||
|
||||
namespace = implementation.scheme.namespace_prefix()
|
||||
non_namespaced = []
|
||||
for symbolstr in symbols:
|
||||
*_, symtype, symbol = symbolstr.split()
|
||||
if symtype in 'TR':
|
||||
if not symbol.startswith(namespace) and not symbol.startswith('_' + namespace):
|
||||
non_namespaced.append(symbol)
|
||||
|
||||
if non_namespaced:
|
||||
print("Missing namespace literal {}".format(namespace))
|
||||
for symbol in non_namespaced:
|
||||
print("\ttype: {}, symbol: {}".format(symtype, symbol))
|
||||
assert(False)
|
Loading…
Reference in New Issue
Block a user