Sanitizer support

Sanitizers は、カスタムJuliaビルドで使用され、Juliaの内部C/C++コードにおける特定の種類のエラーを検出しやすくします。

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)。しかし、もう一つの注意点があります。ほとんどのサニタイザーは、ホストコンパイラによって提供されるランタイムライブラリを必要としますが、JuliaのJITによって生成されたインストゥルメンテッドコードは、そのライブラリの機能に依存しています。これは、ホストコンパイラのLLVMバージョンが、Julia内で使用されるLLVMライブラリのバージョンと一致する必要があることを意味します。

簡単な解決策は、BUILD_LLVM_CLANG=1を使用して、適切なツールチェーンを提供するための専用のビルドフォルダーを持つことです。次に、CCおよびCXX変数を上書きしながら、USECLANG=1を指定することで、別のビルドフォルダーからこのツールチェーンを参照できます。

サニタイザーは、RTLD_DEEPBINDを使用して開かれる共有ライブラリを検出するとエラーを出します(参照: google/sanitizers#611)。デフォルトでlibblastrampolineRTLD_DEEPBINDを使用するため、サニタイザーを使用する際には環境変数LBT_USE_RTLD_DEEPBIND=0を設定する必要があります。

サニタイザーの1つを使用するには、SANITIZE=1を設定し、次に使用したいサニタイザーの適切なフラグを指定します。

macOSでは、これが動作するために追加のフラグが必要な場合があります。全体として、以下のSANITIZE_*フラグの1つ以上を加えたもののように見えるかもしれません:

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の address sanitizer (ASAN) を使用できます。 SANITIZE_ADDRESS=1 でコンパイルすることで、Juliaコンパイラとその生成コードに対してASANを有効にします。さらに、 LLVM_SANITIZE=1 を指定することで、LLVMライブラリもサニタイズできます。これらのオプションは高いパフォーマンスとメモリコストを伴うことに注意してください。たとえば、JuliaとLLVMのASANを使用すると、 testall1 の実行時間が8〜10倍になり、メモリ使用量が20倍になります(これは、以下に説明するオプションを使用することで、それぞれ3倍と4倍に減らすことができます)。

デフォルトでは、Juliaは信号の配信が正しく機能するために必要なallow_user_segv_handler=1 ASANフラグを設定します。他のオプションを定義するには、ASAN_OPTIONS環境フラグを使用しますが、その場合は前述のデフォルトオプションを繰り返す必要があります。たとえば、fast_unwind_on_malloc=0malloc_context_size=2を指定することでメモリ使用量を削減できますが、バックトレースの精度が犠牲になります。現時点では、Juliaはdetect_leaks=0も設定していますが、これは将来的に削除されるべきです。

Example setup

Step 1: Install toolchain

$TOOLCHAIN_WORKTREE に Git ワークツリーをチェックアウトする(またはツリー外ビルドディレクトリを作成する)し、次の内容で設定ファイル $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

$BUILD_WORKTREE に Git ワークツリーをチェックアウトする(またはツリー外ビルドディレクトリを作成する)し、次の内容の設定ファイル $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)

未初期化メモリの使用を検出するには、Clangの memory sanitizer (MSAN) を使用し、SANITIZE_MEMORY=1 でコンパイルします。

Thread Sanitizer (TSAN)

データ競合やその他のスレッド関連の問題をデバッグするために、Clangの thread sanitizer (TSAN) を使用することができます。SANITIZE_THREAD=1 でコンパイルしてください。