Как правильно включить AddressSanitizer в CMake, который работает в Xcode

Я добавил флаг AddressSanitizer следующим образом:

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

Все строит и работает нормально при использовании Unix Makefiles,

Проблема возникает при создании проекта Xcode, он просто не хочет связываться, потому что не может найти библиотеку ASan.

Я уже нашел два решения, но решил не использовать их, потому что они не могут быть автоматизированы с помощью только CMake:

  1. Добавление -Wl,-undefined,dynamic_lookup на связанные флаги, поэтому он пропускает ссылки на динамические библиотеки.
  2. Связать с libclang_rt.asan_osx_dynamic.dylib непосредственно.

Так в чем же проблема с этими двумя решениями?

  • При использовании решения № 1, я должен вручную открыть целевую схему в XCode и добавить DYLD_INSERT_LIBRARIES переменная окружения, указывающая на libclang_rt.asan_osx_dynamic.dylib,
  • При использовании решения № 2 путь к библиотеке ASan варьируется между компьютерами.

Кроме того, в качестве другого решения я попытался включить флаг Address Sanitizer из целевой схемы XCode, но, что интересно, он не обнаружил добавленные мной проблемы, поэтому я не перечислил это как решение, потому что он не прошел мой тест.

Любая помощь будет высоко ценится.

7 ответов

Поскольку ответ с наибольшим количеством голосов - это неправильный способ сделать это в наши дни, и я не получил подходящего решения cmake для этого чтения этой темы, я подумал, что упомяну правильный способ во время написания этого, чтобы следующий читатель сделал не нужно тратить много времени на это. Надеюсь, поможет.

Идея этого решения состоит в том, чтобы пройти -fsanitize=addressк флагам компилятора и компоновщика.

Если вы хотите включить это для всех ваших целей одновременно, вы можете использовать add_compile_options и add_link_options. Это имеет смысл, если у вас есть несколько, потенциально большое количество целей.

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

Кроме того, вы также можете использовать target_compile_options и target_link_options , чтобы установить их для конкретной цели. Это может иметь больше смысла, если вы не хотите, чтобы это применялось ко всем целям.

      target_compile_options(asan-target PRIVATE -fsanitize=address)
target_link_options(asan-target PRIVATE -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")

Предлагаю создать свой Асан профиль.

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_SHARED_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)

Ноты:

  1. AddressSanitizer (ASan) для Windows с MSVC находится на экспериментальной стадии, поэтому я не приводил здесь способ MSVC.

  2. CMAKE_BUILD_TYPE не используется генераторами с несколькими конфигурациями (Xcode, Visual Studio и т. д.), поэтому я предоставил пример для первой проверки.

  3. Значение по умолчанию для CMAKE_BUILD_TYPEэто пустая строка. И пользователь может установить CMAKE_BUILD_TYPEна любое значение в командной строке cmake. Поэтому мы проверяем оба случая и убеждаемся, что имеем дело с известным типом сборки (если он предусмотрен).

  4. Есть также CMAKE_MODULE_LINKER_FLAGS вы можете захотеть настроить.

Применение:

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

cmake 3.13
представить конфигурацию для схемы xcode

в 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)

Когда строить

xcodebuild -enableAddressSanitizer YES

Сначала проверьте информацию об отладке, например настройку CMAKE_BUILD_TYPE к Debug.

Затем, установив одну из этих переменных, у меня это сработает:

  • CMAKE_EXE_LINKER_FLAGS
  • CMAKE_EXE_LINKER_FLAGS_DEBUG
  • CMAKE_SHARED_LINKER_FLAGS
  • CMAKE_SHARED_LINKER_FLAGS_DEBUG

Взять CMAKE_EXE_LINKER_FLAGS например:

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

Самое простое решение, которое я сейчас нашел, это

cmake -DCMAKE_BUILD_TYPE=ASAN .

Я предпочитаю эту опцию, так как она выражает намерение (запуск дезинфицирующих средств), а не изменяет ряд флагов.

Я не знаю, когда эта опция была добавлена. Я также не могу найти какую-либо документацию к нему.

Я обнаружил, что другие ответы не сработали, вам нужно установить переменные инициализации в файле цепочки инструментов:

set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address -fno-omit-frame-pointer")
Другие вопросы по тегам