Sanitizer support

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

Address Sanitizer: easy build

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

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

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

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

General considerations

Использование санитайзеров 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, чтобы вам не нужно было помнить их каждый раз).

Address Sanitizer (ASAN)

Для обнаружения или отладки ошибок памяти вы можете использовать Clang's address sanitizer (ASAN). Компилируя с 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, но это следует удалить в будущем.

Example setup

Step 1: Install toolchain

Проверьте рабочее дерево 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

Step 2: Build Julia with ASAN

Проверьте рабочее дерево Git (или создайте каталог сборки вне дерева) в $BUILD_WORKTREE и создайте файл конфигурации $BUILD_WORKTREE/Make.user с

TOOLCHAIN=$(TOOLCHAIN_WORKTREE)/usr/tools

# use our new toolchain
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

# make the GC use regular malloc/frees, which are hooked by ASAN
override WITH_GC_DEBUG_ENV=1

# default to a debug build for better line number reporting
override JULIA_BUILD_MODE=debug

# make ASAN consume less memory
export ASAN_OPTIONS=detect_leaks=0:fast_unwind_on_malloc=0:allow_user_segv_handler=1:malloc_context_size=2

JULIA_PRECOMPILE=1

# tell libblastrampoline to not use RTLD_DEEPBIND
export LBT_USE_RTLD_DEEPBIND=0

Запуск:

cd $BUILD_WORKTREE
make debug

собрать julia-debug с ASAN.

Memory Sanitizer (MSAN)

For detecting use of uninitialized memory, you can use Clang's memory sanitizer (MSAN) by compiling with SANITIZE_MEMORY=1.

Thread Sanitizer (TSAN)

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