ci: add MemorySanitizer CI job
Add build_msan_toolchain.sh to produce a tarball containing an MSan-instrumented libc++/libc++abi/libunwind toolchain, and add an msan CI job that downloads the tarball and runs the test suite under MSan. Also add USE_MSAN CMake option that disables conflicting sanitizers, switches to lld, and propagates -fsanitize=memory to the shared library and fuzz_driver targets.
This commit is contained in:
@@ -218,6 +218,87 @@ jobs:
|
||||
--link "https://minio.weaselab.dev/jenkins/conflict-set/${{ gitea.run_number }}/release-${{ matrix.arch }}/Test.xml.zst" \
|
||||
| tee -a "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
msan:
|
||||
runs-on: ubuntu-latest-amd64
|
||||
env:
|
||||
MSAN_VERSION: "21.1.8"
|
||||
MSAN_URL: "https://minio.weaselab.dev/public/x86_64/msan-toolchain-21.1.8.tar.zst"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: /var/cache/apt/archives
|
||||
key: apt-amd64-${{ hashFiles('.gitea/workflows/ci.yml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
. /etc/os-release
|
||||
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
|
||||
echo "deb http://apt.llvm.org/${VERSION_CODENAME}/ llvm-toolchain-${VERSION_CODENAME}-21 main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y \
|
||||
build-essential ccache clang-21 cmake libc6-dbg \
|
||||
llvm-21 lld-21 mold ninja-build python3 zstd
|
||||
for tool in clang clang++ llvm-ar llvm-nm llvm-ranlib llvm-objcopy llvm-cov llvm-symbolizer lld ld.lld; do
|
||||
sudo update-alternatives --install /usr/bin/${tool} ${tool} /usr/bin/${tool}-21 100
|
||||
done
|
||||
|
||||
- name: Download MSan toolchain
|
||||
run: |
|
||||
curl -Ls "${MSAN_URL}" -o /tmp/msan-toolchain.tar.zst
|
||||
sudo mkdir -p /opt/msan
|
||||
sudo tar --zstd -xf /tmp/msan-toolchain.tar.zst -C /opt/msan
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: .ccache
|
||||
key: ccache-msan-${{ gitea.sha }}
|
||||
restore-keys: |
|
||||
ccache-msan-
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
export CCACHE_DIR="$GITHUB_WORKSPACE/.ccache"
|
||||
rm -rf build
|
||||
cmake -S . -B build -G Ninja \
|
||||
-DCMAKE_C_COMPILER=clang \
|
||||
-DCMAKE_CXX_COMPILER=clang++ \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DDISABLE_TSAN=ON \
|
||||
-DUSE_MSAN=ON \
|
||||
-DCMAKE_CXX_FLAGS="-fsanitize=memory -stdlib=libc++ -I/opt/msan/include/c++/v1 -L/opt/msan/lib -UNDEBUG" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++ -Wl,-rpath,/opt/msan/lib" \
|
||||
-DCMAKE_SHARED_LINKER_FLAGS="-stdlib=libc++ -Wl,-rpath,/opt/msan/lib"
|
||||
ninja -C build
|
||||
ccache -s
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
cd build
|
||||
ctest --no-compress-output --test-output-size-passed 100000 --test-output-size-failed 100000 -T Test -j "$(nproc)" --timeout 300 > /dev/null
|
||||
|
||||
- name: Upload test results to MinIO
|
||||
if: always()
|
||||
env:
|
||||
MINIO_ACCESS_KEY: ${{ secrets.MINIO_ACCESS_KEY }}
|
||||
MC_HOST_minio: https://${{ secrets.MINIO_ACCESS_KEY }}:${{ secrets.MINIO_SECRET_KEY }}@minio.weaselab.dev
|
||||
run: |
|
||||
if [ -z "$MINIO_ACCESS_KEY" ]; then
|
||||
echo "MinIO credentials not configured; skipping upload"
|
||||
exit 0
|
||||
fi
|
||||
zstd build/Testing/*/Test.xml
|
||||
mc cp build/Testing/*/Test.xml.zst "minio/jenkins/conflict-set/${{ gitea.run_number }}/msan/"
|
||||
|
||||
- name: Test summary
|
||||
if: always()
|
||||
run: |
|
||||
python3 ctest_summary.py build/Testing/*/Test.xml \
|
||||
--link "https://minio.weaselab.dev/jenkins/conflict-set/${{ gitea.run_number }}/msan/Test.xml.zst" \
|
||||
| tee -a "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
coverage:
|
||||
runs-on: ubuntu-latest-amd64
|
||||
steps:
|
||||
|
||||
+31
-3
@@ -49,6 +49,18 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
${LLVM_OBJCOPY}
|
||||
CACHE FILEPATH "path to objcopy binary" FORCE)
|
||||
endif()
|
||||
if(USE_MSAN)
|
||||
find_program(LLD_LINKER lld)
|
||||
if(LLD_LINKER)
|
||||
set(CMAKE_LINKER_TYPE
|
||||
"LLD"
|
||||
CACHE STRING "Use LLD linker" FORCE)
|
||||
set(CMAKE_LINKER
|
||||
${LLD_LINKER}
|
||||
CACHE FILEPATH "path to linker binary" FORCE)
|
||||
add_link_options("-fuse-ld=lld")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
@@ -103,6 +115,8 @@ option(USE_SIMD_FALLBACK
|
||||
|
||||
option(DISABLE_TSAN "Disable TSAN" OFF)
|
||||
|
||||
option(USE_MSAN "Build with MemorySanitizer (disables ASan/UBSan)" OFF)
|
||||
|
||||
# This is encouraged according to
|
||||
# https://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq
|
||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/valgrind)
|
||||
@@ -232,8 +246,10 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
target_compile_definitions(conflict_set_main PRIVATE ENABLE_MAIN)
|
||||
target_link_libraries(conflict_set_main PRIVATE nanobench)
|
||||
|
||||
if(NOT APPLE)
|
||||
# libfuzzer target, to generate/manage corpus
|
||||
if(NOT APPLE AND NOT USE_MSAN)
|
||||
# libfuzzer target, to generate/manage corpus. MSan requires an instrumented
|
||||
# libfuzzer runtime, which is not shipped with the compiler, so skip this
|
||||
# target when building with MSan.
|
||||
set(FUZZ_FLAGS "-fsanitize=fuzzer-no-link,address,undefined")
|
||||
include(CheckCXXCompilerFlag)
|
||||
cmake_push_check_state()
|
||||
@@ -257,9 +273,14 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
add_executable(fuzz_driver ConflictSet.cpp FuzzTestDriver.cpp)
|
||||
target_compile_options(fuzz_driver PRIVATE ${TEST_FLAGS})
|
||||
if(NOT CMAKE_CROSSCOMPILING)
|
||||
if(USE_MSAN)
|
||||
target_compile_options(fuzz_driver PRIVATE -fsanitize=memory)
|
||||
target_link_options(fuzz_driver PRIVATE -fsanitize=memory)
|
||||
else()
|
||||
target_compile_options(fuzz_driver PRIVATE -fsanitize=address,undefined)
|
||||
target_link_options(fuzz_driver PRIVATE -fsanitize=address,undefined)
|
||||
endif()
|
||||
endif()
|
||||
target_compile_definitions(fuzz_driver PRIVATE ENABLE_FUZZ)
|
||||
target_include_directories(fuzz_driver
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
@@ -269,7 +290,9 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
endforeach()
|
||||
|
||||
# tsan tests
|
||||
if(NOT CMAKE_CROSSCOMPILING AND NOT DISABLE_TSAN)
|
||||
if(NOT CMAKE_CROSSCOMPILING
|
||||
AND NOT DISABLE_TSAN
|
||||
AND NOT USE_MSAN)
|
||||
add_executable(tsan_driver ConflictSet.cpp FuzzTestDriver.cpp)
|
||||
target_compile_options(tsan_driver PRIVATE ${TEST_FLAGS} -fsanitize=thread)
|
||||
target_link_options(tsan_driver PRIVATE -fsanitize=thread)
|
||||
@@ -491,6 +514,11 @@ target_include_directories(
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}>)
|
||||
|
||||
if(USE_MSAN)
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC -fsanitize=memory)
|
||||
target_link_options(${PROJECT_NAME} PUBLIC -fsanitize=memory)
|
||||
endif()
|
||||
|
||||
set_target_properties(
|
||||
${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR})
|
||||
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
LLVM_VERSION="${LLVM_VERSION:-21}"
|
||||
MSAN_PREFIX="${MSAN_PREFIX:-$PWD/msan}"
|
||||
JOBS="${JOBS:-$(nproc)}"
|
||||
|
||||
cd /tmp
|
||||
rm -rf libcxx-msan
|
||||
mkdir libcxx-msan
|
||||
cd libcxx-msan
|
||||
|
||||
git clone --depth=1 "https://github.com/llvm/llvm-project.git" -b "release/${LLVM_VERSION}.x"
|
||||
|
||||
cmake -S llvm-project/runtimes -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER="clang-${LLVM_VERSION}" \
|
||||
-DCMAKE_CXX_COMPILER="clang++-${LLVM_VERSION}" \
|
||||
-DLLVM_USE_SANITIZER=MemoryWithOrigins \
|
||||
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
|
||||
-DLLVM_TARGETS_TO_BUILD=Native \
|
||||
-DCMAKE_INSTALL_PREFIX="${MSAN_PREFIX}" \
|
||||
-DLIBCXXABI_USE_LLVM_UNWINDER=ON \
|
||||
-DLIBCXXABI_ENABLE_STATIC_UNWINDER=ON \
|
||||
-DLIBCXX_USE_COMPILER_RT=ON \
|
||||
-DLIBCXXABI_USE_COMPILER_RT=ON \
|
||||
-DLIBUNWIND_USE_COMPILER_RT=ON \
|
||||
-DLIBCXX_INCLUDE_TESTS=OFF \
|
||||
-DLIBCXXABI_INCLUDE_TESTS=OFF \
|
||||
-DLIBUNWIND_INCLUDE_TESTS=OFF \
|
||||
-DLIBCXX_ENABLE_CLANG_TIDY=OFF
|
||||
|
||||
cmake --build build -j"${JOBS}"
|
||||
cmake --install build
|
||||
|
||||
VERSION="$(clang-"${LLVM_VERSION}" --version | head -n1 | sed -E 's/.*clang version ([0-9.]+).*/\1/')"
|
||||
TARBALL="msan-toolchain-${VERSION}.tar.zst"
|
||||
|
||||
tar --zstd -cf "${TARBALL}" -C "${MSAN_PREFIX}" .
|
||||
|
||||
TARBALL_PATH="$(pwd)/${TARBALL}"
|
||||
echo "Created: ${TARBALL_PATH}"
|
||||
Reference in New Issue
Block a user