Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
NAME: Address Sanitizer
- TARGET_CMAKE_ARGS: -DENABLE_SANITIZER_THREAD=ON -DCMAKE_BUILD_TYPE=Debug
NAME: Thread Sanitizer
- TARGET_CMAKE_ARGS: -DENABLE_SANITIZER_UNDEFINED_BEHAVIOR=ON -DCMAKE_BUILD_TYPE=Debug
NAME: Undefined Behavior Sanitizer
env:
ROS_DISTRO: rolling
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# ENABLE_SANITIZER_* options: instrument the library, test plugins and tests alike.
include(cmake/sanitizers.cmake)
class_loader_enable_sanitizers()

set(CLASS_LOADER_IGNORE_AMENT FALSE CACHE BOOL
"Do not use ament when building this package.")
if(NOT CLASS_LOADER_IGNORE_AMENT)
Expand Down
69 changes: 47 additions & 22 deletions cmake/sanitizers.cmake
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
function(enable_sanitizers project_name)
# Sets LIST_OF_SANITIZERS in the caller's scope to the comma-separated sanitizers selected by the
# ENABLE_SANITIZER_* options (empty if none, or if the compiler isn't GCC or Clang).
function(class_loader_get_sanitizers)
set(SANITIZERS "")

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")
Expand Down Expand Up @@ -46,23 +40,54 @@ function(enable_sanitizers project_name)
list(APPEND SANITIZERS "memory")
endif()
endif()
endif()

list(
JOIN
SANITIZERS
","
LIST_OF_SANITIZERS)
list(JOIN SANITIZERS "," LIST_OF_SANITIZERS)
set(LIST_OF_SANITIZERS "${LIST_OF_SANITIZERS}" PARENT_SCOPE)
endfunction()

# Sets the compile and link options for the selected sanitizers (and ENABLE_COVERAGE) on the
# current directory, so they apply to every target defined after this call, here and in
# subdirectories. Call it before defining any targets, so the library is instrumented as well as
# the tests and test plugins. Directory options aren't exported, so consumers of the installed
# library are unaffected.
function(class_loader_enable_sanitizers)
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)
add_compile_options(--coverage -O0 -g -fno-omit-frame-pointer)
add_link_options(--coverage)
endif()
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})
class_loader_get_sanitizers()
if(NOT LIST_OF_SANITIZERS STREQUAL "")
message(STATUS "class_loader: building with -fsanitize=${LIST_OF_SANITIZERS}")
set(flags -fsanitize=${LIST_OF_SANITIZERS} -fno-omit-frame-pointer)
if(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR)
# Make undefined behavior fail the test instead of only printing a diagnostic.
list(APPEND flags -fno-sanitize-recover=undefined)
endif()
add_compile_options(${flags})
add_link_options(${flags})
endif()
endfunction()

# Adds the options for the selected sanitizers (and ENABLE_COVERAGE) to the interface of target
# project_name. Kept for compatibility, since this file is installed; this package itself uses
# class_loader_enable_sanitizers().
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()
endif()

class_loader_get_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()
endfunction()
9 changes: 2 additions & 7 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ 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)
target_link_libraries(${PROJECT_NAME}_TestPlugins1 ${PROJECT_NAME})
class_loader_hide_library_symbols(${PROJECT_NAME}_TestPlugins1)
Expand Down Expand Up @@ -46,7 +41,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} project_options)
target_link_libraries(${PROJECT_NAME}_utest ${PROJECT_NAME})

if(NOT WIN32)
target_link_libraries(${PROJECT_NAME}_utest pthread)
Expand All @@ -63,7 +58,7 @@ ament_add_gtest(${PROJECT_NAME}_unmanaged_test unmanaged_test.cpp
)
if(TARGET ${PROJECT_NAME}_unmanaged_test)
target_include_directories(${PROJECT_NAME}_unmanaged_test PUBLIC "../include")
target_link_libraries(${PROJECT_NAME}_unmanaged_test ${PROJECT_NAME} project_options)
target_link_libraries(${PROJECT_NAME}_unmanaged_test ${PROJECT_NAME})
add_dependencies(${PROJECT_NAME}_unmanaged_test
${PROJECT_NAME}_TestPlugins1
${PROJECT_NAME}_TestPlugins3)
Expand Down
Loading