From e4c368ee493741621deba1dcfe364af4e3d170e7 Mon Sep 17 00:00:00 2001 From: Douglas Stebila Date: Thu, 14 Feb 2019 11:29:49 -0500 Subject: [PATCH 1/3] Implement symbol namespace check using new Python testing framework. --- Makefile | 14 +--------- test/check_symbol_namespace.py | 43 ----------------------------- test/helpers.py | 1 + test/pqclean.py | 3 ++ test/test_symbol_namespace.py | 50 ++++++++++++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 56 deletions(-) delete mode 100644 test/check_symbol_namespace.py create mode 100644 test/test_symbol_namespace.py diff --git a/Makefile b/Makefile index 7857678e..80df2470 100644 --- a/Makefile +++ b/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: diff --git a/test/check_symbol_namespace.py b/test/check_symbol_namespace.py deleted file mode 100644 index 4a020801..00000000 --- a/test/check_symbol_namespace.py +++ /dev/null @@ -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)) diff --git a/test/helpers.py b/test/helpers.py index 06ccdbbf..32432917 100644 --- a/test/helpers.py +++ b/test/helpers.py @@ -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') diff --git a/test/pqclean.py b/test/pqclean.py index f52cee25..7a5d69c2 100644 --- a/test/pqclean.py +++ b/test/pqclean.py @@ -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(): diff --git a/test/test_symbol_namespace.py b/test/test_symbol_namespace.py new file mode 100644 index 00000000..c24edcb2 --- /dev/null +++ b/test/test_symbol_namespace.py @@ -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) From ba359473b94e28959da0c25fe24390d0e8f9bb78 Mon Sep 17 00:00:00 2001 From: Douglas Stebila Date: Thu, 14 Feb 2019 11:36:24 -0500 Subject: [PATCH 2/3] Remove old license check and reduce re-building --- .travis.yml | 2 +- Makefile | 8 -------- test/test_compile_lib.py | 4 ++++ test/test_functest.py | 4 ---- test/test_symbol_namespace.py | 4 ---- 5 files changed, 5 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index ca3f3e87..941b3808 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ matrix: os: linux compiler: gcc env: - - MAKETARGET="test-all tidy-all check-format check-metadata check-license-files" + - MAKETARGET="test-all tidy-all check-format check-metadata" addons: apt: packages: diff --git a/Makefile b/Makefile index 80df2470..80722184 100644 --- a/Makefile +++ b/Makefile @@ -175,14 +175,6 @@ run-sanitizer-all: sanitizer-all done @echo Tests completed -.PHONY: check-license-files -check-license-files: - @echo Checking that LICENSE files exist - @for scheme in $(ALL_SCHEMES); do \ - echo Checking for $$scheme/clean/LICENSE;\ - test -f $$scheme/clean/LICENSE || exit 1 ;\ - done - .PHONY: test-all test-all: run-functest-all run-valgrind-all run-sanitizer-all run-testvectors-all diff --git a/test/test_compile_lib.py b/test/test_compile_lib.py index e2896a17..d53df8cb 100644 --- a/test/test_compile_lib.py +++ b/test/test_compile_lib.py @@ -13,6 +13,10 @@ def test_compile_lib(): def check_compile_lib(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() diff --git a/test/test_functest.py b/test/test_functest.py index c54b7c96..b40ad2c9 100644 --- a/test/test_functest.py +++ b/test/test_functest.py @@ -13,10 +13,6 @@ def test_functest(): def check_functest(scheme_name, implementation_name): implementation = pqclean.Implementation.by_name(scheme_name, implementation_name) - helpers.run_subprocess( - ['make', 'clean', 'TYPE=' + implementation.scheme.type, 'SCHEME=' + scheme_name, 'IMPLEMENTATION=' + implementation_name], - os.path.join('..', 'test') - ) helpers.run_subprocess( ['make', 'TYPE=' + implementation.scheme.type, 'SCHEME=' + scheme_name, 'IMPLEMENTATION=' + implementation_name], os.path.join('..', 'test') diff --git a/test/test_symbol_namespace.py b/test/test_symbol_namespace.py index c24edcb2..33386b5f 100644 --- a/test/test_symbol_namespace.py +++ b/test/test_symbol_namespace.py @@ -16,10 +16,6 @@ def test_symbol_namespace(): 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() From 0943ae4c6e8f3e270761d6141b6ed229e2af9a08 Mon Sep 17 00:00:00 2001 From: Douglas Stebila Date: Thu, 14 Feb 2019 11:53:54 -0500 Subject: [PATCH 3/3] Remove old make target for symbol namespace check. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 941b3808..2fb93676 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,7 +50,7 @@ matrix: os: linux services: docker env: - - MAKETARGET="run-functest-all run-testvectors-all run-sanitizer-all run-symbol-namespace-all" + - MAKETARGET="run-functest-all run-testvectors-all run-sanitizer-all" script: - docker run --rm --privileged multiarch/qemu-user-static:register --reset - docker run --rm -v `pwd`:`pwd` -w `pwd` "pqclean/debian-unstable-ppc" /bin/bash -c "uname -a &&