diff --git a/ci/crossbeam-channel.sh b/ci/crossbeam-channel.sh index abe70583a..02ed9ed53 100755 --- a/ci/crossbeam-channel.sh +++ b/ci/crossbeam-channel.sh @@ -1,8 +1,10 @@ #!/bin/bash -cd "$(dirname "$0")"/../crossbeam-channel set -ex +script_dir="$(cd "$(dirname "$0")" && pwd)" +cd "$script_dir"/../crossbeam-channel + export RUSTFLAGS="-D warnings" cargo check --bins --examples --tests @@ -11,6 +13,11 @@ cargo test -- --test-threads=1 if [[ "$RUST_VERSION" == "nightly"* ]]; then cd benchmarks cargo check --bins + cd .. RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --all-features + + # Run sanitizers + export TSAN_OPTIONS="suppressions=$script_dir/tsan" + "$script_dir"/san.sh --features sanitize fi diff --git a/ci/crossbeam-deque.sh b/ci/crossbeam-deque.sh index fb53ab88c..1796b1e24 100755 --- a/ci/crossbeam-deque.sh +++ b/ci/crossbeam-deque.sh @@ -1,8 +1,10 @@ #!/bin/bash -cd "$(dirname "$0")"/../crossbeam-deque set -ex +script_dir="$(cd "$(dirname "$0")" && pwd)" +cd "$script_dir"/../crossbeam-deque + export RUSTFLAGS="-D warnings" cargo check --bins --examples --tests @@ -10,4 +12,8 @@ cargo test if [[ "$RUST_VERSION" == "nightly"* ]]; then RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --all-features + + # Run sanitizers + export TSAN_OPTIONS="suppressions=$script_dir/tsan" + "$script_dir"/san.sh fi diff --git a/ci/crossbeam-epoch.sh b/ci/crossbeam-epoch.sh index 995f81c0d..95f773717 100755 --- a/ci/crossbeam-epoch.sh +++ b/ci/crossbeam-epoch.sh @@ -1,8 +1,10 @@ #!/bin/bash -cd "$(dirname "$0")"/../crossbeam-epoch set -ex +script_dir="$(cd "$(dirname "$0")" && pwd)" +cd "$script_dir"/../crossbeam-epoch + export RUSTFLAGS="-D warnings" cargo check --bins --examples --tests @@ -14,7 +16,10 @@ if [[ "$RUST_VERSION" == "nightly"* ]]; then RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --all-features if [[ "$OSTYPE" == "linux"* ]]; then - ASAN_OPTIONS="detect_odr_violation=0 detect_leaks=0" \ + # Run sanitizers + export TSAN_OPTIONS="suppressions=$script_dir/tsan" + "$script_dir"/san.sh --features sanitize,nightly + RUSTFLAGS="-Z sanitizer=address" \ cargo run \ --release \ diff --git a/ci/crossbeam-queue.sh b/ci/crossbeam-queue.sh index b15303b5b..d00df0276 100755 --- a/ci/crossbeam-queue.sh +++ b/ci/crossbeam-queue.sh @@ -1,8 +1,10 @@ #!/bin/bash -cd "$(dirname "$0")"/../crossbeam-queue set -ex +script_dir="$(cd "$(dirname "$0")" && pwd)" +cd "$script_dir"/../crossbeam-queue + export RUSTFLAGS="-D warnings" cargo check --bins --examples --tests @@ -10,4 +12,7 @@ cargo test if [[ "$RUST_VERSION" == "nightly"* ]]; then RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --all-features + + # Run sanitizers + "$script_dir"/san.sh --features nightly fi diff --git a/ci/crossbeam-skiplist.sh b/ci/crossbeam-skiplist.sh index 3928d42e4..9cc38e7d9 100755 --- a/ci/crossbeam-skiplist.sh +++ b/ci/crossbeam-skiplist.sh @@ -1,8 +1,10 @@ #!/bin/bash -cd "$(dirname "$0")"/../crossbeam-skiplist set -ex +script_dir="$(cd "$(dirname "$0")" && pwd)" +cd "$script_dir"/../crossbeam-skiplist + export RUSTFLAGS="-D warnings" cargo check --bins --examples --tests @@ -12,4 +14,9 @@ if [[ "$RUST_VERSION" == "nightly"* ]]; then cargo test --features nightly RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --all-features + + # Run sanitizers + # https://github.com/crossbeam-rs/crossbeam/issues/614 + export ASAN_OPTIONS="detect_leaks=0" + "$script_dir"/san.sh --features nightly fi diff --git a/ci/crossbeam-utils.sh b/ci/crossbeam-utils.sh index 4879687de..95bad2454 100755 --- a/ci/crossbeam-utils.sh +++ b/ci/crossbeam-utils.sh @@ -1,8 +1,10 @@ #!/bin/bash -cd "$(dirname "$0")"/../crossbeam-utils set -ex +script_dir="$(cd "$(dirname "$0")" && pwd)" +cd "$script_dir"/../crossbeam-utils + export RUSTFLAGS="-D warnings" cargo check --bins --examples --tests @@ -12,4 +14,7 @@ if [[ "$RUST_VERSION" == "nightly"* ]]; then cargo test --features nightly RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --all-features + + # Run sanitizers + "$script_dir"/san.sh --features nightly fi diff --git a/ci/crossbeam.sh b/ci/crossbeam.sh index 99d4483bd..564a846b5 100755 --- a/ci/crossbeam.sh +++ b/ci/crossbeam.sh @@ -1,8 +1,10 @@ #!/bin/bash -cd "$(dirname "$0")"/.. set -ex +script_dir="$(cd "$(dirname "$0")" && pwd)" +cd "$script_dir"/.. + export RUSTFLAGS="-D warnings" cargo check --bins --examples --tests @@ -12,4 +14,7 @@ if [[ "$RUST_VERSION" == "nightly"* ]]; then cargo test --features nightly RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --all-features + + # Run sanitizers + "$script_dir"/san.sh --features nightly fi diff --git a/ci/san.sh b/ci/san.sh new file mode 100755 index 000000000..89e42cc7a --- /dev/null +++ b/ci/san.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +set -ex + +if [[ "$OSTYPE" != "linux"* ]]; then + exit 0 +fi + +rustup component add rust-src + +# Run address sanitizer +cargo clean +RUSTFLAGS="-Z sanitizer=address" \ +cargo test --release --target x86_64-unknown-linux-gnu --tests "$@" + +# Run leak sanitizer (when memory leak detection is enabled) +if [[ "$ASAN_OPTIONS" != *"detect_leaks=0"* ]]; then + cargo clean + RUSTFLAGS="-Z sanitizer=leak" \ + cargo test --release --target x86_64-unknown-linux-gnu --tests "$@" +fi + +# Run memory sanitizer +cargo clean +RUSTFLAGS="-Z sanitizer=memory" \ +cargo test -Zbuild-std --release --target x86_64-unknown-linux-gnu --tests "$@" + +# Run thread sanitizer +cargo clean +RUSTFLAGS="-Z sanitizer=thread" \ +cargo test -Zbuild-std --release --target x86_64-unknown-linux-gnu --tests "$@" diff --git a/ci/tsan b/ci/tsan new file mode 100644 index 000000000..8c7e23fc9 --- /dev/null +++ b/ci/tsan @@ -0,0 +1,13 @@ +# TSAN suppressions file for crossbeam + +# The epoch-based GC uses fences. +race:crossbeam_epoch + +# Push and steal operations in crossbeam-deque may cause data races, but such +# data races are safe. If a data race happens, the value read by `steal` is +# forgotten and the steal operation is then retried. +race:crossbeam_deque*push +race:crossbeam_deque*steal + +# AtomicCell::compare_exchange uses fences if it is not lock-free. +race:crossbeam_utils::atomic::atomic_cell::AtomicCell::compare_exchange diff --git a/crossbeam-channel/Cargo.toml b/crossbeam-channel/Cargo.toml index 2931d21cd..3959a0acd 100644 --- a/crossbeam-channel/Cargo.toml +++ b/crossbeam-channel/Cargo.toml @@ -23,6 +23,12 @@ default = ["std"] # This is enabled by default. std = ["crossbeam-utils/std"] +# TODO: Once `cfg(sanitize = "..")` is stable, replace this. +# An internal feature used when running sanitizers. +# This is not part of the public API and crossbeam may make breaking changes +# to them at any time. +sanitize = [] + [dependencies] cfg-if = "1" diff --git a/crossbeam-channel/tests/tick.rs b/crossbeam-channel/tests/tick.rs index 5dc87306f..470dfdf8f 100644 --- a/crossbeam-channel/tests/tick.rs +++ b/crossbeam-channel/tests/tick.rs @@ -127,6 +127,7 @@ fn recv() { assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); } +#[cfg(not(feature = "sanitize"))] // TODO: assertions failed due to tsan is slow #[test] fn recv_timeout() { let start = Instant::now(); @@ -251,6 +252,7 @@ fn select() { assert_eq!(hits.load(Ordering::SeqCst), 8); } +#[cfg(not(feature = "sanitize"))] // TODO: assertions failed due to tsan is slow #[test] fn ready() { const THREADS: usize = 4; diff --git a/crossbeam-epoch/Cargo.toml b/crossbeam-epoch/Cargo.toml index b56b6f52a..d7b3d8ed9 100644 --- a/crossbeam-epoch/Cargo.toml +++ b/crossbeam-epoch/Cargo.toml @@ -33,7 +33,10 @@ alloc = [] # of crossbeam may make breaking changes to them at any time. nightly = ["crossbeam-utils/nightly"] -# TODO: docs +# TODO: Once `cfg(sanitize = "..")` is stable, replace this. +# An internal feature used when running sanitizers. +# This is not part of the public API and crossbeam may make breaking changes +# to them at any time. sanitize = [] # Makes it more likely to trigger any potential data races. [dependencies] diff --git a/crossbeam-epoch/src/collector.rs b/crossbeam-epoch/src/collector.rs index 8224e1184..ec7fe9b8c 100644 --- a/crossbeam-epoch/src/collector.rs +++ b/crossbeam-epoch/src/collector.rs @@ -199,6 +199,7 @@ mod tests { .unwrap(); } + #[cfg(not(feature = "sanitize"))] // TODO: assertions failed due to tsan is slow #[test] fn incremental() { const COUNT: usize = 100_000; diff --git a/crossbeam-epoch/src/internal.rs b/crossbeam-epoch/src/internal.rs index bf2dfb887..0f9b7e90d 100644 --- a/crossbeam-epoch/src/internal.rs +++ b/crossbeam-epoch/src/internal.rs @@ -374,6 +374,7 @@ pub struct Local { // Make sure `Local` is less than or equal to 2048 bytes. // https://github.com/crossbeam-rs/crossbeam/issues/551 +#[cfg(not(feature = "sanitize"))] // `feature = "sanitize"` reduces the size of `Local` #[test] fn local_size() { assert!(core::mem::size_of::() <= 2048, "An allocation of `Local` should be <= 2048 bytes.");