| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- # detect-sanitizer.cmake -- Detect supported compiler sanitizer flags
- # Licensed under the Zlib license, see LICENSE.md for details
- macro(add_common_sanitizer_flags)
- if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
- add_compile_options(-g3)
- endif()
- check_c_compiler_flag(-fno-omit-frame-pointer HAVE_NO_OMIT_FRAME_POINTER)
- if(HAVE_NO_OMIT_FRAME_POINTER)
- add_compile_options(-fno-omit-frame-pointer)
- add_link_options(-fno-omit-frame-pointer)
- endif()
- check_c_compiler_flag(-fno-optimize-sibling-calls HAVE_NO_OPTIMIZE_SIBLING_CALLS)
- if(HAVE_NO_OPTIMIZE_SIBLING_CALLS)
- add_compile_options(-fno-optimize-sibling-calls)
- add_link_options(-fno-optimize-sibling-calls)
- endif()
- endmacro()
- macro(check_sanitizer_support known_checks supported_checks)
- set(available_checks "")
- # Build list of supported sanitizer flags by incrementally trying compilation with
- # known sanitizer checks
- foreach(check ${known_checks})
- if(available_checks STREQUAL "")
- set(compile_checks "${check}")
- else()
- set(compile_checks "${available_checks},${check}")
- endif()
- set(CMAKE_REQUIRED_FLAGS -fsanitize=${compile_checks})
- check_c_source_compiles("int main() { return 0; }" HAVE_SANITIZER_${check}
- FAIL_REGEX "not supported|unrecognized command|unknown option")
- set(CMAKE_REQUIRED_FLAGS)
- if(HAVE_SANITIZER_${check})
- set(available_checks ${compile_checks})
- endif()
- endforeach()
- set(${supported_checks} ${available_checks})
- endmacro()
- macro(add_address_sanitizer)
- set(known_checks
- address
- pointer-compare
- pointer-subtract
- )
- check_sanitizer_support("${known_checks}" supported_checks)
- if(NOT ${supported_checks} STREQUAL "")
- message(STATUS "Address sanitizer is enabled: ${supported_checks}")
- add_compile_options(-fsanitize=${supported_checks})
- add_link_options(-fsanitize=${supported_checks})
- add_common_sanitizer_flags()
- else()
- message(STATUS "Address sanitizer is not supported")
- endif()
- if(CMAKE_CROSSCOMPILING_EMULATOR)
- # Only check for leak sanitizer if not cross-compiling due to qemu crash
- message(WARNING "Leak sanitizer is not supported when cross compiling")
- else()
- # Leak sanitizer requires address sanitizer
- check_sanitizer_support("leak" supported_checks)
- if(NOT ${supported_checks} STREQUAL "")
- message(STATUS "Leak sanitizer is enabled: ${supported_checks}")
- add_compile_options(-fsanitize=${supported_checks})
- add_link_options(-fsanitize=${supported_checks})
- add_common_sanitizer_flags()
- else()
- message(STATUS "Leak sanitizer is not supported")
- endif()
- endif()
- endmacro()
- macro(add_memory_sanitizer)
- check_sanitizer_support("memory" supported_checks)
- if(NOT ${supported_checks} STREQUAL "")
- message(STATUS "Memory sanitizer is enabled: ${supported_checks}")
- add_compile_options(-fsanitize=${supported_checks})
- add_link_options(-fsanitize=${supported_checks})
- add_common_sanitizer_flags()
- check_c_compiler_flag(-fsanitize-memory-track-origins HAVE_MEMORY_TRACK_ORIGINS)
- if(HAVE_MEMORY_TRACK_ORIGINS)
- add_compile_options(-fsanitize-memory-track-origins)
- add_link_options(-fsanitize-memory-track-origins)
- endif()
- else()
- message(STATUS "Memory sanitizer is not supported")
- endif()
- endmacro()
- macro(add_thread_sanitizer)
- check_sanitizer_support("thread" supported_checks)
- if(NOT ${supported_checks} STREQUAL "")
- message(STATUS "Thread sanitizer is enabled: ${supported_checks}")
- add_compile_options(-fsanitize=${supported_checks})
- add_link_options(-fsanitize=${supported_checks})
- add_common_sanitizer_flags()
- else()
- message(STATUS "Thread sanitizer is not supported")
- endif()
- endmacro()
- macro(add_undefined_sanitizer)
- set(known_checks
- array-bounds
- bool
- bounds
- builtin
- enum
- float-cast-overflow
- float-divide-by-zero
- function
- integer-divide-by-zero
- local-bounds
- null
- nonnull-attribute
- pointer-overflow
- return
- returns-nonnull-attribute
- shift
- shift-base
- shift-exponent
- signed-integer-overflow
- undefined
- unsigned-integer-overflow
- unsigned-shift-base
- vla-bound
- vptr
- )
- # Only check for alignment sanitizer flag if unaligned access is not supported
- if(NOT WITH_UNALIGNED)
- list(APPEND known_checks alignment)
- endif()
- # Object size sanitizer has no effect at -O0 and produces compiler warning if enabled
- if(NOT CMAKE_C_FLAGS MATCHES "-O0")
- list(APPEND known_checks object-size)
- endif()
- check_sanitizer_support("${known_checks}" supported_checks)
- if(NOT ${supported_checks} STREQUAL "")
- message(STATUS "Undefined behavior sanitizer is enabled: ${supported_checks}")
- add_compile_options(-fsanitize=${supported_checks})
- add_link_options(-fsanitize=${supported_checks})
- # Group sanitizer flag -fsanitize=undefined will automatically add alignment, even if
- # it is not in our sanitize flag list, so we need to explicitly disable alignment sanitizing.
- if(WITH_UNALIGNED)
- add_compile_options(-fno-sanitize=alignment)
- endif()
- add_common_sanitizer_flags()
- else()
- message(STATUS "Undefined behavior sanitizer is not supported")
- endif()
- endmacro()
|