105

I've added AddressSanitizer flag as follow:

set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") 

Everything builds and runs fine when using Unix Makefiles.

The problem comes when generating the Xcode project, it just doesn't want to link because it cannot find the ASan library.

I already found two solutions, but decided not to use them because they cannot be automated using just CMake:

  1. Adding -Wl,-undefined,dynamic_lookup to the linked flags, so it skips linking to dynamic libraries.
  2. Link with libclang_rt.asan_osx_dynamic.dylib directly.

So what's the problem with these two solutions?

  • When using solution #1, I have to manually open the target scheme in Xcode and add DYLD_INSERT_LIBRARIES environment variable pointing to libclang_rt.asan_osx_dynamic.dylib.
  • When using solution #2, the path for the ASan library varies between computers.

Additionally as another solution, I tried enabling Address Sanitizer flag from the Xcode target scheme but interestingly it didn't detect the issues I added, so I didn't list this as a solution because it failed my test.

Any help will be much appreciated.

2
  • 4
    maybe check this out: github.com/arsenm/sanitizers-cmake Commented Jun 2, 2017 at 5:03
  • 1
    If you know of an Xcode project setting that turns on what you want, you can set it from CMake by populating CMAKE_XCODE_ATTRIBUTE_... variables or using the per-target properties XCODE_ATTRIBUTE_.... Commented Jun 3, 2017 at 2:40

7 Answers 7

119

The idea of this solution is to pass -fsanitize=address to the compiler and linker flags.

If you would like to enable this for all your targets at the same time, you can use add_compile_options and add_link_options. This makes sense if you have multiple, potentially a large of, targets.

add_compile_options(-fsanitize=address) add_link_options(-fsanitize=address) 

Alternatively, you can also use target_compile_options and target_link_options to set these for a particular target. This might make more sense if you do not want this to apply to all the targets.

target_compile_options(asan-target PRIVATE -fsanitize=address) target_link_options(asan-target PRIVATE -fsanitize=address) 
Sign up to request clarification or add additional context in comments.

4 Comments

Just tried this it builds but no errors detected... When I build the same code using the line g++ test_with_leak_main.cpp -fsanitize-address -g -std=c++20 -lpthread -static-libasn it reports the memory leak.
Keep in mind ASAN needs to be compiled/linked with Clang and not ld.
I used the first form but had both as $<$<CONFIG:Debug>:-fsanitize-address> so it will only be enabled for debug builds.
When using the commands for a particular target (a library that gets linked against from other targets), I had to use PUBLIC instead of PRIVATE, or I'd get linker errors.
47

You need to provide the flag(s) to the linker too. I'm doing it like this:

set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") 

7 Comments

Modern CMake: string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-omit...")
@Timmmm Fiddling with CMAKE_CXX_FLAGS directly is not a modern CMake whatsoever. Use of check_cxx_compiler_flag would be closest.
@Timmmm Well spotted. Thank you. I made copy & paste mistake. I meant target_compile_options instead, of course.
Ah yes that is indeed cleaner, however in this case it requires you to apply it to every target, which is rather tedious.
@Timmmm: you can use add_compile/link_options to apply it to every targets. But this answer is the wrong way to do it these days. Just added the correct with cmake these days. Please find the answer below: stackoverflow.com/a/70272150/2682142
|
30

I propose create your own Asan profile.

get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(isMultiConfig) if(NOT "Asan" IN_LIST CMAKE_CONFIGURATION_TYPES) list(APPEND CMAKE_CONFIGURATION_TYPES Asan) endif() else() set(allowedBuildTypes Asan Debug Release RelWithDebInfo MinSizeRel) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${allowedBuildTypes}") if(CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE IN_LIST allowedBuildTypes) message(FATAL_ERROR "Invalid build type: ${CMAKE_BUILD_TYPE}") endif() endif() set(CMAKE_C_FLAGS_ASAN "${CMAKE_C_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer" CACHE STRING "Flags used by the C compiler for Asan build type or configuration." FORCE) set(CMAKE_CXX_FLAGS_ASAN "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer" CACHE STRING "Flags used by the C++ compiler for Asan build type or configuration." FORCE) set(CMAKE_EXE_LINKER_FLAGS_ASAN "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fsanitize=address" CACHE STRING "Linker flags to be used to create executables for Asan build type." FORCE) set(CMAKE_SHARED_LINKER_FLAGS_ASAN "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=address" CACHE STRING "Linker lags to be used to create shared libraries for Asan build type." FORCE) 

Notes:

  1. AddressSanitizer (ASan) for Windows with MSVC is under experimental stage thus I didn't provided the MSVC way here.

  2. CMAKE_BUILD_TYPE isn't used by multi-configuration generators (Xcode, Visual Studio, etc), thus I provided an example to check this first.

  3. The default value for CMAKE_BUILD_TYPE is an empty string. And user can set CMAKE_BUILD_TYPE to any value at the cmake command line. Therefore, we check both cases, and make sure that we are dealing with a known build type (if provided).

  4. There is also CMAKE_MODULE_LINKER_FLAGS you may want to configure.

Usage:

$ cmake \ -DCMAKE_BUILD_TYPE=Asan \ ... ... 

3 Comments

While this seems a bit complex compared some other answers, it does seem to be the best way to do it. Did you get this info from the book Professional CMake, by chance?
Yes, I adopted this from the book.
Anecdotally, this worked for me with cmake version 3.16.3 (and cmake_minimum_required(VERSION 3.9))
14

cmake 3.13
introduce configuration for xcode schema

in CMake

cmake_minimum_required(VERSION 3.13) set(CMAKE_XCODE_GENERATE_SCHEME ON) set(CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER ON) set(CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN ON) 

When Build

xcodebuild -enableAddressSanitizer YES 

Comments

5

First ensure with debug info, such as setting CMAKE_BUILD_TYPE to Debug passing -g flag for GCC/Clang.

Then, if your target is an executable or an shared library, then you may set those cmake variables:

  • CMAKE_EXE_LINKER_FLAGS
  • CMAKE_EXE_LINKER_FLAGS_DEBUG
  • CMAKE_SHARED_LINKER_FLAGS
  • CMAKE_SHARED_LINKER_FLAGS_DEBUG

i.e. When your target is an executable:

set(CMAKE_BUILD_TYPE "Debug") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") 

When your target is an shared library:

set(CMAKE_BUILD_TYPE "Debug") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") 

However, when your executable relies on an static library and you'd like to use asan to check your static library, then you have to set like this:

set(CMAKE_BUILD_TYPE "Debug") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") 

Comments

0

I made it work for Xcode without hardcoding -fsanitize=address. One may work normally in Xcode without sanitizers and when necessary enable them in Scheme settings without re-running CMake.

I copy asan libs to the following folder and that's it.

set (XCODE_DEVELOPER_TOOLCHAINS_ROOT "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain") # Here is detection for iOS/MacOS, but other platforms also can be added here like tvos, watchos, xros if (IOS) set (PLATFORM_SUFFIX "ios") else () set (PLATFORM_SUFFIX "osx") endif () file (GLOB_RECURSE _asan_libs "${XCODE_DEVELOPER_TOOLCHAINS_ROOT}/*/libclang_rt.*an_${PLATFORM_SUFFIX}*_dynamic.dylib") foreach (_asan_lib ${_asan_libs}) file (RELATIVE_PATH _asan_relative_to_toolchain "${XCODE_DEVELOPER_TOOLCHAINS_ROOT}/usr/" "${_asan_lib}") configure_file ("${_asan_lib}" "${CMAKE_BINARY_DIR}/../${_asan_relative_to_toolchain}" COPYONLY) endforeach () 

Also here I answered how to make it work with ccache: https://stackoverflow.com/a/77547119/5517503

Here is demo project https://github.com/Hsilgos/xcode-ccache-demo

Comments

-3

The simplest solution that I currently found is

cmake -DCMAKE_BUILD_TYPE=ASAN . 

I prefer this option since it expresses the intent (run sanitizers) rather than modifies a number of flags.

I do not know when this option was added. I also cannot find any documentation to it.

5 Comments

What version of CMake are you using? I can't find any meaningful reference to ASAN in the current CMake source code.
The provided link, @MartinGerhardy, says at the very top that it is outdated.
This seems to only work for projects that directly query build type or do something like this FindASan.cmake script
not working for my cmake 3.18.0 with cmake_minimum_required(VERSION 3.15)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.