Документация Engee

Поддержка санитайзеров

В пользовательских сборках Julia можно использовать санитайзеры, чтобы легче выявлять определенные виды ошибок во внутреннем коде Julia на C/C++.

Санитайзер адресов: легкая сборка

На основе извлеченного исходного кода Julia можно создать версию, поддерживающую очищение адресов в Julia и LLVM:

$ mkdir /tmp/julia
$ contrib/asan/build.sh /tmp/julia/

Здесь выбран каталог сборки /tmp/julia, но это может быть любой каталог на ваш выбор. После сборки запустите рабочую нагрузку, которую нужно протестировать с помощью /tmp/julia/julia. Обо всех ошибках памяти будет сообщаться.

Более подробные сведения, в том числе о настройке, см. в документации ниже.

Общие положения

Очевидно, что для применения санитайзеров Clang потребуется использовать Clang (USECLANG=1), но есть и еще один момент: большинству санитайзеров требуется библиотека времени выполнения, предоставляемая главным компилятором, однако инструментированный код, генерируемый JIT Julia, полагается на функциональные возможности этой библиотеки. Из этого следует, что версия LLVM главного компилятора должна соответствовать версии библиотеки LLVM, используемой в Julia.

Для решения этой проблемы можно просто создать специальную папку сборки для предоставления соответствующего набора инструментальных средств, выполнив сборку с параметром BUILD_LLVM_CLANG=1. Затем на этот набор инструментальных средств можно ссылаться из другой папки сборки, указывая параметр USECLANG=1 при переопределении переменных CC и CXX.

При обнаружении общей папки, открытой с помощью RTLD_DEEPBIND, санитайзеры выдают ошибку (см. google/sanitizers#611). Так как библиотека libblastrampoline по умолчанию использует RTLD_DEEPBIND, при использовании санитайзера необходимо задать переменную среды LBT_USE_RTLD_DEEPBIND=0.

Чтобы использовать один из санитайзеров, задайте SANITIZE=1, а затем установите соответствующий флаг для нужного санитайзера.

В macOS могут потребоваться дополнительные флаги. В целом это может выглядеть так с добавлением одного флага SANITIZE_* или нескольких, перечисленных ниже.

make -C deps USE_BINARYBUILDER_LLVM=0 LLVM_VER=svn stage-llvm

make -C src SANITIZE=1 USECLANG=1 \
    CC=~+/deps/scratch/llvm-svn/build_Release/bin/clang \
    CXX=~+/deps/scratch/llvm-svn/build_Release/bin/clang++ \
    CPPFLAGS="-isysroot $(xcode-select -p)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" \
    CXXFLAGS="-isystem $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1"

Этот код можно также поместить в файл Make.user, чтобы не вспоминать его каждый раз.

Санитайзер адресов (ASAN)

Для обнаружения или отладки ошибок памяти можно использовать санитайзер адресов (ASAN) Clang. Выполняя компиляцию с параметром SANITIZE_ADDRESS=1, вы включаете ASAN для компилятора Julia и генерируемого им кода. Кроме того, можно указать LLVM_SANITIZE=1, чтобы также санировать библиотеку LLVM. Имейте в виду, что эти параметры приводят к высоким затратам вычислительных ресурсов и ресурсов памяти. Например, при использовании ASAN для Julia и LLVM testall1 выполняется в 8—​10 раз дольше и потребляет в 20 раз больше памяти (с помощью описанных ниже параметров эти цифры можно уменьшить в 3 и 4 раза соответственно).

По умолчанию Julia устанавливает флаг ASAN allow_user_segv_handler=1, который необходим для корректной доставки сигналов. С помощью флага среды ASAN_OPTIONS можно задать и другие параметры; в этом случае придется повторять указанный ранее параметр по умолчанию. Например, указав fast_unwind_on_malloc=0 и malloc_context_size=2, можно сократить потребление памяти за счет точности обратной трассировки. В настоящее время Julia также задает параметр detect_leaks=0, однако в будущем это будет изменено.

Пример настройки

Шаг 1. Установка набора инструментальных средств

Извлеките рабочее дерево Git (или создайте каталог сборки вне дерева) в $TOOLCHAIN_WORKTREE и создайте файл конфигурации $TOOLCHAIN_WORKTREE/Make.user со следующим содержимым:

USE_BINARYBUILDER_LLVM=1
BUILD_LLVM_CLANG=1

Выполните следующие команды:

cd $TOOLCHAIN_WORKTREE
make -C deps install-llvm install-clang install-llvm-tools

чтобы установить двоичные файлы набора инструментальных средств в $TOOLCHAIN_WORKTREE/usr/tools.

Шаг 2. Сборка Julia с ASAN

Извлеките рабочее дерево Git (или создайте каталог сборки вне дерева) в $BUILD_WORKTREE и создайте файл конфигурации $BUILD_WORKTREE/Make.user со следующим содержимым:

TOOLCHAIN=$(TOOLCHAIN_WORKTREE)/usr/tools

# используем новый набор инструментальных средств
USECLANG=1
override CC=$(TOOLCHAIN)/clang
override CXX=$(TOOLCHAIN)/clang++
export ASAN_SYMBOLIZER_PATH=$(TOOLCHAIN)/llvm-symbolizer

USE_BINARYBUILDER_LLVM=1

override SANITIZE=1
override SANITIZE_ADDRESS=1

# предписываем сборщику мусора использовать обычные операции выделения и освобождения памяти, к которым привязан ASAN
override WITH_GC_DEBUG_ENV=1

# используем по умолчанию отладочную сборку для более точной информации о номерах строк
override JULIA_BUILD_MODE=debug

# сокращаем объем памяти, потребляемый ASAN
export ASAN_OPTIONS=detect_leaks=0:fast_unwind_on_malloc=0:allow_user_segv_handler=1:malloc_context_size=2

JULIA_PRECOMPILE=1

# предписываем libblastrampoline не использовать RTLD_DEEPBIND
export LBT_USE_RTLD_DEEPBIND=0

Выполните следующие команды:

cd $BUILD_WORKTREE
make debug

для сборки julia-debug с ASAN.

Санитайзер памяти (MSAN)

Для обнаружения использования неинициализированной памяти можно применять санитайзер памяти (MSAN) Clang, выполнив компиляцию с параметром SANITIZE_MEMORY=1.

Санитайзер потоков (TSAN)

Для отладки состязаний за данные и других проблем, связанных с потоками, можно использовать санитайзер потоков (TSAN) Clang, выполнив компиляцию с параметром SANITIZE_THREAD=1.