From 34263376505d07cbf8a587b9841af0a7b3bc6ada Mon Sep 17 00:00:00 2001 From: "Stainsby, Hayden" Date: Tue, 5 Jul 2022 11:12:55 +0200 Subject: [PATCH] signal: add track_caller to public APIs 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 the signal() function which is the only function in the signal public API which can panic. Documentation was added to this function to indicate that it may panic. Not all panic cases can have #[track_caller] applied fully as the callstack passes through a closure which isn't yet supported by the annotation (e.g. signal() called from outside a tokio runtime). Tests are included to cover the case where signal() is called from a runtime without IO enabled. Refs: #4413 --- tokio/src/signal/unix.rs | 6 ++++++ tokio/src/signal/unix/driver.rs | 2 ++ tokio/tests/signal_panic.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 tokio/tests/signal_panic.rs diff --git a/tokio/src/signal/unix.rs b/tokio/src/signal/unix.rs index 11f848b5a99..0fe83150109 100644 --- a/tokio/src/signal/unix.rs +++ b/tokio/src/signal/unix.rs @@ -384,6 +384,12 @@ pub struct Signal { /// * If the previous initialization of this specific signal failed. /// * If the signal is one of /// [`signal_hook::FORBIDDEN`](fn@signal_hook_registry::register#panics) +/// +/// # Panics +/// +/// This function panics if there is no current reactor set, or if the `rt` +/// feature flag is not enabled. +#[track_caller] pub fn signal(kind: SignalKind) -> io::Result { let rx = signal_with_handle(kind, &Handle::current())?; diff --git a/tokio/src/signal/unix/driver.rs b/tokio/src/signal/unix/driver.rs index 5fe7c354c5f..e14a6d77747 100644 --- a/tokio/src/signal/unix/driver.rs +++ b/tokio/src/signal/unix/driver.rs @@ -182,6 +182,7 @@ cfg_rt! { /// # Panics /// /// This function panics if there is no current signal driver set. + #[track_caller] pub(super) fn current() -> Self { crate::runtime::context::signal_handle().expect( "there is no signal driver running, must be called from the context of Tokio runtime", @@ -197,6 +198,7 @@ cfg_not_rt! { /// # Panics /// /// This function panics if there is no current signal driver set. + #[track_caller] pub(super) fn current() -> Self { panic!( "there is no signal driver running, must be called from the context of Tokio runtime or with\ diff --git a/tokio/tests/signal_panic.rs b/tokio/tests/signal_panic.rs new file mode 100644 index 00000000000..ce1ec3e4a73 --- /dev/null +++ b/tokio/tests/signal_panic.rs @@ -0,0 +1,29 @@ +#![warn(rust_2018_idioms)] +#![cfg(feature = "full")] +#![cfg(unix)] + +use std::error::Error; +use tokio::runtime::Builder; +use tokio::signal::unix::{signal, SignalKind}; + +mod support { + pub mod panic; +} +use support::panic::test_panic; + +#[test] +fn signal_panic_caller() -> Result<(), Box> { + let panic_location_file = test_panic(|| { + let rt = Builder::new_current_thread().build().unwrap(); + + rt.block_on(async { + let kind = SignalKind::from_raw(-1); + let _ = signal(kind); + }); + }); + + // The panic location should be in this file + assert_eq!(&panic_location_file.unwrap(), file!()); + + Ok(()) +}