Skip to content

Commit 5adb71f

Browse files
committed
Run Miri on CI
1 parent 28c5577 commit 5adb71f

22 files changed

+110
-29
lines changed

.github/workflows/ci.yml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
name: CI
22

3+
permissions:
4+
contents: read
5+
36
on:
47
pull_request:
58
push:
@@ -10,8 +13,12 @@ on:
1013
- cron: '0 1 * * *'
1114

1215
env:
13-
RUSTFLAGS: -D warnings
16+
CARGO_INCREMENTAL: 0
17+
CARGO_NET_RETRY: 10
18+
CARGO_TERM_COLOR: always
1419
RUST_BACKTRACE: 1
20+
RUSTFLAGS: -D warnings
21+
RUSTUP_MAX_RETRIES: 10
1522

1623
defaults:
1724
run:
@@ -229,6 +236,18 @@ jobs:
229236
- run: ci/no_atomic_cas.sh
230237
- run: git diff --exit-code
231238

239+
miri:
240+
name: cargo miri test
241+
runs-on: ubuntu-latest
242+
steps:
243+
- uses: actions/checkout@v2
244+
- name: Install Rust
245+
run: rustup toolchain install nightly --component miri && rustup default nightly
246+
# futures-executor uses boxed futures so many tests trigger https://github.com/rust-lang/miri/issues/1038
247+
- run: cargo miri test --workspace --exclude futures-executor --all-features
248+
env:
249+
MIRIFLAGS: -Zmiri-disable-isolation # TODO: use -Zmiri-tag-raw-pointers
250+
232251
san:
233252
name: cargo test -Z sanitizer=${{ matrix.sanitizer }}
234253
strategy:
@@ -261,6 +280,7 @@ jobs:
261280
- run: cargo clippy --workspace --all-features --all-targets
262281

263282
fmt:
283+
name: cargo fmt
264284
runs-on: ubuntu-latest
265285
steps:
266286
- uses: actions/checkout@v2

futures-channel/tests/mpsc-close.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ fn single_receiver_drop_closes_channel_and_drains() {
147147

148148
// Stress test that `try_send()`s occurring concurrently with receiver
149149
// close/drops don't appear as successful sends.
150+
#[cfg_attr(miri, ignore)] // Miri is too slow
150151
#[test]
151152
fn stress_try_send_as_receiver_closes() {
152153
const AMT: usize = 10000;

futures-channel/tests/mpsc.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ fn tx_close_gets_none() {
200200

201201
#[test]
202202
fn stress_shared_unbounded() {
203+
#[cfg(miri)]
204+
const AMT: u32 = 100;
205+
#[cfg(not(miri))]
203206
const AMT: u32 = 10000;
204207
const NTHREADS: u32 = 8;
205208
let (tx, rx) = mpsc::unbounded::<i32>();
@@ -229,6 +232,9 @@ fn stress_shared_unbounded() {
229232

230233
#[test]
231234
fn stress_shared_bounded_hard() {
235+
#[cfg(miri)]
236+
const AMT: u32 = 100;
237+
#[cfg(not(miri))]
232238
const AMT: u32 = 10000;
233239
const NTHREADS: u32 = 8;
234240
let (tx, rx) = mpsc::channel::<i32>(0);
@@ -259,6 +265,9 @@ fn stress_shared_bounded_hard() {
259265
#[allow(clippy::same_item_push)]
260266
#[test]
261267
fn stress_receiver_multi_task_bounded_hard() {
268+
#[cfg(miri)]
269+
const AMT: usize = 100;
270+
#[cfg(not(miri))]
262271
const AMT: usize = 10_000;
263272
const NTHREADS: u32 = 2;
264273

@@ -327,6 +336,11 @@ fn stress_receiver_multi_task_bounded_hard() {
327336
/// after sender dropped.
328337
#[test]
329338
fn stress_drop_sender() {
339+
#[cfg(miri)]
340+
const ITER: usize = 100;
341+
#[cfg(not(miri))]
342+
const ITER: usize = 10000;
343+
330344
fn list() -> impl Stream<Item = i32> {
331345
let (tx, rx) = mpsc::channel(1);
332346
thread::spawn(move || {
@@ -335,7 +349,7 @@ fn stress_drop_sender() {
335349
rx
336350
}
337351

338-
for _ in 0..10000 {
352+
for _ in 0..ITER {
339353
let v: Vec<_> = block_on(list().collect());
340354
assert_eq!(v, vec![1, 2, 3]);
341355
}
@@ -380,9 +394,12 @@ fn stress_close_receiver_iter() {
380394
}
381395
}
382396

397+
#[cfg_attr(miri, ignore)] // Miri is too slow
383398
#[test]
384399
fn stress_close_receiver() {
385-
for _ in 0..10000 {
400+
const ITER: usize = 10000;
401+
402+
for _ in 0..ITER {
386403
stress_close_receiver_iter();
387404
}
388405
}
@@ -397,6 +414,9 @@ async fn stress_poll_ready_sender(mut sender: mpsc::Sender<u32>, count: u32) {
397414
#[allow(clippy::same_item_push)]
398415
#[test]
399416
fn stress_poll_ready() {
417+
#[cfg(miri)]
418+
const AMT: u32 = 100;
419+
#[cfg(not(miri))]
400420
const AMT: u32 = 1000;
401421
const NTHREADS: u32 = 8;
402422

@@ -424,6 +444,7 @@ fn stress_poll_ready() {
424444
stress(16);
425445
}
426446

447+
#[cfg_attr(miri, ignore)] // Miri is too slow
427448
#[test]
428449
fn try_send_1() {
429450
const N: usize = 3000;

futures-channel/tests/oneshot.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ fn cancel_notifies() {
3535

3636
#[test]
3737
fn cancel_lots() {
38+
#[cfg(miri)]
39+
const N: usize = 100;
40+
#[cfg(not(miri))]
41+
const N: usize = 20000;
42+
3843
let (tx, rx) = mpsc::channel::<(Sender<_>, mpsc::Sender<_>)>();
3944
let t = thread::spawn(move || {
4045
for (mut tx, tx2) in rx {
@@ -43,7 +48,7 @@ fn cancel_lots() {
4348
}
4449
});
4550

46-
for _ in 0..20000 {
51+
for _ in 0..N {
4752
let (otx, orx) = oneshot::channel::<u32>();
4853
let (tx2, rx2) = mpsc::channel();
4954
tx.send((otx, tx2)).unwrap();
@@ -101,14 +106,19 @@ fn is_canceled() {
101106

102107
#[test]
103108
fn cancel_sends() {
109+
#[cfg(miri)]
110+
const N: usize = 100;
111+
#[cfg(not(miri))]
112+
const N: usize = 20000;
113+
104114
let (tx, rx) = mpsc::channel::<Sender<_>>();
105115
let t = thread::spawn(move || {
106116
for otx in rx {
107117
let _ = otx.send(42);
108118
}
109119
});
110120

111-
for _ in 0..20000 {
121+
for _ in 0..N {
112122
let (otx, mut orx) = oneshot::channel::<u32>();
113123
tx.send(otx).unwrap();
114124

futures-util/src/compat/compat01as03.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ pub trait Future01CompatExt: Future01 {
6464
/// [`Future<Output = Result<T, E>>`](futures_core::future::Future).
6565
///
6666
/// ```
67+
/// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514
6768
/// # futures::executor::block_on(async {
6869
/// # // TODO: These should be all using `futures::compat`, but that runs up against Cargo
6970
/// # // feature issues
@@ -90,6 +91,7 @@ pub trait Stream01CompatExt: Stream01 {
9091
/// [`Stream<Item = Result<T, E>>`](futures_core::stream::Stream).
9192
///
9293
/// ```
94+
/// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514
9395
/// # futures::executor::block_on(async {
9496
/// use futures::stream::StreamExt;
9597
/// use futures_util::compat::Stream01CompatExt;
@@ -119,6 +121,7 @@ pub trait Sink01CompatExt: Sink01 {
119121
/// [`Sink<T, Error = E>`](futures_sink::Sink).
120122
///
121123
/// ```
124+
/// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514
122125
/// # futures::executor::block_on(async {
123126
/// use futures::{sink::SinkExt, stream::StreamExt};
124127
/// use futures_util::compat::{Stream01CompatExt, Sink01CompatExt};
@@ -362,6 +365,7 @@ mod io {
362365
/// [`AsyncRead`](futures_io::AsyncRead).
363366
///
364367
/// ```
368+
/// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514
365369
/// # futures::executor::block_on(async {
366370
/// use futures::io::AsyncReadExt;
367371
/// use futures_util::compat::AsyncRead01CompatExt;
@@ -391,6 +395,7 @@ mod io {
391395
/// [`AsyncWrite`](futures_io::AsyncWrite).
392396
///
393397
/// ```
398+
/// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514
394399
/// # futures::executor::block_on(async {
395400
/// use futures::io::AsyncWriteExt;
396401
/// use futures_util::compat::AsyncWrite01CompatExt;

futures-util/src/compat/executor.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub trait Executor01CompatExt: Executor01<Executor01Future> + Clone + Send + 'st
1717
/// futures 0.3 [`Spawn`](futures_task::Spawn).
1818
///
1919
/// ```
20+
/// # if cfg!(miri) { return; } // Miri does not support epoll
2021
/// use futures::task::SpawnExt;
2122
/// use futures::future::{FutureExt, TryFutureExt};
2223
/// use futures_util::compat::Executor01CompatExt;

futures-util/src/stream/try_stream/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,7 @@ pub trait TryStreamExt: TryStream {
894894
/// Wraps a [`TryStream`] into a stream compatible with libraries using
895895
/// futures 0.1 `Stream`. Requires the `compat` feature to be enabled.
896896
/// ```
897+
/// # if cfg!(miri) { return; } // Miri does not support epoll
897898
/// use futures::future::{FutureExt, TryFutureExt};
898899
/// # let (tx, rx) = futures::channel::oneshot::channel();
899900
///

futures-util/src/task/spawn.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub trait SpawnExt: Spawn {
3434
/// today. Feel free to use this method in the meantime.
3535
///
3636
/// ```
37+
/// # if cfg!(miri) { return; } // https://github.com/rust-lang/miri/issues/1038
3738
/// use futures::executor::ThreadPool;
3839
/// use futures::task::SpawnExt;
3940
///
@@ -58,6 +59,7 @@ pub trait SpawnExt: Spawn {
5859
/// resolves to the output of the spawned future.
5960
///
6061
/// ```
62+
/// # if cfg!(miri) { return; } // https://github.com/rust-lang/miri/issues/1038
6163
/// use futures::executor::{block_on, ThreadPool};
6264
/// use futures::future;
6365
/// use futures::task::SpawnExt;
@@ -136,6 +138,7 @@ pub trait LocalSpawnExt: LocalSpawn {
136138
/// resolves to the output of the spawned future.
137139
///
138140
/// ```
141+
/// # if cfg!(miri) { return; } // https://github.com/rust-lang/miri/issues/1038
139142
/// use futures::executor::LocalPool;
140143
/// use futures::task::LocalSpawnExt;
141144
///

futures/tests/compat.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![cfg(feature = "compat")]
2+
#![cfg(not(miri))] // Miri does not support epoll
23

34
use futures::compat::Future01CompatExt;
45
use futures::prelude::*;

futures/tests/eventual.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![cfg(not(miri))] // https://github.com/rust-lang/miri/issues/1038
2+
13
use futures::channel::oneshot;
24
use futures::executor::ThreadPool;
35
use futures::future::{self, ok, Future, FutureExt, TryFutureExt};

futures/tests/future_join_all.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
use futures::executor::block_on;
22
use futures::future::{join_all, ready, Future, JoinAll};
3+
use futures::pin_mut;
34
use std::fmt::Debug;
45

5-
fn assert_done<T, F>(actual_fut: F, expected: T)
6+
#[track_caller]
7+
fn assert_done<T>(actual_fut: impl Future<Output = T>, expected: T)
68
where
79
T: PartialEq + Debug,
8-
F: FnOnce() -> Box<dyn Future<Output = T> + Unpin>,
910
{
10-
let output = block_on(actual_fut());
11+
pin_mut!(actual_fut);
12+
let output = block_on(actual_fut);
1113
assert_eq!(output, expected);
1214
}
1315

1416
#[test]
1517
fn collect_collects() {
16-
assert_done(|| Box::new(join_all(vec![ready(1), ready(2)])), vec![1, 2]);
17-
assert_done(|| Box::new(join_all(vec![ready(1)])), vec![1]);
18+
assert_done(join_all(vec![ready(1), ready(2)]), vec![1, 2]);
19+
assert_done(join_all(vec![ready(1)]), vec![1]);
1820
// REVIEW: should this be implemented?
19-
// assert_done(|| Box::new(join_all(Vec::<i32>::new())), vec![]);
21+
// assert_done(join_all(Vec::<i32>::new()), vec![]);
2022

2123
// TODO: needs more tests
2224
}
@@ -25,18 +27,15 @@ fn collect_collects() {
2527
fn join_all_iter_lifetime() {
2628
// In futures-rs version 0.1, this function would fail to typecheck due to an overly
2729
// conservative type parameterization of `JoinAll`.
28-
fn sizes(bufs: Vec<&[u8]>) -> Box<dyn Future<Output = Vec<usize>> + Unpin> {
30+
fn sizes(bufs: Vec<&[u8]>) -> impl Future<Output = Vec<usize>> {
2931
let iter = bufs.into_iter().map(|b| ready::<usize>(b.len()));
30-
Box::new(join_all(iter))
32+
join_all(iter)
3133
}
3234

33-
assert_done(|| sizes(vec![&[1, 2, 3], &[], &[0]]), vec![3_usize, 0, 1]);
35+
assert_done(sizes(vec![&[1, 2, 3], &[], &[0]]), vec![3_usize, 0, 1]);
3436
}
3537

3638
#[test]
3739
fn join_all_from_iter() {
38-
assert_done(
39-
|| Box::new(vec![ready(1), ready(2)].into_iter().collect::<JoinAll<_>>()),
40-
vec![1, 2],
41-
)
40+
assert_done(vec![ready(1), ready(2)].into_iter().collect::<JoinAll<_>>(), vec![1, 2])
4241
}

futures/tests/future_shared.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ fn drop_in_poll() {
9696
assert_eq!(block_on(future1), 1);
9797
}
9898

99+
#[cfg_attr(miri, ignore)] // https://github.com/rust-lang/miri/issues/1038
99100
#[test]
100101
fn peek() {
101102
let mut local_pool = LocalPool::new();

futures/tests/future_try_join_all.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
use futures::executor::block_on;
2+
use futures::pin_mut;
23
use futures_util::future::{err, ok, try_join_all, TryJoinAll};
34
use std::fmt::Debug;
45
use std::future::Future;
56

6-
fn assert_done<T, F>(actual_fut: F, expected: T)
7+
#[track_caller]
8+
fn assert_done<T>(actual_fut: impl Future<Output = T>, expected: T)
79
where
810
T: PartialEq + Debug,
9-
F: FnOnce() -> Box<dyn Future<Output = T> + Unpin>,
1011
{
11-
let output = block_on(actual_fut());
12+
pin_mut!(actual_fut);
13+
let output = block_on(actual_fut);
1214
assert_eq!(output, expected);
1315
}
1416

1517
#[test]
1618
fn collect_collects() {
17-
assert_done(|| Box::new(try_join_all(vec![ok(1), ok(2)])), Ok::<_, usize>(vec![1, 2]));
18-
assert_done(|| Box::new(try_join_all(vec![ok(1), err(2)])), Err(2));
19-
assert_done(|| Box::new(try_join_all(vec![ok(1)])), Ok::<_, usize>(vec![1]));
19+
assert_done(try_join_all(vec![ok(1), ok(2)]), Ok::<_, usize>(vec![1, 2]));
20+
assert_done(try_join_all(vec![ok(1), err(2)]), Err(2));
21+
assert_done(try_join_all(vec![ok(1)]), Ok::<_, usize>(vec![1]));
2022
// REVIEW: should this be implemented?
21-
// assert_done(|| Box::new(try_join_all(Vec::<i32>::new())), Ok(vec![]));
23+
// assert_done(try_join_all(Vec::<i32>::new()), Ok(vec![]));
2224

2325
// TODO: needs more tests
2426
}
@@ -27,18 +29,18 @@ fn collect_collects() {
2729
fn try_join_all_iter_lifetime() {
2830
// In futures-rs version 0.1, this function would fail to typecheck due to an overly
2931
// conservative type parameterization of `TryJoinAll`.
30-
fn sizes(bufs: Vec<&[u8]>) -> Box<dyn Future<Output = Result<Vec<usize>, ()>> + Unpin> {
32+
fn sizes(bufs: Vec<&[u8]>) -> impl Future<Output = Result<Vec<usize>, ()>> {
3133
let iter = bufs.into_iter().map(|b| ok::<usize, ()>(b.len()));
32-
Box::new(try_join_all(iter))
34+
try_join_all(iter)
3335
}
3436

35-
assert_done(|| sizes(vec![&[1, 2, 3], &[], &[0]]), Ok(vec![3_usize, 0, 1]));
37+
assert_done(sizes(vec![&[1, 2, 3], &[], &[0]]), Ok(vec![3_usize, 0, 1]));
3638
}
3739

3840
#[test]
3941
fn try_join_all_from_iter() {
4042
assert_done(
41-
|| Box::new(vec![ok(1), ok(2)].into_iter().collect::<TryJoinAll<_>>()),
43+
vec![ok(1), ok(2)].into_iter().collect::<TryJoinAll<_>>(),
4244
Ok::<_, usize>(vec![1, 2]),
4345
)
4446
}

0 commit comments

Comments
 (0)