* 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) | |||
| # | |||
| # 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 | |||
| # 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 | |||
| # 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 | |||
| "-g -O0 -fsanitize=address" | |||
| "-g -O1 -fsanitize=address" | |||
| # 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) | |||
| sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "AddressSanitizer" "ASan") | |||
| function (sanitize_address TARGET) | |||
| function (add_sanitize_address TARGET) | |||
| if (NOT SANITIZE_ADDRESS) | |||
| return() | |||
| 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 () | |||
| @@ -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) | |||
| set(${RETURN_VAR} "${BUFFER}" PARENT_SCOPE) | |||
| 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_executable(${TESTNAME} ${ARGV}) | |||
| add_sanitizers(${TESTNAME}) | |||
| # add a testcase for executable | |||
| add_test(${TESTNAME} ${TESTNAME}) | |||
| @@ -41,10 +42,7 @@ endfunction(add_testcase) | |||
| # | |||
| # search for sanitizers | |||
| # | |||
| find_package(ASan) | |||
| find_package(MSan) | |||
| find_package(TSan) | |||
| find_package(UBSan) | |||
| find_package(Sanitizers) | |||