Skip to content

Commit 95a9783

Browse files
authored
refactor(http1): use MaybeUninit for parsing with uninitialized headers (#2545)
Closes #2532
1 parent be08648 commit 95a9783

File tree

1 file changed

+38
-17
lines changed

1 file changed

+38
-17
lines changed

src/proto/h1/role.rs

+38-17
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
// `mem::uninitialized` replaced with `mem::MaybeUninit`,
2-
// can't upgrade yet
3-
#![allow(deprecated)]
4-
51
use std::fmt::{self, Write};
6-
use std::mem;
2+
use std::mem::{self, MaybeUninit};
73

84
#[cfg(any(test, feature = "server", feature = "ffi"))]
95
use bytes::Bytes;
@@ -115,17 +111,23 @@ impl Http1Transaction for Server {
115111
// but we *never* read any of it until after httparse has assigned
116112
// values into it. By not zeroing out the stack memory, this saves
117113
// a good ~5% on pipeline benchmarks.
118-
let mut headers_indices: [HeaderIndices; MAX_HEADERS] = unsafe { mem::uninitialized() };
114+
let mut headers_indices: [MaybeUninit<HeaderIndices>; MAX_HEADERS] = unsafe {
115+
// SAFETY: We can go safely from MaybeUninit array to array of MaybeUninit
116+
MaybeUninit::uninit().assume_init()
117+
};
119118
{
120-
let mut headers: [httparse::Header<'_>; MAX_HEADERS] = unsafe { mem::uninitialized() };
119+
/* SAFETY: it is safe to go from MaybeUninit array to array of MaybeUninit */
120+
let mut headers: [MaybeUninit<httparse::Header<'_>>; MAX_HEADERS] = unsafe {
121+
MaybeUninit::uninit().assume_init()
122+
};
121123
trace!(
122124
"Request.parse([Header; {}], [u8; {}])",
123125
headers.len(),
124126
buf.len()
125127
);
126-
let mut req = httparse::Request::new(&mut headers);
128+
let mut req = httparse::Request::new(&mut []);
127129
let bytes = buf.as_ref();
128-
match req.parse(bytes) {
130+
match req.parse_with_uninit_headers(bytes, &mut headers) {
129131
Ok(httparse::Status::Complete(parsed_len)) => {
130132
trace!("Request.parse Complete({})", parsed_len);
131133
len = parsed_len;
@@ -194,6 +196,8 @@ impl Http1Transaction for Server {
194196
headers.reserve(headers_len);
195197

196198
for header in &headers_indices[..headers_len] {
199+
// SAFETY: array is valid up to `headers_len`
200+
let header = unsafe { &*header.as_ptr() };
197201
let name = header_name!(&slice[header.name.0..header.name.1]);
198202
let value = header_value!(slice.slice(header.value.0..header.value.1));
199203

@@ -867,18 +871,24 @@ impl Http1Transaction for Client {
867871
// Loop to skip information status code headers (100 Continue, etc).
868872
loop {
869873
// Unsafe: see comment in Server Http1Transaction, above.
870-
let mut headers_indices: [HeaderIndices; MAX_HEADERS] = unsafe { mem::uninitialized() };
874+
let mut headers_indices: [MaybeUninit<HeaderIndices>; MAX_HEADERS] = unsafe {
875+
// SAFETY: We can go safely from MaybeUninit array to array of MaybeUninit
876+
MaybeUninit::uninit().assume_init()
877+
};
871878
let (len, status, reason, version, headers_len) = {
872-
let mut headers: [httparse::Header<'_>; MAX_HEADERS] =
873-
unsafe { mem::uninitialized() };
879+
// SAFETY: We can go safely from MaybeUninit array to array of MaybeUninit
880+
let mut headers: [MaybeUninit<httparse::Header<'_>>; MAX_HEADERS] =
881+
unsafe { MaybeUninit::uninit().assume_init() };
874882
trace!(
875883
"Response.parse([Header; {}], [u8; {}])",
876884
headers.len(),
877885
buf.len()
878886
);
879-
let mut res = httparse::Response::new(&mut headers);
887+
let mut res = httparse::Response::new(&mut []);
880888
let bytes = buf.as_ref();
881-
match ctx.h1_parser_config.parse_response(&mut res, bytes) {
889+
match ctx.h1_parser_config
890+
.parse_response_with_uninit_headers(&mut res, bytes, &mut headers)
891+
{
882892
Ok(httparse::Status::Complete(len)) => {
883893
trace!("Response.parse Complete({})", len);
884894
let status = StatusCode::from_u16(res.code.unwrap())?;
@@ -934,6 +944,8 @@ impl Http1Transaction for Client {
934944

935945
headers.reserve(headers_len);
936946
for header in &headers_indices[..headers_len] {
947+
// SAFETY: array is valid up to `headers_len`
948+
let header = unsafe { &*header.as_ptr() };
937949
let name = header_name!(&slice[header.name.0..header.name.1]);
938950
let value = header_value!(slice.slice(header.value.0..header.value.1));
939951

@@ -1288,7 +1300,7 @@ struct HeaderIndices {
12881300
fn record_header_indices(
12891301
bytes: &[u8],
12901302
headers: &[httparse::Header<'_>],
1291-
indices: &mut [HeaderIndices],
1303+
indices: &mut [MaybeUninit<HeaderIndices>],
12921304
) -> Result<(), crate::error::Parse> {
12931305
let bytes_ptr = bytes.as_ptr() as usize;
12941306

@@ -1299,10 +1311,19 @@ fn record_header_indices(
12991311
}
13001312
let name_start = header.name.as_ptr() as usize - bytes_ptr;
13011313
let name_end = name_start + header.name.len();
1302-
indices.name = (name_start, name_end);
13031314
let value_start = header.value.as_ptr() as usize - bytes_ptr;
13041315
let value_end = value_start + header.value.len();
1305-
indices.value = (value_start, value_end);
1316+
1317+
// FIXME(maybe_uninit_extra)
1318+
// FIXME(addr_of)
1319+
// Currently we don't have `ptr::addr_of_mut` in stable rust or
1320+
// MaybeUninit::write, so this is some way of assigning into a MaybeUninit
1321+
// safely
1322+
let new_header_indices = HeaderIndices {
1323+
name: (name_start, name_end),
1324+
value: (value_start, value_end),
1325+
};
1326+
*indices = MaybeUninit::new(new_header_indices);
13061327
}
13071328

13081329
Ok(())

0 commit comments

Comments
 (0)