# Find sanitizers # # This module sets the following targets: # Sanitizer::address # Sanitizer::thread # Sanitizer::undefined # Sanitizer::leak # Sanitizer::memory include_guard(GLOBAL) option(UBSAN_FLAGS "additional UBSAN flags" OFF) get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) set(_source_code [==[ #include int main() { printf("hello world!"); return 0; } ]==]) include(CMakePushCheckState) cmake_push_check_state(RESET) foreach(sanitizer_name IN ITEMS address thread undefined leak memory) if(TARGET Sanitizer::${sanitizer_name}) continue() endif() set(CMAKE_REQUIRED_FLAGS "-fsanitize=${sanitizer_name};-fno-omit-frame-pointer") if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR CMAKE_C_COMPILER_ID STREQUAL "MSVC") if(sanitizer_name STREQUAL "address") set(CMAKE_REQUIRED_FLAGS "/fsanitize=${sanitizer_name}") else() continue() endif() endif() if(sanitizer_name STREQUAL "address") if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") list(APPEND CMAKE_REQUIRED_FLAGS "-shared-libasan") endif() endif() if(sanitizer_name STREQUAL "undefined" AND UBSAN_FLAGS) list(APPEND CMAKE_REQUIRED_FLAGS "${UBSAN_FLAGS}") endif() if(sanitizer_name STREQUAL "memory") list(APPEND CMAKE_REQUIRED_FLAGS "-fsanitize-memory-track-origins=2") endif() set(CMAKE_REQUIRED_QUIET ON) set(_run_res 0) include(CheckCSourceRuns) include(CheckCXXSourceRuns) foreach(lang IN LISTS languages) if(lang STREQUAL C) check_c_source_runs("${_source_code}" __${lang}_${sanitizer_name}_res) if(__${lang}_${sanitizer_name}_res) set(_run_res 1) endif() endif() if(lang STREQUAL CXX) check_cxx_source_runs("${_source_code}" __${lang}_${sanitizer_name}_res) if(__${lang}_${sanitizer_name}_res) set(_run_res 1) endif() endif() endforeach() if(_run_res) add_library(Sanitizer::${sanitizer_name} INTERFACE IMPORTED GLOBAL) target_compile_options( Sanitizer::${sanitizer_name} INTERFACE $<$,$>:${CMAKE_REQUIRED_FLAGS}> $<$,$>:${CMAKE_REQUIRED_FLAGS}> ) if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND NOT CMAKE_C_COMPILER_ID STREQUAL "MSVC") target_link_options( Sanitizer::${sanitizer_name} INTERFACE $<$,$>:${CMAKE_REQUIRED_FLAGS}> $<$,$>:${CMAKE_REQUIRED_FLAGS}> ) else() target_link_options( Sanitizer::${sanitizer_name} INTERFACE $<$,$>:/INCREMENTAL:NO> $<$,$>:/INCREMENTAL:NO> ) endif() if(sanitizer_name STREQUAL "address") target_compile_definitions( Sanitizer::${sanitizer_name} INTERFACE $<$,$>:_GLIBCXX_SANITIZE_VECTOR> $<$,$>:_GLIBCXX_SANITIZE_STD_ALLOCATOR> ) target_link_options( Sanitizer::${sanitizer_name} INTERFACE $<$,$,$>:-lasan> $<$,$,$>:-lasan> ) endif() if(sanitizer_name STREQUAL "undefined") target_link_options( Sanitizer::${sanitizer_name} INTERFACE $<$,$,$>:-lubsan> $<$,$,$>:-lubsan> ) endif() endif() endforeach() cmake_pop_check_state()