From d6ac5f8947b89a21d3192f8689483ff3be4f8aea Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Tue, 12 Nov 2024 23:53:45 -0500 Subject: [PATCH] Avoid over allocations & reallocations As we know, vectors amortize the cost of adding new elements by reserving space for multiple elements when full. This is useful but may lead to allocating more memory than necessary. `relibc` generally avoids over allocations by reserving the exact amount of space when possible. I fixed a few areas that still over allocated or reallocated unnecessarily by leveraging iterators that are more likely to know sizes. --- src/header/netdb/host.rs | 19 +++------ src/header/netdb/lookup.rs | 86 ++++++++++++++++++++------------------ src/header/netdb/mod.rs | 43 +++++++------------ src/header/unistd/mod.rs | 7 +++- src/platform/linux/mod.rs | 5 +-- src/platform/redox/exec.rs | 3 +- 6 files changed, 74 insertions(+), 89 deletions(-) diff --git a/src/header/netdb/host.rs b/src/header/netdb/host.rs index 576f8d0593..d16ddb02d2 100644 --- a/src/header/netdb/host.rs +++ b/src/header/netdb/host.rs @@ -78,8 +78,7 @@ pub unsafe extern "C" fn gethostent() -> *mut hostent { let mut iter: SplitWhitespace = r.split_whitespace(); - let mut addr_vec = iter.next().unwrap().as_bytes().to_vec(); - addr_vec.push(b'\0'); + let addr_vec: Vec = iter.next().unwrap().bytes().chain(Some(b'\0')).collect(); let addr_cstr = addr_vec.as_slice().as_ptr() as *const i8; let mut addr = mem::MaybeUninit::uninit(); inet_aton(addr_cstr, addr.as_mut_ptr()); @@ -90,16 +89,11 @@ pub unsafe extern "C" fn gethostent() -> *mut hostent { HOST_ADDR = Some(addr); - let mut host_name = iter.next().unwrap().as_bytes().to_vec(); - host_name.push(b'\0'); + let host_name = iter.next().unwrap().bytes().chain(Some(b'\0')).collect(); - let mut _host_aliases: Vec> = Vec::new(); - - for s in iter { - let mut alias = s.as_bytes().to_vec(); - alias.push(b'\0'); - _host_aliases.push(alias); - } + let mut _host_aliases: Vec> = iter + .map(|alias| alias.bytes().chain(Some(b'\0')).collect()) + .collect(); HOST_ALIASES = Some(_host_aliases); let mut host_aliases: Vec<*mut i8> = HOST_ALIASES @@ -107,9 +101,8 @@ pub unsafe extern "C" fn gethostent() -> *mut hostent { .unwrap() .iter_mut() .map(|x| x.as_mut_ptr() as *mut i8) + .chain([ptr::null_mut(), ptr::null_mut()]) .collect(); - host_aliases.push(ptr::null_mut()); - host_aliases.push(ptr::null_mut()); HOST_NAME = Some(host_name); diff --git a/src/header/netdb/lookup.rs b/src/header/netdb/lookup.rs index e2cfd60696..4b267b2943 100644 --- a/src/header/netdb/lookup.rs +++ b/src/header/netdb/lookup.rs @@ -107,21 +107,28 @@ pub fn lookup_host(host: &str) -> Result { match Dns::parse(&buf[..count as usize]) { Ok(response) => { - let mut addrs = vec![]; - for answer in response.answers.iter() { - if answer.a_type == 0x0001 && answer.a_class == 0x0001 && answer.data.len() == 4 - { - let addr = in_addr { - s_addr: u32::from_ne_bytes([ - answer.data[0], - answer.data[1], - answer.data[2], - answer.data[3], - ]), - }; - addrs.push(addr); - } - } + let addrs: Vec<_> = response + .answers + .into_iter() + .filter_map(|answer| { + if answer.a_type == 0x0001 + && answer.a_class == 0x0001 + && answer.data.len() == 4 + { + let addr = in_addr { + s_addr: u32::from_ne_bytes([ + answer.data[0], + answer.data[1], + answer.data[2], + answer.data[3], + ]), + }; + Some(addr) + } else { + None + } + }) + .collect(); Ok(LookupHost(addrs.into_iter())) } Err(_err) => Err(EINVAL), @@ -146,19 +153,12 @@ pub fn lookup_addr(addr: in_addr) -> Result>, c_int> { dns_arr[i] = *octet; } - let mut addr_vec: Vec = addr.s_addr.to_ne_bytes().to_vec(); - addr_vec.reverse(); - let mut name: Vec = vec![]; - for octet in addr_vec { - for ch in format!("{}", octet).as_bytes() { - name.push(*ch); - } - name.push(b"."[0]); - } - name.pop(); - for ch in b".IN-ADDR.ARPA" { - name.push(*ch); - } + let addr: [u8; 4] = addr.s_addr.to_ne_bytes(); + // Address intentionally backwards for reverse lookup + let name = format!( + "{}.{}.{}.{}.in-addr.arpa", + addr[3], addr[2], addr[1], addr[0] + ); if dns_vec.len() == 4 { let mut timespec = timespec::default(); @@ -169,7 +169,7 @@ pub fn lookup_addr(addr: in_addr) -> Result>, c_int> { transaction_id: tid, flags: 0x0100, queries: vec![DnsQuery { - name: String::from_utf8(name).unwrap(), + name, q_type: 0x000C, q_class: 0x0001, }], @@ -221,18 +221,22 @@ pub fn lookup_addr(addr: in_addr) -> Result>, c_int> { match Dns::parse(&buf[..count as usize]) { Ok(response) => { - let mut names = vec![]; - for answer in response.answers.iter() { - if answer.a_type == 0x000C && answer.a_class == 0x0001 { - // answer.data is encoded kinda weird. - // Basically length-prefixed strings for each - // subsection of the domain. - // We need to parse this to insert periods where - // they belong (ie at the end of each string) - let data = parse_revdns_answer(&answer.data); - names.push(data); - } - } + let names = response + .answers + .into_iter() + .filter_map(|answer| { + if answer.a_type == 0x000C && answer.a_class == 0x0001 { + // answer.data is encoded kinda weird. + // Basically length-prefixed strings for each + // subsection of the domain. + // We need to parse this to insert periods where + // they belong (ie at the end of each string) + Some(parse_revdns_answer(&answer.data)) + } else { + None + } + }) + .collect(); Ok(names) } Err(_err) => Err(EINVAL), diff --git a/src/header/netdb/mod.rs b/src/header/netdb/mod.rs index c01579af9e..d9d2f8103b 100644 --- a/src/header/netdb/mod.rs +++ b/src/header/netdb/mod.rs @@ -462,29 +462,24 @@ pub unsafe extern "C" fn getnetent() -> *mut netent { let mut iter: SplitWhitespace = r.split_whitespace(); - let mut net_name = iter.next().unwrap().as_bytes().to_vec(); - net_name.push(b'\0'); + let net_name = iter.next().unwrap().bytes().chain(Some(b'\0')).collect(); NET_NAME = Some(net_name); - let mut addr_vec = iter.next().unwrap().as_bytes().to_vec(); - addr_vec.push(b'\0'); + let addr_vec: Vec = iter.next().unwrap().bytes().chain(Some(b'\0')).collect(); let addr_cstr = addr_vec.as_slice().as_ptr() as *const i8; let mut addr = mem::MaybeUninit::uninit(); inet_aton(addr_cstr, addr.as_mut_ptr()); let addr = addr.assume_init(); NET_ADDR = Some(ntohl(addr.s_addr)); - let mut _net_aliases: Vec> = Vec::new(); - for s in iter { - let mut alias = s.as_bytes().to_vec(); - alias.push(b'\0'); - _net_aliases.push(alias); - } + let mut _net_aliases: Vec> = iter + .map(|alias| alias.bytes().chain(Some(b'\0')).collect()) + .collect(); let mut net_aliases: Vec<*mut i8> = _net_aliases .iter_mut() .map(|x| x.as_mut_ptr() as *mut i8) + .chain(Some(ptr::null_mut())) .collect(); - net_aliases.push(ptr::null_mut()); NET_ALIASES = Some(_net_aliases); NET_ENTRY = netent { @@ -583,17 +578,14 @@ pub unsafe extern "C" fn getprotoent() -> *mut protoent { num.push(b'\0'); PROTO_NUM = Some(atoi(num.as_mut_slice().as_mut_ptr() as *mut i8)); - let mut _proto_aliases: Vec> = Vec::new(); - for s in iter { - let mut alias = s.as_bytes().to_vec(); - alias.push(b'\0'); - _proto_aliases.push(alias); - } + let mut _proto_aliases: Vec> = iter + .map(|alias| alias.bytes().chain(Some(b'\0')).collect()) + .collect(); let mut proto_aliases: Vec<*mut i8> = _proto_aliases .iter_mut() .map(|x| x.as_mut_ptr() as *mut i8) + .chain(Some(ptr::null_mut())) .collect(); - proto_aliases.push(ptr::null_mut()); PROTO_ALIASES = Some(_proto_aliases); PROTO_NAME = Some(proto_name); @@ -692,28 +684,25 @@ pub unsafe extern "C" fn getservent() -> *mut servent { }; let mut iter = r.split_whitespace(); - let mut serv_name = match iter.next() { - Some(serv_name) => serv_name.as_bytes().to_vec(), + let serv_name = match iter.next() { + Some(serv_name) => serv_name.bytes().chain(Some(b'\0')).collect(), None => continue, }; - serv_name.push(b'\0'); let port_proto = match iter.next() { Some(port_proto) => port_proto, None => continue, }; let mut split = port_proto.split('/'); - let mut port = match split.next() { - Some(port) => port.as_bytes().to_vec(), + let mut port: Vec = match split.next() { + Some(port) => port.bytes().chain(Some(b'\0')).collect(), None => continue, }; - port.push(b'\0'); SERV_PORT = Some(htons(atoi(port.as_mut_slice().as_mut_ptr() as *mut i8) as u16) as u32 as i32); - let mut proto = match split.next() { - Some(proto) => proto.as_bytes().to_vec(), + let proto = match split.next() { + Some(proto) => proto.bytes().chain(Some(b'\0')).collect(), None => continue, }; - proto.push(b'\0'); rlb.next(); S_POS = rlb.line_pos(); diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs index df8f8c6fa6..19a09373ee 100644 --- a/src/header/unistd/mod.rs +++ b/src/header/unistd/mod.rs @@ -308,9 +308,12 @@ pub unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) - if !path_env.is_null() { let path_env = CStr::from_ptr(path_env); for path in path_env.to_bytes().split(|&b| b == PATH_SEPARATOR) { - let mut program = path.to_vec(); + let file = file.to_bytes(); + let length = file.len() + path.len() + 2; + let mut program = alloc::vec::Vec::with_capacity(length); + program.extend_from_slice(path); program.push(b'/'); - program.extend_from_slice(file.to_bytes()); + program.extend_from_slice(file); program.push(b'\0'); let program_c = CStr::from_bytes_with_nul(&program).unwrap(); diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 541c9430ad..86ae1af3b7 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -219,10 +219,7 @@ impl Pal for Sys { } fn fpath(fildes: c_int, out: &mut [u8]) -> Result { - let mut proc_path = b"/proc/self/fd/".to_vec(); - write!(proc_path, "{}", fildes).unwrap(); - proc_path.push(0); - + let proc_path = format!("/proc/self/fd/{}\0", fildes).into_bytes(); Self::readlink(CStr::from_bytes_with_nul(&proc_path).unwrap(), out) } diff --git a/src/platform/redox/exec.rs b/src/platform/redox/exec.rs index 990502bdd6..da7bb4e640 100644 --- a/src/platform/redox/exec.rs +++ b/src/platform/redox/exec.rs @@ -337,8 +337,7 @@ where { let mut vec = Vec::new(); for item in iter { - vec.extend(item.as_ref()); - vec.push(b'\0'); + vec.extend(item.as_ref().iter().copied().chain(Some(b'\0'))); } vec.into_boxed_slice() }