perf: costly zero initialization of buffer
- Dominant language
- Rust
- Stars
- 85
- Forks
- 19
- Avg merge
- 2h
- Merged PRs (30d)
- 2
Description
The `hyper::io::Read::poll_read` implementation for `HyperStream` currently zero initializes the uninitialized `ReadBufCursor` and then passes it to `futures_util::AsyncRead::poll_read` implementation for `MaybeTlsStream`.
Tokio performs the following cast before passing its buffer to `std::io::Read::read`
```rust
let b = unsafe { &mut *(buf.unfilled_mut() as *mut [std::mem::MaybeUninit] as *mut [u8]) };
```
Is it not UB according to Rust's memory model as the compiler may make any assumption based on the information that it is properly initialized? I think it works because we advance the cursor according to the number of bytes read and read only from the initialized portion from there onwards and also there's no other way to prevent the zero initialization and still be using `std::io::Read::read`.
Are we not doing the same cast keeping in mind the UB?
If that's not the case, maybe we can also do the cast to prevent the zero initialization the way tokio does and then pass the buffer to `futures_util::AsyncRead::poll_read`, get the number of bytes that have been read and then advance the cursor accordingly.
Contributor guide
Research direction
Locate the HyperStream `poll_read` implementation and trace how its `ReadBufCursor` is passed to `futures_util::AsyncRead::poll_read` for `MaybeTlsStream`. Compare this with Tokio's `MaybeUninit` to `u8` cast and determine whether the proposed optimization is sound under Rust's memory model. Done means reaching a documented safety decision and adding the corresponding implementation or tests if warranted.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- networking, performance
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100