Skip to content

Commit

Permalink
signal: add track_caller to public APIs (#4806)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
hds committed Jul 6, 2022
1 parent d8cad13 commit 18efef7
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 0 deletions.
6 changes: 6 additions & 0 deletions tokio/src/signal/unix.rs
Expand Up @@ -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<Signal> {
let rx = signal_with_handle(kind, &Handle::current())?;

Expand Down
2 changes: 2 additions & 0 deletions tokio/src/signal/unix/driver.rs
Expand Up @@ -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",
Expand All @@ -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\
Expand Down
29 changes: 29 additions & 0 deletions 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<dyn Error>> {
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(())
}

0 comments on commit 18efef7

Please sign in to comment.