From f9cb0252d0e8be7fc48bbde73a9ed763edb46277 Mon Sep 17 00:00:00 2001 From: Lori-Shu Date: Wed, 27 May 2026 15:10:58 +0800 Subject: [PATCH 1/4] Removing wildcard_imports lint allowance The wildcard_imports used in http1.rs is replaced with explict type imports. --- Cargo.toml | 1 - src/client/conn/http1.rs | 11 ++++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fbb8031adb..af23c7e570 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -169,7 +169,6 @@ unused_trait_names = "allow" # TODO: kinda annoying, but might be good to deny unwrap_in_result = "allow" useless_borrows_in_formatting = "allow" wildcard_enum_match_arm = "allow" -wildcard_imports = "allow" # TODO: never, except for tests # explicitly allowed absolute_paths = "allow" # sometimes its cleaner diff --git a/src/client/conn/http1.rs b/src/client/conn/http1.rs index 433cfaf160..b78757b9ca 100644 --- a/src/client/conn/http1.rs +++ b/src/client/conn/http1.rs @@ -591,10 +591,11 @@ impl Builder { } mod upgrades { + use super::{Connection, Context, Future, Parts, Pin, Poll, Read, StdError, Write}; + use crate::body::Body; + use crate::proto::Dispatched; use crate::upgrade::Upgraded; - - use super::*; - + use futures_core::ready; // A future binding a connection with a Service with Upgrade support. // // This type is unnameable outside the crate. @@ -628,8 +629,8 @@ mod upgrades { ) .poll(cx)) { - Ok(proto::Dispatched::Shutdown) => Poll::Ready(Ok(())), - Ok(proto::Dispatched::Upgrade(pending)) => { + Ok(Dispatched::Shutdown) => Poll::Ready(Ok(())), + Ok(Dispatched::Upgrade(pending)) => { let Parts { io, read_buf } = self .inner .take() From 0c36385eb2200e83af4dc931685371329ef4adf5 Mon Sep 17 00:00:00 2001 From: Lori-Shu Date: Thu, 28 May 2026 12:55:30 +0800 Subject: [PATCH 2/4] Removing 'undocumented_unsafe_blocks' lint allowance --- Cargo.toml | 1 - src/common/io/compat.rs | 7 +++++++ src/proto/h1/role.rs | 4 +++- src/rt/timer.rs | 2 ++ src/upgrade.rs | 5 ++++- 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2c73a64f6e..0b44c3e99e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -158,7 +158,6 @@ single_char_lifetime_names = "allow" single_match_else = "allow" # TODO: easy fix struct_excessive_bools = "allow" # TODO: bogus lint? trivially_copy_pass_by_ref = "allow" -undocumented_unsafe_blocks = "allow" # TODO: fix me uninlined_format_args = "allow" # TODO: easy fix unnecessary_semicolon = "allow" # TODO: easy fix unnecessary_trailing_comma = "allow" diff --git a/src/common/io/compat.rs b/src/common/io/compat.rs index d026b6d38b..58016c218a 100644 --- a/src/common/io/compat.rs +++ b/src/common/io/compat.rs @@ -23,6 +23,7 @@ impl tokio::io::AsyncRead for Compat where T: crate::rt::Read, { + /// `poll_read` fn implementation for `Compat`. fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, @@ -30,6 +31,9 @@ where ) -> Poll> { let init = tbuf.initialized().len(); let filled = tbuf.filled().len(); + // SAFETY: + // this is an unsafe block which calls unsafe functions: + // `ReadBuf::inner_mut`, `ReadBuf::set_init`, `ReadBuf::set_filled`. let (new_init, new_filled) = unsafe { let mut buf = crate::rt::ReadBuf::uninit(tbuf.inner_mut()); buf.set_init(init); @@ -42,6 +46,9 @@ where }; let n_init = new_init - init; + // SAFETY: + // this is an unsafe block which calls unsafe functions: + // `ReadBuf::assume_init`, `ReadBuf::set_filled`. unsafe { tbuf.assume_init(n_init); tbuf.set_filled(new_filled); diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs index 544f16ef80..fa2c3826d5 100644 --- a/src/proto/h1/role.rs +++ b/src/proto/h1/role.rs @@ -43,10 +43,12 @@ macro_rules! header_name { } }}; } - +/// construct `HeaderValue` from a maybe shared expression. macro_rules! header_value { ($bytes:expr) => {{ { + // SAFETY: + // this is unsafe because of the call of `HeaderValue::from_maybe_shared_unchecked`. unsafe { HeaderValue::from_maybe_shared_unchecked($bytes) } } }}; diff --git a/src/rt/timer.rs b/src/rt/timer.rs index 944e5d34f7..5f156b069f 100644 --- a/src/rt/timer.rs +++ b/src/rt/timer.rs @@ -116,6 +116,8 @@ impl dyn Sleep { T: Sleep + 'static, { if self.is::() { + // SAFETY: + // this is unsafe because of the call of `Pin::into_inner_unchecked` and `Pin::new_unchecked`. unsafe { let inner = Pin::into_inner_unchecked(self); Some(Pin::new_unchecked( diff --git a/src/upgrade.rs b/src/upgrade.rs index 352ed5e1c7..7b100ea33f 100644 --- a/src/upgrade.rs +++ b/src/upgrade.rs @@ -301,10 +301,13 @@ impl dyn Io + Send { let t = TypeId::of::(); self.__hyper_type_id() == t } - + /// downcast a Box wrapped Type to a Box + /// implemented by raw pointer cast. fn __hyper_downcast(self: Box) -> Result, Box> { if self.__hyper_is::() { // Taken from `std::error::Error::downcast()`. + // SAFETY: + // this is unsafe because of the call of `Box::from_raw`. unsafe { let raw: *mut dyn Io = Box::into_raw(self); Ok(Box::from_raw(raw as *mut T)) From 6f00f23619422c82ec3ba61a3bb594f81eeb553e Mon Sep 17 00:00:00 2001 From: Lori-Shu Date: Thu, 28 May 2026 15:48:25 +0800 Subject: [PATCH 3/4] Removing 'undocumented_unsafe_blocks' lint allowance --- src/common/io/compat.rs | 16 +++++++++++----- src/proto/h1/role.rs | 6 +++++- src/rt/timer.rs | 9 ++++++++- src/upgrade.rs | 9 ++++++++- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/common/io/compat.rs b/src/common/io/compat.rs index 58016c218a..877bb23919 100644 --- a/src/common/io/compat.rs +++ b/src/common/io/compat.rs @@ -31,9 +31,13 @@ where ) -> Poll> { let init = tbuf.initialized().len(); let filled = tbuf.filled().len(); - // SAFETY: - // this is an unsafe block which calls unsafe functions: - // `ReadBuf::inner_mut`, `ReadBuf::set_init`, `ReadBuf::set_filled`. + // SAFETY: + // 1. `tbuf.inner_mut()` returns a raw pointer/mutable slice which we wrap into + // a `crate::rt::ReadBuf` that is layout-compatible with the source `tokio::io::ReadBuf`. + // 2. We explicitly restore the `init` and `filled` states from the original buffer + // to maintain the invariant that the new `ReadBuf` tracks the same progress. + // 3. The underlying memory remains valid and uniquely accessible via `tbuf` for + // the duration of this poll operation. let (new_init, new_filled) = unsafe { let mut buf = crate::rt::ReadBuf::uninit(tbuf.inner_mut()); buf.set_init(init); @@ -47,8 +51,10 @@ where let n_init = new_init - init; // SAFETY: - // this is an unsafe block which calls unsafe functions: - // `ReadBuf::assume_init`, `ReadBuf::set_filled`. + // 1. `tbuf.assume_init(n_init)` is safe because `crate::rt::Read::poll_read` + // guarantees that the bytes written into the buffer were initialized. + // 2. `tbuf.set_filled(new_filled)` is safe because `new_filled` is derived + // directly from the buffer state after the successful read operation. unsafe { tbuf.assume_init(n_init); tbuf.set_filled(new_filled); diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs index fa2c3826d5..978257f856 100644 --- a/src/proto/h1/role.rs +++ b/src/proto/h1/role.rs @@ -47,8 +47,12 @@ macro_rules! header_name { macro_rules! header_value { ($bytes:expr) => {{ { + // unsafe used because of the call of `HeaderValue::from_maybe_shared_unchecked`. // SAFETY: - // this is unsafe because of the call of `HeaderValue::from_maybe_shared_unchecked`. + // 1. The input `$bytes` must be a valid header value as per RFC 7230. + // 2. Specifically, it must not contain any prohibited characters (like `\r`, `\n`, or non-visible ASCII characters outside of allowed ranges). + // 3. This is safe because the caller is responsible for ensuring the byte content + // has been validated or is known to be a constant/static valid header value. unsafe { HeaderValue::from_maybe_shared_unchecked($bytes) } } }}; diff --git a/src/rt/timer.rs b/src/rt/timer.rs index 5f156b069f..b7b8d615ef 100644 --- a/src/rt/timer.rs +++ b/src/rt/timer.rs @@ -117,7 +117,14 @@ impl dyn Sleep { { if self.is::() { // SAFETY: - // this is unsafe because of the call of `Pin::into_inner_unchecked` and `Pin::new_unchecked`. + // 1. `self.is::()` guarantees that the underlying object is indeed of type `T`. + // 2. We use `Pin::into_inner_unchecked` to gain mutable access to the underlying + // value because we are maintaining the pinning contract. + // 3. We convert the reference to `dyn Sleep` to a reference to `T` via raw pointers. + // Since we've verified the type, this is a sound downcast. + // 4. `Pin::new_unchecked` is safe here because the original object was already pinned, + // and by pinning the downcasted reference, we continue to uphold the pinning guarantee + // that the object will not be moved. unsafe { let inner = Pin::into_inner_unchecked(self); Some(Pin::new_unchecked( diff --git a/src/upgrade.rs b/src/upgrade.rs index 7b100ea33f..07f8bd8296 100644 --- a/src/upgrade.rs +++ b/src/upgrade.rs @@ -307,7 +307,14 @@ impl dyn Io + Send { if self.__hyper_is::() { // Taken from `std::error::Error::downcast()`. // SAFETY: - // this is unsafe because of the call of `Box::from_raw`. + // 1. `self.__hyper_is::()` performs a runtime type check (typically via `TypeId`), + // guaranteeing that the underlying concrete type is indeed `T`. + // 2. We use `Box::into_raw` to obtain a pointer to the trait object, which + // has the same memory layout as the underlying concrete type `T` at the + // location identified by the runtime check. + // 3. `Box::from_raw` is safe to call here because we are reconstructing the + // box from the pointer that was originally created by `Box::into_raw`, + // and the type `T` matches the original type of the allocated memory. unsafe { let raw: *mut dyn Io = Box::into_raw(self); Ok(Box::from_raw(raw as *mut T)) From 59432761b40a75e737a8b9cf6f6524692d8162aa Mon Sep 17 00:00:00 2001 From: Lori-Shu Date: Thu, 28 May 2026 15:54:34 +0800 Subject: [PATCH 4/4] Fix fmt style --- src/common/io/compat.rs | 12 ++++++------ src/proto/h1/role.rs | 2 +- src/rt/timer.rs | 4 ++-- src/upgrade.rs | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/common/io/compat.rs b/src/common/io/compat.rs index 877bb23919..c390b130c1 100644 --- a/src/common/io/compat.rs +++ b/src/common/io/compat.rs @@ -31,12 +31,12 @@ where ) -> Poll> { let init = tbuf.initialized().len(); let filled = tbuf.filled().len(); - // SAFETY: - // 1. `tbuf.inner_mut()` returns a raw pointer/mutable slice which we wrap into + // SAFETY: + // 1. `tbuf.inner_mut()` returns a raw pointer/mutable slice which we wrap into // a `crate::rt::ReadBuf` that is layout-compatible with the source `tokio::io::ReadBuf`. - // 2. We explicitly restore the `init` and `filled` states from the original buffer + // 2. We explicitly restore the `init` and `filled` states from the original buffer // to maintain the invariant that the new `ReadBuf` tracks the same progress. - // 3. The underlying memory remains valid and uniquely accessible via `tbuf` for + // 3. The underlying memory remains valid and uniquely accessible via `tbuf` for // the duration of this poll operation. let (new_init, new_filled) = unsafe { let mut buf = crate::rt::ReadBuf::uninit(tbuf.inner_mut()); @@ -51,9 +51,9 @@ where let n_init = new_init - init; // SAFETY: - // 1. `tbuf.assume_init(n_init)` is safe because `crate::rt::Read::poll_read` + // 1. `tbuf.assume_init(n_init)` is safe because `crate::rt::Read::poll_read` // guarantees that the bytes written into the buffer were initialized. - // 2. `tbuf.set_filled(new_filled)` is safe because `new_filled` is derived + // 2. `tbuf.set_filled(new_filled)` is safe because `new_filled` is derived // directly from the buffer state after the successful read operation. unsafe { tbuf.assume_init(n_init); diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs index 978257f856..cf4ff8cc16 100644 --- a/src/proto/h1/role.rs +++ b/src/proto/h1/role.rs @@ -51,7 +51,7 @@ macro_rules! header_value { // SAFETY: // 1. The input `$bytes` must be a valid header value as per RFC 7230. // 2. Specifically, it must not contain any prohibited characters (like `\r`, `\n`, or non-visible ASCII characters outside of allowed ranges). - // 3. This is safe because the caller is responsible for ensuring the byte content + // 3. This is safe because the caller is responsible for ensuring the byte content // has been validated or is known to be a constant/static valid header value. unsafe { HeaderValue::from_maybe_shared_unchecked($bytes) } } diff --git a/src/rt/timer.rs b/src/rt/timer.rs index b7b8d615ef..e577379352 100644 --- a/src/rt/timer.rs +++ b/src/rt/timer.rs @@ -118,9 +118,9 @@ impl dyn Sleep { if self.is::() { // SAFETY: // 1. `self.is::()` guarantees that the underlying object is indeed of type `T`. - // 2. We use `Pin::into_inner_unchecked` to gain mutable access to the underlying + // 2. We use `Pin::into_inner_unchecked` to gain mutable access to the underlying // value because we are maintaining the pinning contract. - // 3. We convert the reference to `dyn Sleep` to a reference to `T` via raw pointers. + // 3. We convert the reference to `dyn Sleep` to a reference to `T` via raw pointers. // Since we've verified the type, this is a sound downcast. // 4. `Pin::new_unchecked` is safe here because the original object was already pinned, // and by pinning the downcasted reference, we continue to uphold the pinning guarantee diff --git a/src/upgrade.rs b/src/upgrade.rs index 07f8bd8296..8e1c33f6db 100644 --- a/src/upgrade.rs +++ b/src/upgrade.rs @@ -309,11 +309,11 @@ impl dyn Io + Send { // SAFETY: // 1. `self.__hyper_is::()` performs a runtime type check (typically via `TypeId`), // guaranteeing that the underlying concrete type is indeed `T`. - // 2. We use `Box::into_raw` to obtain a pointer to the trait object, which - // has the same memory layout as the underlying concrete type `T` at the + // 2. We use `Box::into_raw` to obtain a pointer to the trait object, which + // has the same memory layout as the underlying concrete type `T` at the // location identified by the runtime check. - // 3. `Box::from_raw` is safe to call here because we are reconstructing the - // box from the pointer that was originally created by `Box::into_raw`, + // 3. `Box::from_raw` is safe to call here because we are reconstructing the + // box from the pointer that was originally created by `Box::into_raw`, // and the type `T` matches the original type of the allocated memory. unsafe { let raw: *mut dyn Io = Box::into_raw(self);