Skip to content

Tailor CI for Tuwunel. #10

Tailor CI for Tuwunel.

Tailor CI for Tuwunel. #10

Workflow file for this run

name: Sanitizers
# Sanitizers run when any trusted branch changes or a maintainer dispatches the
# workflow. Pull request code does not execute in this public runner-enabled
# repository.
on:
push:
branches:
- "**"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
SANITIZER_FEATURES: bindgen-runtime,bzip2,io-uring,lz4,multi-threaded-cf,serde1,zstd,zstd-static-linking-only
jobs:
ubsan:
name: UndefinedBehaviorSanitizer
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- name: Checkout sources
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
with:
persist-credentials: false
submodules: recursive
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1.17.0
with:
toolchain: stable
cache-key: "v1-rust-ubsan"
cache-bin: false
cache-on-failure: false
cache-save-if: ${{ github.event_name == 'push' && github.ref_name == github.event.repository.default_branch }}
cache-targets: false
rustflags: ""
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang libclang-dev liburing-dev llvm pkg-config
# rustc has no UBSan, so only the C++ is instrumented. That is where the
# value is anyway: RocksDB plus the hand-written extension in
# `librocksdb-sys/c-api-extensions/`, which does pointer and length
# arithmetic across the FFI boundary.
#
# ROCKSDB_UBSAN_RUN is RocksDB's own switch. It puts
# `no_sanitize("alignment")` on the deliberately unaligned loads in
# `util/coding.h`, `util/murmurhash.cc` and the crc32c sources.
#
# vptr needs RTTI and `build.rs` compiles with `-fno-rtti` unless the
# `rtti` feature is on, so that check has to come back out.
#
# Without `-fno-sanitize-recover=all` UBSan prints and carries on, and
# the job passes with undefined behaviour in the log.
- name: Run tests with UndefinedBehaviorSanitizer
env:
CC: clang
CXX: clang++
CFLAGS: -fsanitize=undefined -fno-sanitize=vptr -fno-sanitize-recover=all -DROCKSDB_UBSAN_RUN -fno-omit-frame-pointer
CXXFLAGS: -fsanitize=undefined -fno-sanitize=vptr -fno-sanitize-recover=all -DROCKSDB_UBSAN_RUN -fno-omit-frame-pointer
RUSTFLAGS: -Clinker=clang -Clink-arg=-fsanitize=undefined
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
run: |
cargo test --locked --workspace --no-default-features \
--features "$SANITIZER_FEATURES" --lib --bins --tests --jobs 2
asan:
name: AddressSanitizer and LeakSanitizer
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- name: Checkout sources
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
with:
persist-credentials: false
submodules: recursive
- name: Install rust nightly
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1.17.0
with:
toolchain: nightly
components: rust-src
cache-key: "v1-rust-asan"
cache-bin: false
cache-on-failure: false
cache-save-if: ${{ github.event_name == 'push' && github.ref_name == github.event.repository.default_branch }}
cache-targets: false
rustflags: ""
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang libclang-dev liburing-dev llvm pkg-config
- name: Run tests with AddressSanitizer and LeakSanitizer
env:
CC: clang
CXX: clang++
RUSTFLAGS: -Zsanitizer=address
RUSTDOCFLAGS: -Zsanitizer=address
CFLAGS: -fsanitize=address -fno-omit-frame-pointer
CXXFLAGS: -fsanitize=address -fno-omit-frame-pointer
ASAN_OPTIONS: detect_leaks=1:detect_stack_use_after_return=1:abort_on_error=1:print_stats=1
run: |
cargo +nightly test -Zbuild-std --target x86_64-unknown-linux-gnu \
--locked --workspace --no-default-features --features "$SANITIZER_FEATURES" \
--lib --bins --tests --jobs 2
tsan:
name: ThreadSanitizer
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- name: Checkout sources
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
with:
persist-credentials: false
submodules: recursive
- name: Install rust nightly
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1.17.0
with:
toolchain: nightly
components: rust-src
cache-key: "v1-rust-tsan"
cache-bin: false
cache-on-failure: false
cache-save-if: ${{ github.event_name == 'push' && github.ref_name == github.event.repository.default_branch }}
cache-targets: false
rustflags: ""
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang libclang-dev liburing-dev llvm pkg-config
# This crate's public contract is largely a thread-safety claim: the
# `Send`/`Sync` impls, the `MultiThreaded` column family map, and
# snapshot and iterator lifetimes against RocksDB's background threads.
# TSan is the only tool here that checks any of it.
#
# `-fPIC` and `FOLLY_SANITIZE_THREAD` match what RocksDB's own Makefile
# does under COMPILE_WITH_TSAN. SANITIZER_FEATURES intentionally omits
# jemalloc because TSan does not work with it.
#
# Do not add `-fsanitize=thread` as a link arg. `-Zsanitizer=thread`
# already links rustc's TSan runtime and clang's is a duplicate of it.
- name: Run tests with ThreadSanitizer
env:
CC: clang
CXX: clang++
CFLAGS: -fsanitize=thread -fPIC -DFOLLY_SANITIZE_THREAD -fno-omit-frame-pointer
CXXFLAGS: -fsanitize=thread -fPIC -DFOLLY_SANITIZE_THREAD -fno-omit-frame-pointer
RUSTFLAGS: -Zsanitizer=thread
TSAN_OPTIONS: halt_on_error=1:suppressions=${{ github.workspace }}/.github/tsan-suppressions.txt
run: |
cargo +nightly test -Zbuild-std --target x86_64-unknown-linux-gnu \
--locked --workspace --no-default-features --features "$SANITIZER_FEATURES" \
--lib --bins --tests --jobs 2
valgrind:
name: Valgrind memcheck
runs-on: ubuntu-24.04
timeout-minutes: 90
steps:
- name: Checkout sources
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
with:
persist-credentials: false
submodules: recursive
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1.17.0
with:
toolchain: stable
cache-key: "v1-rust-valgrind"
cache-bin: false
cache-on-failure: false
cache-save-if: ${{ github.event_name == 'push' && github.ref_name == github.event.repository.default_branch }}
cache-targets: false
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang libclang-dev liburing-dev pkg-config valgrind
- name: Build test binaries
run: |
set -euo pipefail
cargo test --locked --workspace --no-default-features \
--features "$SANITIZER_FEATURES,valgrind" \
--lib --bins --tests --no-run --message-format=json \
> cargo-test.json
grep -o '"executable":"[^"]*"' cargo-test.json \
| cut -d'"' -f4 | sort -u > test-binaries.txt
count=$(wc -l < test-binaries.txt)
echo "found $count test binaries"
# Without this the loop below would find nothing and report success.
test "$count" -gt 0
# Memcheck is the only thing here that reports reads of uninitialised
# memory. MemorySanitizer would too, but it needs an instrumented libc++
# underneath RocksDB, which is not a reasonable amount of work for this
# crate. Leak checking is off because LeakSanitizer already covers it in
# the AddressSanitizer job and is much faster at it.
- name: Run test binaries under memcheck
run: |
set -uo pipefail
failed=0
while read -r bin; do
echo "::group::$(basename "$bin")"
if ! valgrind --suppressions=.github/valgrind.supp \
--error-exitcode=99 --leak-check=no \
--errors-for-leak-kinds=none \
"$bin" --test-threads=1; then
failed=1
echo "::error::valgrind reported errors in $(basename "$bin")"
fi
echo "::endgroup::"
done < test-binaries.txt
exit "$failed"