Sanitizers have been available for a while with the Clang compiler and were later also introduced into the GCC toolset. They were designed for use with C and C++ programs, but recent versions of Fortran will understand the same flags and produce correctly instrumented libraries and executables. This recipe will however focus on a C++ example.
- As usual, we first declare a C++11 project:
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-07 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
- We declare a list, CXX_BASIC_FLAGS, containing the compiler flags to be always used when building the project, -g3 and -O1:
list(APPEND CXX_BASIC_FLAGS "-g3" "-O1")
- We include the CMake module CheckCXXCompilerFlag.cmake. A similar module is available also for C (CheckCCompilerFlag.cmake) and Fortran (CheckFortranCompilerFlag.cmake, since CMake 3.3):
include(CheckCXXCompilerFlag)
- We declare an ASAN_FLAGS variable, which holds the flags needed to activate the address sanitizer, and set the CMAKE_REQUIRED_FLAGS variable, used internally by the check_cxx_compiler_flag function:
set(ASAN_FLAGS "-fsanitize=address -fno-omit-frame-pointer")
set(CMAKE_REQUIRED_FLAGS ${ASAN_FLAGS})
- We call check_cxx_compiler_flag to ensure that the compiler understands the flags in the ASAN_FLAGS variable. After calling the function, we unset CMAKE_REQUIRED_FLAGS:
check_cxx_compiler_flag(${ASAN_FLAGS} asan_works)
unset(CMAKE_REQUIRED_FLAGS)
- If the compiler understands the options, we transform the variable into a list by replacing the spaces with semicolons:
if(asan_works)
string(REPLACE " " ";" _asan_flags ${ASAN_FLAGS})
- We add an executable target for our code sample with the address sanitizer:
add_executable(asan-example asan-example.cpp)
- We set the compiler flags for the executable to contain the basic and address sanitizer flags:
target_compile_options(asan-example
PUBLIC
${CXX_BASIC_FLAGS}
${_asan_flags}
)
- Finally, we add the address sanitizer flags also to the set of flags used by the linker. This closes the if(asan_works) block:
target_link_libraries(asan-example PUBLIC ${_asan_flags})
endif()
The full recipe source code also shows how to compile and link sample executables for the thread, memory, and undefined behavior sanitizers. These are not discussed in detail here, since we use the same pattern for the compiler flag checking.
A custom CMake module for finding support for sanitizers on your system is available on GitHub: https://github.com/arsenm/sanitizers-cmake.