Skip to content

Commit 11d646e

Browse files
committed
stream: add track_caller to public APIs (tokio-rs#4413)
Functions that may panic can be annotated with `#[track_caller]` so that in the event of a panic, the function where the user called the panicking function is shown instead of the file and line within Tokio source. This change adds `#[track_caller]` to all the non-unstable public APIs in tokio-stream (only `chunks_timeout` in `StreamExt`) where the documentation describes how this function may panic due to incorrect input. A test has been included to cover the panic.
1 parent 159508b commit 11d646e

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

tokio-stream/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ tokio-util = { version = "0.7.0", path = "../tokio-util", optional = true }
3434
[dev-dependencies]
3535
tokio = { version = "1.2.0", path = "../tokio", features = ["full", "test-util"] }
3636
async-stream = "0.3"
37+
parking_lot = "0.12.0"
3738
tokio-test = { path = "../tokio-test" }
3839
futures = { version = "0.3", default-features = false }
3940

tokio-stream/src/stream_ext.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,7 @@ pub trait StreamExt: Stream {
10561056
/// ```
10571057
#[cfg(feature = "time")]
10581058
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
1059+
#[track_caller]
10591060
fn chunks_timeout(self, max_size: usize, duration: Duration) -> ChunksTimeout<Self>
10601061
where
10611062
Self: Sized,

tokio-stream/tests/stream_panic.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#![warn(rust_2018_idioms)]
2+
#![cfg(feature = "time")]
3+
4+
use parking_lot::{const_mutex, Mutex};
5+
use std::error::Error;
6+
use std::panic;
7+
use std::sync::Arc;
8+
use tokio::time::Duration;
9+
use tokio_stream::{self as stream, StreamExt};
10+
11+
fn test_panic<Func: FnOnce() + panic::UnwindSafe>(func: Func) -> Option<String> {
12+
static PANIC_MUTEX: Mutex<()> = const_mutex(());
13+
14+
{
15+
let _guard = PANIC_MUTEX.lock();
16+
let panic_file: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None));
17+
18+
let prev_hook = panic::take_hook();
19+
{
20+
let panic_file = panic_file.clone();
21+
panic::set_hook(Box::new(move |panic_info| {
22+
let panic_location = panic_info.location().unwrap();
23+
panic_file
24+
.lock()
25+
.clone_from(&Some(panic_location.file().to_string()));
26+
}));
27+
}
28+
29+
let result = panic::catch_unwind(func);
30+
// Return to the previously set panic hook (maybe default) so that we get nice error
31+
// messages in the tests.
32+
panic::set_hook(prev_hook);
33+
34+
if result.is_err() {
35+
panic_file.lock().clone()
36+
} else {
37+
None
38+
}
39+
}
40+
}
41+
42+
#[test]
43+
fn stream_chunks_timeout_panic_caller() -> Result<(), Box<dyn Error>> {
44+
let panic_location_file = test_panic(|| {
45+
let iter = vec![1, 2, 3].into_iter();
46+
let stream0 = stream::iter(iter);
47+
48+
let _chunk_stream = stream0.chunks_timeout(0, Duration::from_secs(2));
49+
});
50+
51+
// The panic location should be in this file
52+
assert_eq!(&panic_location_file.unwrap(), file!());
53+
54+
Ok(())
55+
}

0 commit comments

Comments
 (0)