From 4476c07bae00dc2cec5183878d81b3e53ff3b97e Mon Sep 17 00:00:00 2001 From: Matthias Gierlings Date: Fri, 6 Apr 2018 20:20:35 +0200 Subject: Make tests pass by default in UBSAN mode - Adds macros to check if botan was compiled with a certain sanitizers. - Automatically excludes the tests that are intended to provoke undefined behaviour from the test bench, when botan is compiled with UBSAN. - Changes option `--avoid-undefined` to `--no-avoid-undefined` so the failing tests can be explicitly activated when needed. --- configure.py | 5 +++++ src/build-data/buildh.in | 4 ++++ src/tests/main.cpp | 4 ++-- src/tests/test_dl_group.cpp | 7 +++++-- src/tests/test_ffi.cpp | 6 +++++- src/tests/tests.h | 10 +++++----- src/tests/unit_ecdsa.cpp | 6 +++++- 7 files changed, 31 insertions(+), 11 deletions(-) diff --git a/configure.py b/configure.py index 8bc18bbba..986081279 100755 --- a/configure.py +++ b/configure.py @@ -1099,6 +1099,7 @@ class CompilerInfo(InfoObject): # pylint: disable=too-many-instance-attributes self.output_to_object = lex.output_to_object self.preproc_flags = lex.preproc_flags self.sanitizers = lex.sanitizers + self.sanitizer_types = [] self.shared_flags = lex.shared_flags self.size_optimization_flags = lex.size_optimization_flags self.so_link_commands = lex.so_link_commands @@ -1224,6 +1225,8 @@ class CompilerInfo(InfoObject): # pylint: disable=too-many-instance-attributes else: abi_link.add(self.sanitizers[s]) + self.sanitizer_types = san + if options.with_openmp: if 'openmp' not in self.mach_abi_linking: raise UserError('No support for OpenMP for %s' % (self.basename)) @@ -1866,6 +1869,8 @@ def create_template_vars(source_paths, build_paths, options, modules, cc, arch, 'linker': cc.linker_name or '$(CXX)', 'make_supports_phony': cc.basename != 'msvc', + 'sanitizer_types' : sorted(cc.sanitizer_types), + 'cc_compile_opt_flags': cc.cc_compile_flags(options, False, True), 'cc_compile_debug_flags': cc.cc_compile_flags(options, True, False), diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in index d42e85ac4..807b6f479 100644 --- a/src/build-data/buildh.in +++ b/src/build-data/buildh.in @@ -52,6 +52,10 @@ #define BOTAN_BUILD_COMPILER_IS_%{cc_macro} +%{for sanitizer_types} +#define BOTAN_HAS_SANITIZER_%{i|upper} +%{endfor} + #define BOTAN_TARGET_ARCH_IS_%{arch|upper} %{if endian} #define BOTAN_TARGET_CPU_IS_%{endian|upper}_ENDIAN diff --git a/src/tests/main.cpp b/src/tests/main.cpp index 5cf4e4fe3..0e0360783 100644 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -60,7 +60,7 @@ int main(int argc, char* argv[]) { const std::string arg_spec = "botan-test --verbose --help --data-dir= --pkcs11-lib= --provider= " - "--log-success --abort-on-first-fail --avoid-undefined " + "--log-success --abort-on-first-fail --no-avoid-undefined " "--run-long-tests --run-online-tests --test-runs=1 --drbg-seed= " "*suites"; @@ -85,7 +85,7 @@ int main(int argc, char* argv[]) parser.flag_set("run-online-tests"), parser.flag_set("run-long-tests"), parser.flag_set("abort-on-first-fail"), - parser.flag_set("avoid-undefined")); + parser.flag_set("no-avoid-undefined")); #if defined(BOTAN_HAS_OPENSSL) if(opts.provider().empty() || opts.provider() == "openssl") diff --git a/src/tests/test_dl_group.cpp b/src/tests/test_dl_group.cpp index 10a7e3bc6..c9e654bd7 100644 --- a/src/tests/test_dl_group.cpp +++ b/src/tests/test_dl_group.cpp @@ -44,16 +44,19 @@ class DL_Group_Tests final : public Test "DL_Group uninitialized", []() { Botan::DL_Group dl; dl.get_p(); }); - if(Test::avoid_undefined_behavior() == false) +#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) + if(Test::no_avoid_undefined_behavior()) { +#endif result.test_throws("Bad generator param", "Invalid argument DL_Group unknown PrimeType", []() { auto invalid_type = static_cast(9); Botan::DL_Group dl(Test::rng(), invalid_type, 1024); }); +#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) } - +#endif return result; } diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index 58b9852a0..0d831f251 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -842,14 +842,18 @@ class FFI_Unit_Tests final : public Test // delete of null is ok/ignored TEST_FFI_RC(0, botan_hash_destroy, (nullptr)); - if(Test::avoid_undefined_behavior() == false) +#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) + if(Test::no_avoid_undefined_behavior()) { +#endif // Confirm that botan_x_destroy checks the argument type botan_mp_t mp; botan_mp_init(&mp); TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT, botan_hash_destroy, (reinterpret_cast(mp))); TEST_FFI_RC(0, botan_mp_destroy, (mp)); +#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) } +#endif return result; } diff --git a/src/tests/tests.h b/src/tests/tests.h index 0c63797fa..56aa4b8c5 100644 --- a/src/tests/tests.h +++ b/src/tests/tests.h @@ -62,7 +62,7 @@ class Test_Options bool run_online_tests, bool run_long_tests, bool abort_on_first_fail, - bool avoid_undefined) : + bool no_avoid_undefined) : m_requested_tests(requested_tests), m_data_dir(data_dir), m_pkcs11_lib(pkcs11_lib), @@ -73,7 +73,7 @@ class Test_Options m_run_online_tests(run_online_tests), m_run_long_tests(run_long_tests), m_abort_on_first_fail(abort_on_first_fail), - m_avoid_undefined(avoid_undefined) + m_no_avoid_undefined(no_avoid_undefined) {} const std::vector& requested_tests() const @@ -97,7 +97,7 @@ class Test_Options bool abort_on_first_fail() const { return m_abort_on_first_fail; } - bool avoid_undefined_behavior() const { return m_avoid_undefined; } + bool no_avoid_undefined_behavior() const { return m_no_avoid_undefined; } private: std::vector m_requested_tests; @@ -110,7 +110,7 @@ class Test_Options bool m_run_online_tests; bool m_run_long_tests; bool m_abort_on_first_fail; - bool m_avoid_undefined; + bool m_no_avoid_undefined; }; /* @@ -466,7 +466,7 @@ class Test static void set_test_rng(std::unique_ptr rng); - static bool avoid_undefined_behavior() { return m_opts.avoid_undefined_behavior(); } + static bool no_avoid_undefined_behavior() { return m_opts.no_avoid_undefined_behavior(); } static bool log_success() { return m_opts.log_success(); } static bool run_online_tests() { return m_opts.run_online_tests(); } static bool run_long_tests() { return m_opts.run_long_tests(); } diff --git a/src/tests/unit_ecdsa.cpp b/src/tests/unit_ecdsa.cpp index dc2a43af5..f94f445ee 100644 --- a/src/tests/unit_ecdsa.cpp +++ b/src/tests/unit_ecdsa.cpp @@ -299,14 +299,18 @@ Test::Result test_encoding_options() result.test_eq("Hybrid point same size as uncompressed", enc_uncompressed.size(), enc_hybrid.size()); - if(Test::avoid_undefined_behavior() == false) +#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) + if(Test::no_avoid_undefined_behavior()) { +#endif auto invalid_format = static_cast(99); result.test_throws("Invalid point format throws", "Invalid argument Invalid point encoding for EC_PublicKey", [&] { key.set_point_encoding(invalid_format); }); +#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) } +#endif return result; } -- cgit v1.2.3 From a96d1ca450a9cadea8157f3295a970af1f16a58f Mon Sep 17 00:00:00 2001 From: Matthias Gierlings Date: Sat, 7 Apr 2018 17:47:11 +0200 Subject: Moves UBSAN macros from test files to Test_Options To keep the code more readable change the behavior of `Test_Options::no_avoid_undefined_behavior()`, instead of the conditionals inside the tests. `Test_Options::no_avoid_undefined_behavior()` will always return `true` if UBSAN is inactive. This way all tests, including those that cause undefined behaviour, will run. Once botan is compiled with UBSAN those tests will be automatically skipped unless the `--no-avoid-undefined` is passed to the test-bench. --- src/tests/test_dl_group.cpp | 5 +---- src/tests/test_ffi.cpp | 4 ---- src/tests/tests.h | 9 ++++++++- src/tests/unit_ecdsa.cpp | 4 ---- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/tests/test_dl_group.cpp b/src/tests/test_dl_group.cpp index c9e654bd7..064cb2221 100644 --- a/src/tests/test_dl_group.cpp +++ b/src/tests/test_dl_group.cpp @@ -44,19 +44,16 @@ class DL_Group_Tests final : public Test "DL_Group uninitialized", []() { Botan::DL_Group dl; dl.get_p(); }); -#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) if(Test::no_avoid_undefined_behavior()) { -#endif result.test_throws("Bad generator param", "Invalid argument DL_Group unknown PrimeType", []() { auto invalid_type = static_cast(9); Botan::DL_Group dl(Test::rng(), invalid_type, 1024); }); -#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) } -#endif + return result; } diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index 0d831f251..d5627a45f 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -842,18 +842,14 @@ class FFI_Unit_Tests final : public Test // delete of null is ok/ignored TEST_FFI_RC(0, botan_hash_destroy, (nullptr)); -#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) if(Test::no_avoid_undefined_behavior()) { -#endif // Confirm that botan_x_destroy checks the argument type botan_mp_t mp; botan_mp_init(&mp); TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT, botan_hash_destroy, (reinterpret_cast(mp))); TEST_FFI_RC(0, botan_mp_destroy, (mp)); -#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) } -#endif return result; } diff --git a/src/tests/tests.h b/src/tests/tests.h index 56aa4b8c5..8551e4e4d 100644 --- a/src/tests/tests.h +++ b/src/tests/tests.h @@ -97,7 +97,14 @@ class Test_Options bool abort_on_first_fail() const { return m_abort_on_first_fail; } - bool no_avoid_undefined_behavior() const { return m_no_avoid_undefined; } + bool no_avoid_undefined_behavior() const + { +#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) + return m_no_avoid_undefined; +#else + return true; +#endif + } private: std::vector m_requested_tests; diff --git a/src/tests/unit_ecdsa.cpp b/src/tests/unit_ecdsa.cpp index f94f445ee..e21d4764c 100644 --- a/src/tests/unit_ecdsa.cpp +++ b/src/tests/unit_ecdsa.cpp @@ -299,18 +299,14 @@ Test::Result test_encoding_options() result.test_eq("Hybrid point same size as uncompressed", enc_uncompressed.size(), enc_hybrid.size()); -#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) if(Test::no_avoid_undefined_behavior()) { -#endif auto invalid_format = static_cast(99); result.test_throws("Invalid point format throws", "Invalid argument Invalid point encoding for EC_PublicKey", [&] { key.set_point_encoding(invalid_format); }); -#if defined(BOTAN_HAS_SANITIZER_UNDEFINED) } -#endif return result; } -- cgit v1.2.3