blob: 28be7e5901d71fe0c223cf3c698ebbcf5f82dd02 [file] [log] [blame]
# 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 <stdio.h>
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
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>>:${CMAKE_REQUIRED_FLAGS}>
$<$<AND:$<COMPILE_LANGUAGE:C>,$<BOOL:$__C_${sanitizer_name}_res>>:${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
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>>:${CMAKE_REQUIRED_FLAGS}>
$<$<AND:$<COMPILE_LANGUAGE:C>,$<BOOL:$__C_${sanitizer_name}_res>>:${CMAKE_REQUIRED_FLAGS}>
)
else()
target_link_options(
Sanitizer::${sanitizer_name}
INTERFACE
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>>:/INCREMENTAL:NO>
$<$<AND:$<COMPILE_LANGUAGE:C>,$<BOOL:$__C_${sanitizer_name}_res>>:/INCREMENTAL:NO>
)
endif()
if(sanitizer_name STREQUAL "address")
target_compile_definitions(
Sanitizer::${sanitizer_name}
INTERFACE
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>>:_GLIBCXX_SANITIZE_VECTOR>
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>>:_GLIBCXX_SANITIZE_STD_ALLOCATOR>
)
target_link_options(
Sanitizer::${sanitizer_name}
INTERFACE
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>,$<CXX_COMPILER_ID:GNU>>:-lasan>
$<$<AND:$<COMPILE_LANGUAGE:C>,$<BOOL:$__C_${sanitizer_name}_res>,$<C_COMPILER_ID:GNU>>:-lasan>
)
endif()
if(sanitizer_name STREQUAL "undefined")
target_link_options(
Sanitizer::${sanitizer_name}
INTERFACE
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>,$<CXX_COMPILER_ID:GNU>>:-lubsan>
$<$<AND:$<COMPILE_LANGUAGE:C>,$<BOOL:$__C_${sanitizer_name}_res>,$<C_COMPILER_ID:GNU>>:-lubsan>
)
endif()
endif()
endforeach()
cmake_pop_check_state()