1# detect-sanitizer.cmake -- Detect supported compiler sanitizer flags 2# Licensed under the Zlib license, see LICENSE.md for details 3 4macro(check_sanitizer_support known_checks supported_checks) 5 set(available_checks "") 6 7 # Build list of supported sanitizer flags by incrementally trying compilation with 8 # known sanitizer checks 9 10 foreach(check ${known_checks}) 11 if(available_checks STREQUAL "") 12 set(compile_checks "${check}") 13 else() 14 set(compile_checks "${available_checks},${check}") 15 endif() 16 17 set(CMAKE_REQUIRED_FLAGS "-fsanitize=${compile_checks}") 18 19 check_c_source_compiles("int main() { return 0; }" HAS_SANITIZER_${check} 20 FAIL_REGEX "not supported|unrecognized command|unknown option") 21 22 set(CMAKE_REQUIRED_FLAGS) 23 24 if(HAS_SANITIZER_${check}) 25 set(available_checks ${compile_checks}) 26 endif() 27 endforeach() 28 29 set(${supported_checks} ${available_checks}) 30endmacro() 31 32macro(add_address_sanitizer) 33 set(known_checks 34 address 35 pointer-compare 36 pointer-subtract 37 ) 38 39 check_sanitizer_support("${known_checks}" supported_checks) 40 if(NOT ${supported_checks} STREQUAL "") 41 message(STATUS "Address sanitizer is enabled: ${supported_checks}") 42 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=${supported_checks}") 43 else() 44 message(STATUS "Address sanitizer is not supported") 45 endif() 46 47 if(CMAKE_CROSSCOMPILING_EMULATOR) 48 # Only check for leak sanitizer if not cross-compiling due to qemu crash 49 message(WARNING "Leak sanitizer is not supported when cross compiling") 50 else() 51 # Leak sanitizer requires address sanitizer 52 check_sanitizer_support("leak" supported_checks) 53 if(NOT ${supported_checks} STREQUAL "") 54 message(STATUS "Leak sanitizer is enabled: ${supported_checks}") 55 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=${supported_checks}") 56 else() 57 message(STATUS "Leak sanitizer is not supported") 58 endif() 59 endif() 60endmacro() 61 62macro(add_memory_sanitizer) 63 check_sanitizer_support("memory" supported_checks) 64 if(NOT ${supported_checks} STREQUAL "") 65 message(STATUS "Memory sanitizer is enabled: ${supported_checks}") 66 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=${supported_checks}") 67 else() 68 message(STATUS "Memory sanitizer is not supported") 69 endif() 70endmacro() 71 72macro(add_undefined_sanitizer) 73 set(known_checks 74 array-bounds 75 bool 76 bounds 77 builtin 78 enum 79 float-cast-overflow 80 float-divide-by-zero 81 function 82 integer-divide-by-zero 83 local-bounds 84 null 85 nonnull-attribute 86 pointer-overflow 87 return 88 returns-nonnull-attribute 89 shift 90 shift-base 91 shift-exponent 92 signed-integer-overflow 93 undefined 94 unsigned-integer-overflow 95 unsigned-shift-base 96 vla-bound 97 vptr 98 ) 99 100 # Only check for alignment sanitizer flag if unaligned access is not supported 101 if(NOT UNALIGNED_OK) 102 list(APPEND known_checks alignment) 103 endif() 104 # Object size sanitizer has no effect at -O0 and produces compiler warning if enabled 105 if(NOT CMAKE_C_FLAGS MATCHES "-O0") 106 list(APPEND known_checks object-size) 107 endif() 108 109 check_sanitizer_support("${known_checks}" supported_checks) 110 111 if(NOT ${supported_checks} STREQUAL "") 112 message(STATUS "Undefined behavior sanitizer is enabled: ${supported_checks}") 113 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=${supported_checks}") 114 115 # Group sanitizer flag -fsanitize=undefined will automatically add alignment, even if 116 # it is not in our sanitize flag list, so we need to explicitly disable alignment sanitizing. 117 if(UNALIGNED_OK) 118 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize=alignment") 119 endif() 120 else() 121 message(STATUS "UNdefined behavior sanitizer is not supported") 122 endif() 123endmacro()