Skip to content

Commit 748a828

Browse files
authored
Add methods for reading into unitialized buffers (#944)
* Uninitialized slices for getrandom * Implement uninitialized reads for read syscall * Add initialized reads for net methods Signed-off-by: John Nunley <[email protected]>
1 parent 56acc55 commit 748a828

File tree

14 files changed

+335
-147
lines changed

14 files changed

+335
-147
lines changed

src/backend/libc/io/syscalls.rs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,8 @@ use {
2626
crate::io::{IoSlice, IoSliceMut},
2727
};
2828

29-
pub(crate) fn read(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> {
30-
unsafe {
31-
ret_usize(c::read(
32-
borrowed_fd(fd),
33-
buf.as_mut_ptr().cast(),
34-
min(buf.len(), READ_LIMIT),
35-
))
36-
}
29+
pub(crate) unsafe fn read(fd: BorrowedFd<'_>, buf: *mut u8, len: usize) -> io::Result<usize> {
30+
ret_usize(c::read(borrowed_fd(fd), buf.cast(), min(len, READ_LIMIT)))
3731
}
3832

3933
pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> {
@@ -46,8 +40,13 @@ pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> {
4640
}
4741
}
4842

49-
pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], offset: u64) -> io::Result<usize> {
50-
let len = min(buf.len(), READ_LIMIT);
43+
pub(crate) unsafe fn pread(
44+
fd: BorrowedFd<'_>,
45+
buf: *mut u8,
46+
len: usize,
47+
offset: u64,
48+
) -> io::Result<usize> {
49+
let len = min(len, READ_LIMIT);
5150

5251
// Silently cast; we'll get `EINVAL` if the value is negative.
5352
let offset = offset as i64;
@@ -56,14 +55,7 @@ pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], offset: u64) -> io::Resu
5655
#[cfg(any(target_os = "espidf", target_os = "vita"))]
5756
let offset: i32 = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?;
5857

59-
unsafe {
60-
ret_usize(c::pread(
61-
borrowed_fd(fd),
62-
buf.as_mut_ptr().cast(),
63-
len,
64-
offset,
65-
))
66-
}
58+
ret_usize(c::pread(borrowed_fd(fd), buf.cast(), len, offset))
6759
}
6860

6961
pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], offset: u64) -> io::Result<usize> {

src/backend/libc/net/syscalls.rs

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,18 @@ use {
3131
};
3232

3333
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
34-
pub(crate) fn recv(fd: BorrowedFd<'_>, buf: &mut [u8], flags: RecvFlags) -> io::Result<usize> {
35-
unsafe {
36-
ret_send_recv(c::recv(
37-
borrowed_fd(fd),
38-
buf.as_mut_ptr().cast(),
39-
send_recv_len(buf.len()),
40-
bitflags_bits!(flags),
41-
))
42-
}
34+
pub(crate) unsafe fn recv(
35+
fd: BorrowedFd<'_>,
36+
buf: *mut u8,
37+
len: usize,
38+
flags: RecvFlags,
39+
) -> io::Result<usize> {
40+
ret_send_recv(c::recv(
41+
borrowed_fd(fd),
42+
buf.cast(),
43+
send_recv_len(len),
44+
bitflags_bits!(flags),
45+
))
4346
}
4447

4548
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
@@ -55,35 +58,34 @@ pub(crate) fn send(fd: BorrowedFd<'_>, buf: &[u8], flags: SendFlags) -> io::Resu
5558
}
5659

5760
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
58-
pub(crate) fn recvfrom(
61+
pub(crate) unsafe fn recvfrom(
5962
fd: BorrowedFd<'_>,
60-
buf: &mut [u8],
63+
buf: *mut u8,
64+
buf_len: usize,
6165
flags: RecvFlags,
6266
) -> io::Result<(usize, Option<SocketAddrAny>)> {
63-
unsafe {
64-
let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit();
65-
let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t;
66-
67-
// `recvfrom` does not write to the storage if the socket is
68-
// connection-oriented sockets, so we initialize the family field to
69-
// `AF_UNSPEC` so that we can detect this case.
70-
initialize_family_to_unspec(storage.as_mut_ptr());
71-
72-
ret_send_recv(c::recvfrom(
73-
borrowed_fd(fd),
74-
buf.as_mut_ptr().cast(),
75-
send_recv_len(buf.len()),
76-
bitflags_bits!(flags),
77-
storage.as_mut_ptr().cast(),
78-
&mut len,
79-
))
80-
.map(|nread| {
81-
(
82-
nread,
83-
maybe_read_sockaddr_os(storage.as_ptr(), len.try_into().unwrap()),
84-
)
85-
})
86-
}
67+
let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit();
68+
let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t;
69+
70+
// `recvfrom` does not write to the storage if the socket is
71+
// connection-oriented sockets, so we initialize the family field to
72+
// `AF_UNSPEC` so that we can detect this case.
73+
initialize_family_to_unspec(storage.as_mut_ptr());
74+
75+
ret_send_recv(c::recvfrom(
76+
borrowed_fd(fd),
77+
buf.cast(),
78+
send_recv_len(buf_len),
79+
bitflags_bits!(flags),
80+
storage.as_mut_ptr().cast(),
81+
&mut len,
82+
))
83+
.map(|nread| {
84+
(
85+
nread,
86+
maybe_read_sockaddr_os(storage.as_ptr(), len.try_into().unwrap()),
87+
)
88+
})
8789
}
8890

8991
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]

src/backend/libc/rand/syscalls.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44
use {crate::backend::c, crate::backend::conv::ret_usize, crate::io, crate::rand::GetRandomFlags};
55

66
#[cfg(linux_kernel)]
7-
pub(crate) fn getrandom(buf: &mut [u8], flags: GetRandomFlags) -> io::Result<usize> {
7+
pub(crate) unsafe fn getrandom(
8+
buf: *mut u8,
9+
cap: usize,
10+
flags: GetRandomFlags,
11+
) -> io::Result<usize> {
812
// `getrandom` wasn't supported in glibc until 2.25.
913
weak_or_syscall! {
1014
fn getrandom(buf: *mut c::c_void, buflen: c::size_t, flags: c::c_uint) via SYS_getrandom -> c::ssize_t
1115
}
1216

13-
unsafe { ret_usize(getrandom(buf.as_mut_ptr().cast(), buf.len(), flags.bits())) }
17+
ret_usize(getrandom(buf.cast(), cap, flags.bits()))
1418
}

src/backend/linux_raw/io/syscalls.rs

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::backend::conv::loff_t_from_u64;
1515
use crate::backend::conv::zero;
1616
use crate::backend::conv::{
1717
c_uint, pass_usize, raw_fd, ret, ret_c_int, ret_c_uint, ret_discarded_fd, ret_owned_fd,
18-
ret_usize, slice, slice_mut,
18+
ret_usize, slice,
1919
};
2020
#[cfg(target_pointer_width = "32")]
2121
use crate::backend::conv::{hi, lo};
@@ -29,27 +29,28 @@ use core::cmp;
2929
use linux_raw_sys::general::{F_DUPFD_CLOEXEC, F_GETFD, F_SETFD};
3030

3131
#[inline]
32-
pub(crate) fn read(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> {
33-
let (buf_addr_mut, buf_len) = slice_mut(buf);
34-
35-
unsafe { ret_usize(syscall!(__NR_read, fd, buf_addr_mut, buf_len)) }
32+
pub(crate) unsafe fn read(fd: BorrowedFd<'_>, buf: *mut u8, len: usize) -> io::Result<usize> {
33+
ret_usize(syscall!(__NR_read, fd, buf, pass_usize(len)))
3634
}
3735

3836
#[inline]
39-
pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], pos: u64) -> io::Result<usize> {
40-
let (buf_addr_mut, buf_len) = slice_mut(buf);
41-
37+
pub(crate) unsafe fn pread(
38+
fd: BorrowedFd<'_>,
39+
buf: *mut u8,
40+
len: usize,
41+
pos: u64,
42+
) -> io::Result<usize> {
4243
// <https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/arch/arm64/kernel/sys32.c#L75>
4344
#[cfg(all(
4445
target_pointer_width = "32",
4546
any(target_arch = "arm", target_arch = "mips", target_arch = "mips32r6"),
4647
))]
47-
unsafe {
48+
{
4849
ret_usize(syscall!(
4950
__NR_pread64,
5051
fd,
51-
buf_addr_mut,
52-
buf_len,
52+
buf,
53+
pass_usize(len),
5354
zero(),
5455
hi(pos),
5556
lo(pos)
@@ -59,26 +60,24 @@ pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], pos: u64) -> io::Result<
5960
target_pointer_width = "32",
6061
not(any(target_arch = "arm", target_arch = "mips", target_arch = "mips32r6")),
6162
))]
62-
unsafe {
63+
{
6364
ret_usize(syscall!(
6465
__NR_pread64,
6566
fd,
66-
buf_addr_mut,
67-
buf_len,
67+
buf,
68+
pass_usize(len),
6869
hi(pos),
6970
lo(pos)
7071
))
7172
}
7273
#[cfg(target_pointer_width = "64")]
73-
unsafe {
74-
ret_usize(syscall!(
75-
__NR_pread64,
76-
fd,
77-
buf_addr_mut,
78-
buf_len,
79-
loff_t_from_u64(pos)
80-
))
81-
}
74+
ret_usize(syscall!(
75+
__NR_pread64,
76+
fd,
77+
buf,
78+
pass_usize(len),
79+
loff_t_from_u64(pos)
80+
))
8281
}
8382

8483
#[inline]
@@ -268,15 +267,15 @@ pub(crate) fn is_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> {
268267
// Do a `recv` with `PEEK` and `DONTWAIT` for 1 byte. A 0 indicates
269268
// the read side is shut down; an `EWOULDBLOCK` indicates the read
270269
// side is still open.
271-
//
272-
// TODO: This code would benefit from having a better way to read into
273-
// uninitialized memory.
274-
let mut buf = [0];
275-
match crate::backend::net::syscalls::recv(
276-
fd,
277-
&mut buf,
278-
RecvFlags::PEEK | RecvFlags::DONTWAIT,
279-
) {
270+
let mut buf = [core::mem::MaybeUninit::<u8>::uninit()];
271+
match unsafe {
272+
crate::backend::net::syscalls::recv(
273+
fd,
274+
buf.as_mut_ptr() as *mut u8,
275+
1,
276+
RecvFlags::PEEK | RecvFlags::DONTWAIT,
277+
)
278+
} {
280279
Ok(0) => read = false,
281280
Err(err) => {
282281
#[allow(unreachable_patterns)] // `EAGAIN` may equal `EWOULDBLOCK`

0 commit comments

Comments
 (0)