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.
This commit is contained in:
Josh Megnauth
2024-11-12 23:53:45 -05:00
parent a45c7b26d9
commit d6ac5f8947
6 changed files with 74 additions and 89 deletions
+6 -13
View File
@@ -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<u8> = 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<u8>> = 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<Vec<u8>> = 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);
+45 -41
View File
@@ -107,21 +107,28 @@ pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
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<Vec<Vec<u8>>, c_int> {
dns_arr[i] = *octet;
}
let mut addr_vec: Vec<u8> = addr.s_addr.to_ne_bytes().to_vec();
addr_vec.reverse();
let mut name: Vec<u8> = 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<Vec<Vec<u8>>, 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<Vec<Vec<u8>>, 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),
+16 -27
View File
@@ -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<u8> = 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<u8>> = 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<Vec<u8>> = 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<u8>> = 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<Vec<u8>> = 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<u8> = 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();
+5 -2
View File
@@ -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();
+1 -4
View File
@@ -219,10 +219,7 @@ impl Pal for Sys {
}
fn fpath(fildes: c_int, out: &mut [u8]) -> Result<usize> {
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)
}
+1 -2
View File
@@ -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()
}