From 798bd72ff3a9b2a3a961ea5070c6507c5aa74d74 Mon Sep 17 00:00:00 2001 From: Denis Borisov Date: Thu, 12 Sep 2024 11:22:32 +0300 Subject: [PATCH] build: Add options to select sanitizers in configure.py We are going to add ThreadSanitizer that can't be used together with AddressSanitizer. We want to choose which sanitizers to use. There are options to use sanitizers: Use ASAN and UBSAN for Debug and Sanitize build types: ./configure.py Use specified sanitizers for Debug and Sanitize build types: ./configure.py --sanitizer address --sanitizer undefined Do not use sanitizers for any build type: ./configure.py --no-sanitizers Enabling santizers is consistently with Seastar_SANITIZE option. Specified sanitizers are passed to Seastar_SANITIZERS list. If it is empty and Seastar_SANITIZE option is enabled for this build, the content of Seastar_DEFAULT_SANITIZERS will be used. --- CMakeLists.txt | 33 +++++++++++++++++++++++---------- cmake/SeastarDependencies.cmake | 3 +++ configure.py | 16 ++++++++++++++-- seastar_cmake.py | 8 +++++--- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb4c0890563..8a17c0187fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -375,7 +375,9 @@ set (Seastar_SANITIZE "DEFAULT" CACHE STRING - "Enable ASAN and UBSAN. Can be ON, OFF or DEFAULT (which enables it for Debug and Sanitize)") + "Enable sanitizers. Can be ON, OFF or DEFAULT (which enables it for Debug and Sanitize)") + +list (APPEND Seastar_DEFAULT_SANITIZERS address undefined_behavior) set (Seastar_DEBUG_SHARED_PTR "DEFAULT" @@ -391,6 +393,19 @@ set (Seastar_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set (Seastar_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) set (Seastar_GEN_BINARY_DIR ${Seastar_BINARY_DIR}/gen) +include (TriStateOption) +tri_state_option (${Seastar_SANITIZE} + DEFAULT_BUILD_TYPES "Debug" "Sanitize" + CONDITION sanitizers_enabled) + +if (sanitizers_enabled) + if ((NOT Seastar_SANITIZERS) OR (Seastar_SANITIZERS STREQUAL "")) + set (Seastar_SANITIZERS ${Seastar_DEFAULT_SANITIZERS}) + endif () +else () + set (Seastar_SANITIZERS "") +endif () + # # Dependencies. # @@ -875,19 +890,17 @@ if (Seastar_DPDK) DPDK::dpdk) endif () -include (TriStateOption) -tri_state_option (${Seastar_SANITIZE} - DEFAULT_BUILD_TYPES "Debug" "Sanitize" - CONDITION condition) -if (condition) +if (sanitizers_enabled) if (NOT Sanitizers_FOUND) message (FATAL_ERROR "Sanitizers not found!") endif () set (Seastar_Sanitizers_OPTIONS ${Sanitizers_COMPILER_OPTIONS}) - target_link_libraries (seastar - PUBLIC - $<${condition}:Sanitizers::address> - $<${condition}:Sanitizers::undefined_behavior>) + foreach (component ${Seastar_SANITIZERS}) + string (TOUPPER ${component} COMPONENT) + target_link_libraries (seastar + PUBLIC + Sanitizers::${component}) + endforeach () endif () # We only need valgrind to find uninitialized memory uses, so disable diff --git a/cmake/SeastarDependencies.cmake b/cmake/SeastarDependencies.cmake index d23774dcea1..b7686559e20 100644 --- a/cmake/SeastarDependencies.cmake +++ b/cmake/SeastarDependencies.cmake @@ -141,6 +141,9 @@ macro (seastar_find_dependencies) seastar_set_dep_args (rt REQUIRED) seastar_set_dep_args (numactl OPTION ${Seastar_NUMA}) + seastar_set_dep_args (Sanitizers + COMPONENTS + ${Seastar_SANITIZERS}) seastar_set_dep_args (ucontext REQUIRED) seastar_set_dep_args (yaml-cpp REQUIRED VERSION 0.5.1) diff --git a/configure.py b/configure.py index c1fba65ad13..7766997740f 100755 --- a/configure.py +++ b/configure.py @@ -142,6 +142,8 @@ def standard_supported(standard, compiler='g++'): arg_parser.add_argument('--dpdk-machine', default='native', help='Specify the target architecture') add_tristate(arg_parser, name='deferred-action-require-noexcept', dest='deferred_action_require_noexcept', help='noexcept requirement for deferred actions', default=True) arg_parser.add_argument('--prefix', dest='install_prefix', default='/usr/local', help='Root installation path of Seastar files') +arg_parser.add_argument('--sanitizer', dest='sanitizers', action='append', default=[], help='Use specified sanitizer') +arg_parser.add_argument('--no-sanitizers', dest='no_sanitizers', action='store_true', default=False, help='Do not use sanitizers') args = arg_parser.parse_args() @@ -171,15 +173,23 @@ def identify_best_standard(cpp_standards, compiler): MODE_TO_CMAKE_BUILD_TYPE = {'release': 'RelWithDebInfo', 'debug': 'Debug', 'dev': 'Dev', 'sanitize': 'Sanitize' } +SANITIZER_TO_CMAKE = {'address': 'address', 'undefined': 'undefined_behavior'} + def configure_mode(mode): BUILD_PATH = seastar_cmake.build_path(mode, build_root=args.build_root) - CFLAGS = seastar_cmake.convert_strings_to_cmake_list( + CFLAGS = seastar_cmake.whitespace_separated_strings_to_cmake_list( args.user_cflags, args.user_optflags if seastar_cmake.is_release_mode(mode) else '') - LDFLAGS = seastar_cmake.convert_strings_to_cmake_list(args.user_ldflags) + LDFLAGS = seastar_cmake.whitespace_separated_strings_to_cmake_list(args.user_ldflags) + + SANITIZERS = seastar_cmake.strings_to_cmake_list(map(lambda s: SANITIZER_TO_CMAKE[s], args.sanitizers)) + + enable_sanitizers = None + if args.no_sanitizers: + enable_sanitizers = False TRANSLATED_ARGS = [ '-DCMAKE_BUILD_TYPE={}'.format(MODE_TO_CMAKE_BUILD_TYPE[mode]), @@ -209,6 +219,8 @@ def configure_mode(mode): tr(args.deferred_action_require_noexcept, 'DEFERRED_ACTION_REQUIRE_NOEXCEPT'), tr(args.unused_result_error, 'UNUSED_RESULT_ERROR'), tr(args.debug_shared_ptr, 'DEBUG_SHARED_PTR', value_when_none='default'), + tr(enable_sanitizers, 'SANITIZE', value_when_none='default'), + tr(SANITIZERS, 'SANITIZERS'), ] ingredients_to_cook = set(args.cook) diff --git a/seastar_cmake.py b/seastar_cmake.py index 105c01c50c0..fde59977dfe 100644 --- a/seastar_cmake.py +++ b/seastar_cmake.py @@ -34,12 +34,14 @@ def build_path(mode, build_root): def is_release_mode(mode): return mode == 'release' -def convert_strings_to_cmake_list(*args): +def strings_to_cmake_list(iterable): + return ';'.join(iterable) + +def whitespace_separated_strings_to_cmake_list(*args): """Converts a sequence of whitespace-separated strings of tokens into a semicolon-separated string of tokens for CMake. - """ - return ';'.join(' '.join(args).split()) + return strings_to_cmake_list(' '.join(args).split()) def translate_arg(arg, new_name, value_when_none='no'): """