Skip to content

Commit 4df4607

Browse files
author
Lori-Shu
authored
style(lib); fix 'undocumented_unsafe_blocks' lint (#4083)
All uses of `unsafe` now include a SAFETY comment.
1 parent 8795c33 commit 4df4607

5 files changed

Lines changed: 40 additions & 3 deletions

File tree

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ single_char_lifetime_names = "allow"
151151
single_match_else = "allow" # TODO: easy fix
152152
struct_excessive_bools = "allow" # TODO: bogus lint?
153153
trivially_copy_pass_by_ref = "allow"
154-
undocumented_unsafe_blocks = "allow" # TODO: fix me
155154
uninlined_format_args = "allow" # TODO: easy fix
156155
unnecessary_semicolon = "allow" # TODO: easy fix
157156
unnecessary_trailing_comma = "allow"

src/common/io/compat.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,21 @@ impl<T> tokio::io::AsyncRead for Compat<T>
2323
where
2424
T: crate::rt::Read,
2525
{
26+
/// `poll_read` fn implementation for `Compat<T>`.
2627
fn poll_read(
2728
self: Pin<&mut Self>,
2829
cx: &mut Context<'_>,
2930
tbuf: &mut tokio::io::ReadBuf<'_>,
3031
) -> Poll<Result<(), std::io::Error>> {
3132
let init = tbuf.initialized().len();
3233
let filled = tbuf.filled().len();
34+
// SAFETY:
35+
// 1. `tbuf.inner_mut()` returns a raw pointer/mutable slice which we wrap into
36+
// a `crate::rt::ReadBuf` that is layout-compatible with the source `tokio::io::ReadBuf`.
37+
// 2. We explicitly restore the `init` and `filled` states from the original buffer
38+
// to maintain the invariant that the new `ReadBuf` tracks the same progress.
39+
// 3. The underlying memory remains valid and uniquely accessible via `tbuf` for
40+
// the duration of this poll operation.
3341
let (new_init, new_filled) = unsafe {
3442
let mut buf = crate::rt::ReadBuf::uninit(tbuf.inner_mut());
3543
buf.set_init(init);
@@ -42,6 +50,11 @@ where
4250
};
4351

4452
let n_init = new_init - init;
53+
// SAFETY:
54+
// 1. `tbuf.assume_init(n_init)` is safe because `crate::rt::Read::poll_read`
55+
// guarantees that the bytes written into the buffer were initialized.
56+
// 2. `tbuf.set_filled(new_filled)` is safe because `new_filled` is derived
57+
// directly from the buffer state after the successful read operation.
4558
unsafe {
4659
tbuf.assume_init(n_init);
4760
tbuf.set_filled(new_filled);

src/proto/h1/role.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,16 @@ macro_rules! header_name {
4343
}
4444
}};
4545
}
46-
46+
/// construct `HeaderValue` from a maybe shared expression.
4747
macro_rules! header_value {
4848
($bytes:expr) => {{
4949
{
50+
// unsafe used because of the call of `HeaderValue::from_maybe_shared_unchecked`.
51+
// SAFETY:
52+
// 1. The input `$bytes` must be a valid header value as per RFC 7230.
53+
// 2. Specifically, it must not contain any prohibited characters (like `\r`, `\n`, or non-visible ASCII characters outside of allowed ranges).
54+
// 3. This is safe because the caller is responsible for ensuring the byte content
55+
// has been validated or is known to be a constant/static valid header value.
5056
unsafe { HeaderValue::from_maybe_shared_unchecked($bytes) }
5157
}
5258
}};

src/rt/timer.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,15 @@ impl dyn Sleep {
116116
T: Sleep + 'static,
117117
{
118118
if self.is::<T>() {
119+
// SAFETY:
120+
// 1. `self.is::<T>()` guarantees that the underlying object is indeed of type `T`.
121+
// 2. We use `Pin::into_inner_unchecked` to gain mutable access to the underlying
122+
// value because we are maintaining the pinning contract.
123+
// 3. We convert the reference to `dyn Sleep` to a reference to `T` via raw pointers.
124+
// Since we've verified the type, this is a sound downcast.
125+
// 4. `Pin::new_unchecked` is safe here because the original object was already pinned,
126+
// and by pinning the downcasted reference, we continue to uphold the pinning guarantee
127+
// that the object will not be moved.
119128
unsafe {
120129
let inner = Pin::into_inner_unchecked(self);
121130
Some(Pin::new_unchecked(

src/upgrade.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,10 +301,20 @@ impl dyn Io + Send {
301301
let t = TypeId::of::<T>();
302302
self.__hyper_type_id() == t
303303
}
304-
304+
/// downcast a Box wrapped Type to a Box<T>
305+
/// implemented by raw pointer cast.
305306
fn __hyper_downcast<T: Io>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
306307
if self.__hyper_is::<T>() {
307308
// Taken from `std::error::Error::downcast()`.
309+
// SAFETY:
310+
// 1. `self.__hyper_is::<T>()` performs a runtime type check (typically via `TypeId`),
311+
// guaranteeing that the underlying concrete type is indeed `T`.
312+
// 2. We use `Box::into_raw` to obtain a pointer to the trait object, which
313+
// has the same memory layout as the underlying concrete type `T` at the
314+
// location identified by the runtime check.
315+
// 3. `Box::from_raw` is safe to call here because we are reconstructing the
316+
// box from the pointer that was originally created by `Box::into_raw`,
317+
// and the type `T` matches the original type of the allocated memory.
308318
unsafe {
309319
let raw: *mut dyn Io = Box::into_raw(self);
310320
Ok(Box::from_raw(raw.cast()))

0 commit comments

Comments
 (0)