signal: add track_caller to public APIs (#4806)

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
This commit is contained in:
Hayden Stainsby 2022-07-06 12:16:12 +02:00 committed by GitHub
parent d8cad13fd9
commit 18efef7d3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 0 deletions

View File

@ -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())?;

View File

@ -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\

View File

@ -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(())
}