MSAN(MemorySanitizer)で C++ コードをコンパイルするメモ
MSAN(MemorySanitizer)有効で C++ コードをコンパイルする場合, libc 以外のライブラリをすべてリコンパイルする必要がある(STL library 含む).
したがってまずは MSAN 有効で libc++ をビルドする.
MSAN 有効な libc++ のビルド
ただし情報はやや古い.
以下は Linux のみ + llvm 19.1.0(執筆時点での最新) を対象とする.
まず, llvm 19.1.0 の libc++ は clang-17 以上でないとコンパイルできないので注意.
libcxx 関連は llvm-project/runtimes を source dir に指定してビルドできる.
LLVM_ENABLE_RUNTIMES
でどのモジュールをビルドするか指定する.
libcxx が欲しい場合, どうも libcxxabi と libunwind も一緒にビルドしないといけないっぽい.
LLVM_USE_SANITIZER
には Memory
or MemoryWithOrigins
を指定する. MemoriWithOrigin だとどこで実際に原因が発生したかもレポートしてくれるので基本は MemoriWithOrigin がよいでしょう. ただし実行時メモリは Memory
より多く使う.
CMAKE_BUILD_TYPE はお好みで.
$ CXX=clang++-18 CC=clang-18 cmake \
-G Ninja -DCMAKE_INSTALL_PREFIX=${dist_dir} \
-B ${libcxx_build_dir} -S llvm-project/runtimes/ \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
-DLLVM_USE_SANITIZER=MemoryWithOrigins \
-DCMAKE_BUILD_TYPE=Release
C++ コードを MSAN 有効でビルド
あとは -fsanitize=memory
をつけ, msan 有効な libc++ を使うようにして C++ コードをビルドする.
-fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer
-fsanitize-memory-track-origins
をつけると, どこで原因が発生したかも報告してくれる.
メモリは消費するようになる.
include path は
-isystem ${dist_dir}/include -isystem ${dist_dir}/include/c++/v1 -nostdinc++
として, 既存の C++ include path は無効(-nostdinc++
), カスタムビルト libcxx は -isystem
で指定(そうしないと clang の warning level を上げていると reserved keyword エラーがでる)
リンクは -L ${LIBCXX_MSAN_DIR}/lib -lc++ -lc++abi -lunwind
だが, これだとシステムに libcxx がすでにインストールされている場合そちらとリンクしてしまう.
実行時に LD_LIBRARY_PATH で調整してもよいですが, コンパイル時(リンク時)に固定したいときは
-Wl,-rpath,${LIBCXX_MSAN_DIR}/lib -lc++ -lc++abi -lunwind
と -Wl,rpath,
を使う.
llvmlibc?
llvmlibc(C lib)もせっかくなので MSAN 有効でビルドしたいところであるが, llvmlibc は一部に C++ コード(libc++ 由来)を使っているため, MSAN 有効な libc++ でコンパイルする必要がありめんどい.
C lib のいくつかは MSAN で instrumented されて suppress されているようなので, 特段セキュアな検証が必要無い限りは libc まわりは既存のもの(glibc)でよいでしょう.
Discussion