From 898a14962986804d5be0001d73f0ab5f70fb96a1 Mon Sep 17 00:00:00 2001 From: Tyler Weaver Date: Sun, 12 Jun 2022 08:26:16 -0600 Subject: [PATCH] Thread and Address Sanitizer CI Signed-off-by: Tyler Weaver --- .github/workflows/ci.yaml | 30 +++++++++++++++++ cmake/sanitizers.cmake | 68 +++++++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 9 ++++-- 3 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ci.yaml create mode 100644 cmake/sanitizers.cmake diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 00000000..9836444b --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,30 @@ +# This config uses industrial_ci (https://github.com/ros-industrial/industrial_ci.git). +# For troubleshooting, see readme (https://github.com/ros-industrial/industrial_ci/blob/master/README.rst) + +name: CI + +on: + workflow_dispatch: + pull_request: + push: + branches: + - ros2 + +jobs: + ci: + strategy: + fail-fast: false + matrix: + env: + - TARGET_CMAKE_ARGS: -DENABLE_SANITIZER_ADDRESS=ON -DCMAKE_BUILD_TYPE=Debug + NAME: Address Sanitizer + - TARGET_CMAKE_ARGS: -DENABLE_SANITIZER_THREAD=ON -DCMAKE_BUILD_TYPE=Debug + NAME: Thread Sanitizer + env: + ROS_DISTRO: rolling + runs-on: ubuntu-latest + name: ${{ matrix.env.NAME }} + steps: + - uses: actions/checkout@v2 + - uses: 'ros-industrial/industrial_ci@master' + env: ${{matrix.env}} diff --git a/cmake/sanitizers.cmake b/cmake/sanitizers.cmake new file mode 100644 index 00000000..b264fbee --- /dev/null +++ b/cmake/sanitizers.cmake @@ -0,0 +1,68 @@ +function(enable_sanitizers project_name) + + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + option(ENABLE_COVERAGE "Enable coverage reporting for gcc/clang" OFF) + + if(ENABLE_COVERAGE) + target_compile_options(${project_name} INTERFACE --coverage -O0 -g -fno-omit-frame-pointer) + target_link_libraries(${project_name} INTERFACE --coverage) + endif() + + set(SANITIZERS "") + + option(ENABLE_SANITIZER_ADDRESS "Enable address sanitizer" OFF) + if(ENABLE_SANITIZER_ADDRESS) + list(APPEND SANITIZERS "address") + endif() + + option(ENABLE_SANITIZER_LEAK "Enable leak sanitizer" OFF) + if(ENABLE_SANITIZER_LEAK) + list(APPEND SANITIZERS "leak") + endif() + + option(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR "Enable undefined behavior sanitizer" OFF) + if(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR) + list(APPEND SANITIZERS "undefined") + endif() + + option(ENABLE_SANITIZER_THREAD "Enable thread sanitizer" OFF) + if(ENABLE_SANITIZER_THREAD) + if("address" IN_LIST SANITIZERS OR "leak" IN_LIST SANITIZERS) + message(WARNING "Thread sanitizer does not work with Address and Leak sanitizer enabled") + else() + list(APPEND SANITIZERS "thread") + endif() + endif() + + option(ENABLE_SANITIZER_MEMORY "Enable memory sanitizer" OFF) + if(ENABLE_SANITIZER_MEMORY AND CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + message(WARNING "Memory sanitizer requires all the code (including libc++) \ + to be MSan-instrumented otherwise it reports false positives") + if("address" IN_LIST SANITIZERS + OR "thread" IN_LIST SANITIZERS + OR "leak" IN_LIST SANITIZERS) + message(WARNING "Memory sanitizer does not work with Address, Thread and Leak sanitizer enabled") + else() + list(APPEND SANITIZERS "memory") + endif() + endif() + + list( + JOIN + SANITIZERS + "," + LIST_OF_SANITIZERS) + + endif() + + if(LIST_OF_SANITIZERS) + if(NOT + "${LIST_OF_SANITIZERS}" + STREQUAL + "") + target_compile_options(${project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS}) + target_link_options(${project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS}) + endif() + endif() + +endfunction() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 50f0b67a..640a1ff3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,6 +2,11 @@ find_package(ament_cmake_gtest REQUIRED) include("../cmake/class_loader_hide_library_symbols.cmake") +# Link this 'library' to set the compile-time options requested +add_library(project_options INTERFACE) +include(../cmake/sanitizers.cmake) +enable_sanitizers(project_options) + add_library(${PROJECT_NAME}_TestPlugins1 EXCLUDE_FROM_ALL SHARED plugins1.cpp) if(ament_cmake_FOUND) target_include_directories(${PROJECT_NAME}_TestPlugins1 @@ -60,7 +65,7 @@ if(TARGET ${PROJECT_NAME}_utest) PUBLIC "../include" ${console_bridge_INCLUDE_DIRS}) target_link_libraries(${PROJECT_NAME}_utest) endif() - target_link_libraries(${PROJECT_NAME}_utest ${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME}_utest ${PROJECT_NAME} project_options) if(NOT WIN32) target_link_libraries(${PROJECT_NAME}_utest pthread) endif() @@ -83,7 +88,7 @@ if(TARGET ${PROJECT_NAME}_unique_ptr_test) PUBLIC "../include") target_link_libraries(${PROJECT_NAME}_unique_ptr_test) endif() - target_link_libraries(${PROJECT_NAME}_unique_ptr_test ${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME}_unique_ptr_test ${PROJECT_NAME} project_options) if(NOT WIN32) target_link_libraries(${PROJECT_NAME}_unique_ptr_test pthread) endif()