* Added a new module FindSanitizers with new function add_sanitizers to combine all sanitizers in one function instead of adding each one by one. * Code of FindASan.cmake was outdourced into helper functions, so that the code may be used by other sanitizer modules, too. * AddressSanitizer will be used with -O1 now to get a better performance.master
| @@ -1,6 +1,8 @@ | |||||
| # The MIT License (MIT) | # The MIT License (MIT) | ||||
| # | # | ||||
| # Copyright (c) 2013 Matthew Arsenault | |||||
| # Copyright (c) | |||||
| # 2013 Matthew Arsenault | |||||
| # 2015-2016 RWTH Aachen University, Federal Republic of Germany | |||||
| # | # | ||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | # Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| # of this software and associated documentation files (the "Software"), to deal | # of this software and associated documentation files (the "Software"), to deal | ||||
| @@ -20,108 +22,25 @@ | |||||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| # SOFTWARE. | # SOFTWARE. | ||||
| # This module tests if address sanitizer is supported by the compiler. The | |||||
| # necessary flags for compiler and linker will be stored in variables. ASan can | |||||
| # be enabled for all targets with CMake build type "ASan", individual targets | |||||
| # can enable ASan with the saitize_address() function. | |||||
| option(SANITIZE_ADDRESS "Enable AddressSanitizer for sanitized targets." Off) | |||||
| option(SANITIZE_ADDRESS "Selects wheter Address Sanitizer will be enabled for | |||||
| individual targets" Off) | |||||
| set(ASAN_FLAG_CANDIDATES | |||||
| set(FLAG_CANDIDATES | |||||
| # Clang 3.2+ use this version | # Clang 3.2+ use this version | ||||
| "-g -O0 -fsanitize=address" | |||||
| "-g -O1 -fsanitize=address" | |||||
| # Older deprecated flag for ASan | # Older deprecated flag for ASan | ||||
| "-g -O0 -faddress-sanitizer" | |||||
| "-g -O1 -faddress-sanitizer" | |||||
| ) | ) | ||||
| set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) | |||||
| set(CMAKE_REQUIRED_QUIET ${ASan_FIND_QUIETLY}) | |||||
| get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) | |||||
| foreach (LANG ${ENABLED_LANGUAGES}) | |||||
| # Sanitizer flags are not dependend on language, but the used compiler. So | |||||
| # instead of searching flags foreach language, search flags foreach compiler | |||||
| # used. | |||||
| set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) | |||||
| if (NOT ASAN_${COMPILER}_FLAGS) | |||||
| foreach (FLAG ${ASAN_FLAG_CANDIDATES}) | |||||
| if(NOT CMAKE_REQUIRED_QUIET) | |||||
| message(STATUS | |||||
| "Try ${COMPILER} AddressSanitizer flag = [${FLAG}]") | |||||
| endif() | |||||
| set(CMAKE_REQUIRED_FLAGS "${FLAG}") | |||||
| unset(ASAN_FLAG_DETECTED CACHE) | |||||
| if (${LANG} STREQUAL "C") | |||||
| include(CheckCCompilerFlag) | |||||
| check_c_compiler_flag("${FLAG}" ASAN_FLAG_DETECTED) | |||||
| elseif (${LANG} STREQUAL "CXX") | |||||
| include(CheckCXXCompilerFlag) | |||||
| check_cxx_compiler_flag("${FLAG}" ASAN_FLAG_DETECTED) | |||||
| elseif (${LANG} STREQUAL "Fortran") | |||||
| # CheckFortranCompilerFlag was introduced in CMake 3.x. To be | |||||
| # compatible with older Cmake versions, we will check if this | |||||
| # module is present before we use it. Otherwise we will define | |||||
| # Fortran coverage support as not available. | |||||
| include(CheckFortranCompilerFlag OPTIONAL | |||||
| RESULT_VARIABLE INCLUDED) | |||||
| if (INCLUDED) | |||||
| check_fortran_compiler_flag("${FLAG}" ASAN_FLAG_DETECTED) | |||||
| elseif (NOT CMAKE_REQUIRED_QUIET) | |||||
| message("-- Performing Test ASAN_FLAG_DETECTED") | |||||
| message("-- Performing Test ASAN_FLAG_DETECTED - Failed " | |||||
| "(Check not supported)") | |||||
| endif () | |||||
| endif() | |||||
| if (ASAN_FLAG_DETECTED) | |||||
| set(ASAN_${COMPILER}_FLAGS "${FLAG}" | |||||
| CACHE STRING "${COMPILER} flags for AddressSanitizer.") | |||||
| mark_as_advanced(ASAN_${COMPILER}_FLAGS) | |||||
| break() | |||||
| endif () | |||||
| endforeach () | |||||
| endif () | |||||
| endforeach () | |||||
| set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE}) | |||||
| include(sanitize-helpers) | include(sanitize-helpers) | ||||
| sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "AddressSanitizer" "ASan") | |||||
| function (sanitize_address TARGET) | |||||
| function (add_sanitize_address TARGET) | |||||
| if (NOT SANITIZE_ADDRESS) | if (NOT SANITIZE_ADDRESS) | ||||
| return() | return() | ||||
| endif () | endif () | ||||
| # Get list of compilers used by target and check, if target can be checked | |||||
| # by sanitizer. | |||||
| sanitizer_target_compilers(${TARGET} TARGET_COMPILER) | |||||
| list(LENGTH TARGET_COMPILER NUM_COMPILERS) | |||||
| if (NUM_COMPILERS GREATER 1) | |||||
| message(AUTHOR_WARNING "AddressSanitizer disabled for target ${TARGET} " | |||||
| "because it will be compiled by different compilers.") | |||||
| return() | |||||
| elseif ((NUM_COMPILERS EQUAL 0) OR | |||||
| (NOT DEFINED "ASAN_${TARGET_COMPILER}_FLAGS")) | |||||
| message(AUTHOR_WARNING "AddressSanitizer disabled for target ${TARGET} " | |||||
| "because there is no sanitizer available for target sources.") | |||||
| return() | |||||
| endif() | |||||
| # Set compile- and link-flags for target. | |||||
| set_property(TARGET ${TARGET} APPEND_STRING | |||||
| PROPERTY COMPILE_FLAGS " ${ASAN_${TARGET_COMPILER}_FLAGS}") | |||||
| set_property(TARGET ${TARGET} APPEND_STRING | |||||
| PROPERTY LINK_FLAGS " ${ASAN_${TARGET_COMPILER}_FLAGS}") | |||||
| saitizer_add_flags(${TARGET} "AddressSanitizer" "ASan") | |||||
| endfunction () | endfunction () | ||||
| @@ -0,0 +1,50 @@ | |||||
| # The MIT License (MIT) | |||||
| # | |||||
| # Copyright (c) | |||||
| # 2013 Matthew Arsenault | |||||
| # 2015-2016 RWTH Aachen University, Federal Republic of Germany | |||||
| # | |||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
| # of this software and associated documentation files (the "Software"), to deal | |||||
| # in the Software without restriction, including without limitation the rights | |||||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
| # copies of the Software, and to permit persons to whom the Software is | |||||
| # furnished to do so, subject to the following conditions: | |||||
| # | |||||
| # The above copyright notice and this permission notice shall be included in all | |||||
| # copies or substantial portions of the Software. | |||||
| # | |||||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
| # SOFTWARE. | |||||
| # The following options will enable the desired sanitizers. | |||||
| option(SANITIZE "Enable all available sanitizers for sanitized targets." OFF) | |||||
| # If option SANITIZE is enabled, enable all available sanitizers. | |||||
| if (SANITIZE) | |||||
| set(SANITIZE_ADDRESS ON CACHE BOOL | |||||
| "Enable AddressSanitizer for sanitized targets." FORCE) | |||||
| endif (SANITIZE) | |||||
| set(FIND_QUIETLY_FLAG "") | |||||
| if (DEFINED Sanitizers_FIND_QUIETLY) | |||||
| set(FIND_QUIETLY_FLAG "QUIET") | |||||
| endif () | |||||
| find_package(ASan ${FIND_QUIETLY_FLAG}) | |||||
| function(add_sanitizers TARGET) | |||||
| add_sanitize_address(${TARGET}) | |||||
| endfunction(add_sanitizers) | |||||
| @@ -64,3 +64,86 @@ function (sanitizer_target_compilers TARGET RETURN_VAR) | |||||
| list(REMOVE_DUPLICATES BUFFER) | list(REMOVE_DUPLICATES BUFFER) | ||||
| set(${RETURN_VAR} "${BUFFER}" PARENT_SCOPE) | set(${RETURN_VAR} "${BUFFER}" PARENT_SCOPE) | ||||
| endfunction () | endfunction () | ||||
| # Helper function to test compiler flags. | |||||
| function (sanitizer_check_compiler_flags FLAG_CANDIDATES NAME PREFIX) | |||||
| set(CMAKE_REQUIRED_QUIET ${${PREFIX}_FIND_QUIETLY}) | |||||
| get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) | |||||
| foreach (LANG ${ENABLED_LANGUAGES}) | |||||
| # Sanitizer flags are not dependend on language, but the used compiler. | |||||
| # So instead of searching flags foreach language, search flags foreach | |||||
| # compiler used. | |||||
| set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) | |||||
| if (NOT ${PREFIX}_${COMPILER}_FLAGS) | |||||
| foreach (FLAG ${FLAG_CANDIDATES}) | |||||
| if(NOT CMAKE_REQUIRED_QUIET) | |||||
| message(STATUS "Try ${COMPILER} ${NAME} flag = [${FLAG}]") | |||||
| endif() | |||||
| set(CMAKE_REQUIRED_FLAGS "${FLAG}") | |||||
| unset(${PREFIX}_FLAG_DETECTED CACHE) | |||||
| if (${LANG} STREQUAL "C") | |||||
| include(CheckCCompilerFlag) | |||||
| check_c_compiler_flag("${FLAG}" ${PREFIX}_FLAG_DETECTED) | |||||
| elseif (${LANG} STREQUAL "CXX") | |||||
| include(CheckCXXCompilerFlag) | |||||
| check_cxx_compiler_flag("${FLAG}" ${PREFIX}_FLAG_DETECTED) | |||||
| elseif (${LANG} STREQUAL "Fortran") | |||||
| # CheckFortranCompilerFlag was introduced in CMake 3.x. To | |||||
| # be compatible with older Cmake versions, we will check if | |||||
| # this module is present before we use it. Otherwise we will | |||||
| # define Fortran coverage support as not available. | |||||
| include(CheckFortranCompilerFlag OPTIONAL | |||||
| RESULT_VARIABLE INCLUDED) | |||||
| if (INCLUDED) | |||||
| check_fortran_compiler_flag("${FLAG}" | |||||
| ASAN_FLAG_DETECTED) | |||||
| elseif (NOT CMAKE_REQUIRED_QUIET) | |||||
| message(STATUS | |||||
| "Performing Test ${PREFIX}_FLAG_DETECTED") | |||||
| message(STATUS "Performing Test ${PREFIX}_FLAG_DETECTED" | |||||
| " - Failed (Check not supported)") | |||||
| endif () | |||||
| endif() | |||||
| if (${PREFIX}_FLAG_DETECTED) | |||||
| set(${PREFIX}_${COMPILER}_FLAGS "${FLAG}" CACHE STRING | |||||
| "${NAME} flags for ${COMPILER} compiler.") | |||||
| mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) | |||||
| break() | |||||
| endif () | |||||
| endforeach () | |||||
| endif () | |||||
| endforeach () | |||||
| endfunction () | |||||
| # Helper to assign sanitizer flags for TARGET. | |||||
| function (saitizer_add_flags TARGET NAME PREFIX) | |||||
| # Get list of compilers used by target and check, if target can be checked | |||||
| # by sanitizer. | |||||
| sanitizer_target_compilers(${TARGET} TARGET_COMPILER) | |||||
| list(LENGTH TARGET_COMPILER NUM_COMPILERS) | |||||
| if (NUM_COMPILERS GREATER 1) | |||||
| message(AUTHOR_WARNING "${NAME} disabled for target ${TARGET} because " | |||||
| "it will be compiled by different compilers.") | |||||
| return() | |||||
| elseif ((NUM_COMPILERS EQUAL 0) OR | |||||
| (NOT DEFINED "${PREFIX}_${TARGET_COMPILER}_FLAGS")) | |||||
| message(WARNING "${NAME} disabled for target ${TARGET} because there is" | |||||
| " no sanitizer available for target sources.") | |||||
| return() | |||||
| endif() | |||||
| # Set compile- and link-flags for target. | |||||
| set_property(TARGET ${TARGET} APPEND_STRING | |||||
| PROPERTY COMPILE_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") | |||||
| set_property(TARGET ${TARGET} APPEND_STRING | |||||
| PROPERTY LINK_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") | |||||
| endfunction () | |||||
| @@ -31,6 +31,7 @@ function(add_testcase TESTNAME SOURCEFILES) | |||||
| # add a new executable | # add a new executable | ||||
| add_executable(${TESTNAME} ${ARGV}) | add_executable(${TESTNAME} ${ARGV}) | ||||
| add_sanitizers(${TESTNAME}) | |||||
| # add a testcase for executable | # add a testcase for executable | ||||
| add_test(${TESTNAME} ${TESTNAME}) | add_test(${TESTNAME} ${TESTNAME}) | ||||
| @@ -41,10 +42,7 @@ endfunction(add_testcase) | |||||
| # | # | ||||
| # search for sanitizers | # search for sanitizers | ||||
| # | # | ||||
| find_package(ASan) | |||||
| find_package(MSan) | |||||
| find_package(TSan) | |||||
| find_package(UBSan) | |||||
| find_package(Sanitizers) | |||||