Поддержка санитайзеров
В пользовательских сборках 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
.