1# Find sanitizers 2# 3# This module sets the following targets: 4# Sanitizer::address 5# Sanitizer::thread 6# Sanitizer::undefined 7# Sanitizer::leak 8# Sanitizer::memory 9include_guard(GLOBAL) 10 11option(UBSAN_FLAGS "additional UBSAN flags" OFF) 12 13get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) 14 15set(_source_code 16 [==[ 17 #include <stdio.h> 18 int main() { 19 printf("hello world!"); 20 return 0; 21 } 22 ]==]) 23 24include(CMakePushCheckState) 25cmake_push_check_state(RESET) 26foreach(sanitizer_name IN ITEMS address thread undefined leak memory) 27 if(TARGET Sanitizer::${sanitizer_name}) 28 continue() 29 endif() 30 31 set(CMAKE_REQUIRED_FLAGS 32 "-fsanitize=${sanitizer_name};-fno-omit-frame-pointer") 33 if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR CMAKE_C_COMPILER_ID STREQUAL 34 "MSVC") 35 if(sanitizer_name STREQUAL "address") 36 set(CMAKE_REQUIRED_FLAGS "/fsanitize=${sanitizer_name}") 37 else() 38 continue() 39 endif() 40 endif() 41 if(sanitizer_name STREQUAL "address") 42 if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL 43 "Clang") 44 list(APPEND CMAKE_REQUIRED_FLAGS "-shared-libasan") 45 endif() 46 endif() 47 if(sanitizer_name STREQUAL "undefined" AND UBSAN_FLAGS) 48 list(APPEND CMAKE_REQUIRED_FLAGS "${UBSAN_FLAGS}") 49 endif() 50 if(sanitizer_name STREQUAL "memory") 51 list(APPEND CMAKE_REQUIRED_FLAGS "-fsanitize-memory-track-origins=2") 52 endif() 53 54 set(CMAKE_REQUIRED_QUIET ON) 55 set(_run_res 0) 56 include(CheckCSourceRuns) 57 include(CheckCXXSourceRuns) 58 foreach(lang IN LISTS languages) 59 if(lang STREQUAL C) 60 check_c_source_runs("${_source_code}" 61 __${lang}_${sanitizer_name}_res) 62 if(__${lang}_${sanitizer_name}_res) 63 set(_run_res 1) 64 endif() 65 endif() 66 if(lang STREQUAL CXX) 67 check_cxx_source_runs("${_source_code}" 68 __${lang}_${sanitizer_name}_res) 69 if(__${lang}_${sanitizer_name}_res) 70 set(_run_res 1) 71 endif() 72 endif() 73 endforeach() 74 if(_run_res) 75 add_library(Sanitizer::${sanitizer_name} INTERFACE IMPORTED GLOBAL) 76 target_compile_options( 77 Sanitizer::${sanitizer_name} 78 INTERFACE 79 $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>>:${CMAKE_REQUIRED_FLAGS}> 80 $<$<AND:$<COMPILE_LANGUAGE:C>,$<BOOL:$__C_${sanitizer_name}_res>>:${CMAKE_REQUIRED_FLAGS}> 81 ) 82 if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND NOT CMAKE_C_COMPILER_ID 83 STREQUAL "MSVC") 84 target_link_options( 85 Sanitizer::${sanitizer_name} 86 INTERFACE 87 $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>>:${CMAKE_REQUIRED_FLAGS}> 88 $<$<AND:$<COMPILE_LANGUAGE:C>,$<BOOL:$__C_${sanitizer_name}_res>>:${CMAKE_REQUIRED_FLAGS}> 89 ) 90 else() 91 target_link_options( 92 Sanitizer::${sanitizer_name} 93 INTERFACE 94 $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>>:/INCREMENTAL:NO> 95 $<$<AND:$<COMPILE_LANGUAGE:C>,$<BOOL:$__C_${sanitizer_name}_res>>:/INCREMENTAL:NO> 96 ) 97 endif() 98 99 if(sanitizer_name STREQUAL "address") 100 target_compile_definitions( 101 Sanitizer::${sanitizer_name} 102 INTERFACE 103 $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>>:_GLIBCXX_SANITIZE_VECTOR> 104 $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>>:_GLIBCXX_SANITIZE_STD_ALLOCATOR> 105 ) 106 target_link_options( 107 Sanitizer::${sanitizer_name} 108 INTERFACE 109 $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>,$<CXX_COMPILER_ID:GNU>>:-lasan> 110 $<$<AND:$<COMPILE_LANGUAGE:C>,$<BOOL:$__C_${sanitizer_name}_res>,$<C_COMPILER_ID:GNU>>:-lasan> 111 ) 112 endif() 113 if(sanitizer_name STREQUAL "undefined") 114 target_link_options( 115 Sanitizer::${sanitizer_name} 116 INTERFACE 117 $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<BOOL:$__CXX_${sanitizer_name}_res>,$<CXX_COMPILER_ID:GNU>>:-lubsan> 118 $<$<AND:$<COMPILE_LANGUAGE:C>,$<BOOL:$__C_${sanitizer_name}_res>,$<C_COMPILER_ID:GNU>>:-lubsan> 119 ) 120 endif() 121 endif() 122endforeach() 123 124cmake_pop_check_state() 125