diff --git a/.github/asan.supp b/.github/asan.supp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.github/lsan.supp b/.github/lsan.supp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.github/ubsan.supp b/.github/ubsan.supp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.github/workflows/linux-eic-shell.yml b/.github/workflows/linux-eic-shell.yml index f0e514588e..baed984eae 100644 --- a/.github/workflows/linux-eic-shell.yml +++ b/.github/workflows/linux-eic-shell.yml @@ -14,6 +14,11 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +env: + ASAN_OPTIONS: suppressions=${{ github.workspace }}/.github/asan.supp:malloc_context_size=20:detect_leaks=1:verify_asan_link_order=0:detect_stack_use_after_return=1:detect_odr_violation=1:new_delete_type_mismatch=0:intercept_tls_get_addr=0 + LSAN_OPTIONS: suppressions=${{ github.workspace }}/.github/lsan.supp + UBSAN_OPTIONS: suppressions=${{ github.workspace }}/.github/ubsan.supp:print_stacktrace=1:silence_unsigned_overflow=1:report_error_type=1 + jobs: xmllint-before-build: runs-on: ubuntu-latest @@ -52,8 +57,11 @@ jobs: include: - CC: gcc CXX: g++ + # -Wno-error=maybe-uninitialized for GCC only as it has issues with /usr/include/c++/12/bits/std_function.h + CXXFLAGS: -Werror -Wall -Wextra -Wno-error=maybe-uninitialized - CC: clang CXX: clang++ + CXXFLAGS: -Werror -Wall -Wextra env: PREFIX: ${{ github.workspace }}/install steps: @@ -89,7 +97,7 @@ jobs: with: platform-release: "eic_xl:nightly" run: | - CC=${{ matrix.CC }} CXX=${{ matrix.CXX }} cmake -B build -S . -DCMAKE_INSTALL_PREFIX=${PREFIX} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + CC=${{ matrix.CC }} CXX=${{ matrix.CXX }} CXXFLAGS="${{ matrix.CXXFLAGS }}" cmake -B build -S . -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=${PREFIX} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DUSE_ASAN=ON -DUSE_UBSAN=ON cmake --build build -- -k -j $(getconf _NPROCESSORS_ONLN) install - uses: actions/upload-artifact@v4 with: diff --git a/CMakeLists.txt b/CMakeLists.txt index 49e5778d3f..8e35809902 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,60 @@ find_package(DD4hep 1.27 REQUIRED COMPONENTS DDCore DDRec) find_package(fmt REQUIRED) #----------------------------------------------------------------------------------- + +# Address sanitizer +option(USE_ASAN "Compile with address sanitizer" OFF) +if(${USE_ASAN}) + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=libasan.so + OUTPUT_VARIABLE PRELOAD_SANITIZER_LIB_ASAN + OUTPUT_STRIP_TRAILING_WHITESPACE) + list(PREPEND PRELOAD_SANITIZER_LIB ${PRELOAD_SANITIZER_LIB_ASAN}) +endif() + +# Undefined behavior sanitizer +option(USE_UBSAN "Compile with undefined behavior sanitizer" OFF) +if(${USE_UBSAN}) + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=libubsan.so + OUTPUT_VARIABLE PRELOAD_SANITIZER_LIB_UBSAN + OUTPUT_STRIP_TRAILING_WHITESPACE) + list(PREPEND PRELOAD_SANITIZER_LIB ${PRELOAD_SANITIZER_LIB_UBSAN}) +endif() + +#----------------------------------------------------------------------------------- + +function(dd4hep_generate_rootmap library) + + if(APPLE) + set(ENV_VAR DYLD_LIBRARY_PATH) + else() + set(ENV_VAR LD_LIBRARY_PATH) + endif() + set(${ENV_VAR}_VALUE $:$:$ENV{${ENV_VAR}}) + + set(rootmapfile ${CMAKE_SHARED_MODULE_PREFIX}${library}.components) + string(JOIN ":" LD_PRELOAD ${PRELOAD_SANITIZER_LIB}) + + add_custom_command(OUTPUT ${rootmapfile} + DEPENDS ${library} + COMMAND ${ENV_VAR}=${${ENV_VAR}_VALUE} LD_PRELOAD=${LD_PRELOAD} $ -o ${rootmapfile} $ + WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH} + COMMAND_EXPAND_LISTS + ) + + add_custom_target(Components_${library} ALL DEPENDS ${rootmapfile}) + SET( install_destination "lib" ) + if( CMAKE_INSTALL_LIBDIR ) + SET( install_destination ${CMAKE_INSTALL_LIBDIR} ) + endif() + install(FILES $/${rootmapfile} + DESTINATION ${install_destination} + ) +endfunction() + +#----------------------------------------------------------------------------------- + set(a_lib_name ${PROJECT_NAME}) set(DD4HEP_SET_RPATH TRUE) @@ -63,6 +117,34 @@ target_link_libraries(${a_lib_name} PUBLIC DD4hep::DDCore DD4hep::DDRec fmt::fmt ) +#----------------------------------------------------------------------------------- + +# Address sanitizer +if(${USE_ASAN}) + target_compile_options(${a_lib_name} PRIVATE -fsanitize=address -fno-omit-frame-pointer -g -O1) + target_link_options(${a_lib_name} PRIVATE -fsanitize=address) + target_link_libraries(${a_lib_name} PRIVATE asan) + install(FILES .github/asan.supp .github/lsan.supp + DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}) +endif() + +# Undefined behavior sanitizer +option(USE_UBSAN "Compile with undefined behavior sanitizer" OFF) +if(${USE_UBSAN}) + foreach(sanitizer undefined float-divide-by-zero unsigned-integer-overflow + implicit-conversion local-bounds nullability) + check_cxx_compiler_flag("-fsanitize=${sanitizer}" + CXX_COMPILER_HAS_sanitize_${sanitizer}) + if(CXX_COMPILER_HAS_sanitize_${sanitizer}) + target_compile_options(${a_lib_name} PRIVATE -fsanitize=${sanitizer} -g -O1) + target_link_options(${a_lib_name} PRIVATE -fsanitize=${sanitizer}) + target_link_libraries(${a_lib_name} PRIVATE ubsan) + endif() + endforeach() + install(FILES .github/ubsan.supp + DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}) +endif() + #----------------------------------------------------------------------------------- # Parse jinja templates: once by default, and once for all yml files set(TEMPLATE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/templates)