Skip to content

Commit f16f2e3

Browse files
committed
Cast pointers more carefully
Prefer ptr::{cast, cast_const, cast_mut} over `as`. The latter makes it too easy to accidentally change both the type and mutability when changing only one was intended. This exercise caught an unintended mutability cast in one function, the BSD version of sendfile. In this case there's no UB because it isn't possible for anything else to get a reference to the data that was incorrectly cast. There was also a type cast that wasn't guaranteed to be correct (but probably was) due to memory layout guarantees in if_nametoindex.
1 parent 154a8a4 commit f16f2e3

22 files changed

+110
-119
lines changed

src/fcntl.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::errno::Errno;
2-
use libc::{self, c_char, c_int, c_uint, size_t, ssize_t};
2+
use libc::{self, c_int, c_uint, size_t, ssize_t};
33
use std::ffi::OsString;
44
#[cfg(not(target_os = "redox"))]
55
use std::os::raw;
@@ -306,12 +306,12 @@ fn readlink_maybe_at<P: ?Sized + NixPath>(
306306
Some(dirfd) => libc::readlinkat(
307307
dirfd,
308308
cstr.as_ptr(),
309-
v.as_mut_ptr() as *mut c_char,
309+
v.as_mut_ptr().cast(),
310310
v.capacity() as size_t,
311311
),
312312
None => libc::readlink(
313313
cstr.as_ptr(),
314-
v.as_mut_ptr() as *mut c_char,
314+
v.as_mut_ptr().cast(),
315315
v.capacity() as size_t,
316316
),
317317
}
@@ -724,7 +724,7 @@ pub fn vmsplice(
724724
let ret = unsafe {
725725
libc::vmsplice(
726726
fd,
727-
iov.as_ptr() as *const libc::iovec,
727+
iov.as_ptr().cast(),
728728
iov.len(),
729729
flags.bits(),
730730
)

src/ifaddrs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option<SockaddrStorage> {
6565
// memcpy only sa_len bytes, assume the rest is zero
6666
std::ptr::copy_nonoverlapping(
6767
src_sock as *const u8,
68-
dst_sock.as_mut_ptr() as *mut u8,
68+
dst_sock.as_mut_ptr().cast(),
6969
(*src_sock).sa_len.into(),
7070
);
7171

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ impl NixPath for [u8] {
311311
}
312312

313313
let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit();
314-
let buf_ptr = buf.as_mut_ptr() as *mut u8;
314+
let buf_ptr = buf.as_mut_ptr().cast();
315315

316316
unsafe {
317317
ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len());

src/mount/bsd.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ impl<'a> Nmount<'a> {
215215
/// Helper function to push a slice onto the `iov` array.
216216
fn push_slice(&mut self, val: &'a [u8], is_owned: bool) {
217217
self.iov.push(libc::iovec {
218-
iov_base: val.as_ptr() as *mut _,
218+
iov_base: val.as_ptr().cast_mut().cast(),
219219
iov_len: val.len(),
220220
});
221221
self.is_owned.push(is_owned);
@@ -386,7 +386,7 @@ impl<'a> Nmount<'a> {
386386
// SAFETY: we are pushing a mutable iovec here, so we can't use
387387
// the above method
388388
self.iov.push(libc::iovec {
389-
iov_base: errmsg.as_mut_ptr() as *mut c_void,
389+
iov_base: errmsg.as_mut_ptr().cast(),
390390
iov_len: errmsg.len(),
391391
});
392392

src/mqueue.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use crate::NixPath;
3535
use crate::Result;
3636

3737
use crate::sys::stat::Mode;
38-
use libc::{self, c_char, mqd_t, size_t};
38+
use libc::{self, mqd_t, size_t};
3939
use std::mem;
4040
#[cfg(any(
4141
target_os = "linux",
@@ -205,7 +205,7 @@ pub fn mq_receive(
205205
let res = unsafe {
206206
libc::mq_receive(
207207
mqdes.0,
208-
message.as_mut_ptr() as *mut c_char,
208+
message.as_mut_ptr().cast(),
209209
len,
210210
msg_prio as *mut u32,
211211
)
@@ -229,7 +229,7 @@ feature! {
229229
let res = unsafe {
230230
libc::mq_timedreceive(
231231
mqdes.0,
232-
message.as_mut_ptr() as *mut c_char,
232+
message.as_mut_ptr().cast(),
233233
len,
234234
msg_prio as *mut u32,
235235
abstime.as_ref(),
@@ -244,12 +244,7 @@ feature! {
244244
/// See also [`mq_send(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html)
245245
pub fn mq_send(mqdes: &MqdT, message: &[u8], msq_prio: u32) -> Result<()> {
246246
let res = unsafe {
247-
libc::mq_send(
248-
mqdes.0,
249-
message.as_ptr() as *const c_char,
250-
message.len(),
251-
msq_prio,
252-
)
247+
libc::mq_send(mqdes.0, message.as_ptr().cast(), message.len(), msq_prio)
253248
};
254249
Errno::result(res).map(drop)
255250
}

src/net/if_.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ mod if_nameindex {
373373
}
374374

375375
/// A list of the network interfaces available on this system. Obtained from [`if_nameindex()`].
376+
#[repr(transparent)]
376377
pub struct Interfaces {
377378
ptr: NonNull<libc::if_nameindex>,
378379
}
@@ -388,7 +389,7 @@ mod if_nameindex {
388389
/// null-terminated, so calling this calculates the length. If random access isn't needed,
389390
/// [`Interfaces::iter()`] should be used instead.
390391
pub fn to_slice(&self) -> &[Interface] {
391-
let ifs = self.ptr.as_ptr() as *const Interface;
392+
let ifs = self.ptr.as_ptr().cast();
392393
let len = self.iter().count();
393394
unsafe { std::slice::from_raw_parts(ifs, len) }
394395
}

src/poll.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,7 @@ libc_bitflags! {
190190
/// ready.
191191
pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> {
192192
let res = unsafe {
193-
libc::poll(
194-
fds.as_mut_ptr() as *mut libc::pollfd,
195-
fds.len() as libc::nfds_t,
196-
timeout,
197-
)
193+
libc::poll(fds.as_mut_ptr().cast(), fds.len() as libc::nfds_t, timeout)
198194
};
199195

200196
Errno::result(res)
@@ -223,7 +219,7 @@ pub fn ppoll(
223219
let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
224220
let sigmask = sigmask.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
225221
let res = unsafe {
226-
libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd,
222+
libc::ppoll(fds.as_mut_ptr().cast(),
227223
fds.len() as libc::nfds_t,
228224
timeout,
229225
sigmask)

src/sys/aio.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use std::{
3535
ptr, thread,
3636
};
3737

38-
use libc::{c_void, off_t};
38+
use libc::off_t;
3939
use pin_utils::unsafe_pinned;
4040

4141
use crate::{
@@ -581,7 +581,7 @@ impl<'a> AioRead<'a> {
581581
) -> Self {
582582
let mut aiocb = AioCb::common_init(fd, prio, sigev_notify);
583583
aiocb.aiocb.0.aio_nbytes = buf.len();
584-
aiocb.aiocb.0.aio_buf = buf.as_mut_ptr() as *mut c_void;
584+
aiocb.aiocb.0.aio_buf = buf.as_mut_ptr().cast();
585585
aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READ;
586586
aiocb.aiocb.0.aio_offset = offs;
587587
AioRead {
@@ -702,7 +702,7 @@ impl<'a> AioReadv<'a> {
702702
// In vectored mode, aio_nbytes stores the length of the iovec array,
703703
// not the byte count.
704704
aiocb.aiocb.0.aio_nbytes = bufs.len();
705-
aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr() as *mut c_void;
705+
aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr().cast();
706706
aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READV;
707707
aiocb.aiocb.0.aio_offset = offs;
708708
AioReadv {
@@ -817,7 +817,7 @@ impl<'a> AioWrite<'a> {
817817
// but technically its only unsafe to dereference it, not to create
818818
// it. Type Safety guarantees that we'll never pass aiocb to
819819
// aio_read or aio_readv.
820-
aiocb.aiocb.0.aio_buf = buf.as_ptr() as *mut c_void;
820+
aiocb.aiocb.0.aio_buf = buf.as_ptr().cast_mut().cast();
821821
aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITE;
822822
aiocb.aiocb.0.aio_offset = offs;
823823
AioWrite {
@@ -935,7 +935,7 @@ impl<'a> AioWritev<'a> {
935935
// but technically its only unsafe to dereference it, not to create
936936
// it. Type Safety guarantees that we'll never pass aiocb to
937937
// aio_read or aio_readv.
938-
aiocb.aiocb.0.aio_buf = bufs.as_ptr() as *mut c_void;
938+
aiocb.aiocb.0.aio_buf = bufs.as_ptr().cast_mut().cast();
939939
aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITEV;
940940
aiocb.aiocb.0.aio_offset = offs;
941941
AioWritev {

src/sys/epoll.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ impl Epoll {
148148
let res = unsafe {
149149
libc::epoll_wait(
150150
self.0.as_raw_fd(),
151-
events.as_mut_ptr() as *mut libc::epoll_event,
151+
events.as_mut_ptr().cast(),
152152
events.len() as c_int,
153153
timeout as c_int,
154154
)
@@ -240,7 +240,7 @@ pub fn epoll_wait(
240240
let res = unsafe {
241241
libc::epoll_wait(
242242
epfd,
243-
events.as_mut_ptr() as *mut libc::epoll_event,
243+
events.as_mut_ptr().cast(),
244244
events.len() as c_int,
245245
timeout_ms as c_int,
246246
)

src/sys/event.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ impl Kqueue {
6363
let res = unsafe {
6464
libc::kevent(
6565
self.0.as_raw_fd(),
66-
changelist.as_ptr() as *const libc::kevent,
66+
changelist.as_ptr().cast(),
6767
changelist.len() as type_of_nchanges,
68-
eventlist.as_mut_ptr() as *mut libc::kevent,
68+
eventlist.as_mut_ptr().cast(),
6969
eventlist.len() as type_of_nchanges,
7070
if let Some(ref timeout) = timeout_opt {
7171
timeout as *const timespec

src/sys/inotify.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ impl Inotify {
202202
let mut event = MaybeUninit::<libc::inotify_event>::uninit();
203203
ptr::copy_nonoverlapping(
204204
buffer.as_ptr().add(offset),
205-
event.as_mut_ptr() as *mut u8,
205+
event.as_mut_ptr().cast(),
206206
(BUFSIZ - offset).min(header_size),
207207
);
208208
event.assume_init()

src/sys/ptrace/linux.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,13 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
241241
/// and therefore use the data field to return values. This function handles these
242242
/// requests.
243243
fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
244-
let mut data = mem::MaybeUninit::uninit();
244+
let mut data = mem::MaybeUninit::<T>::uninit();
245245
let res = unsafe {
246246
libc::ptrace(
247247
request as RequestType,
248248
libc::pid_t::from(pid),
249249
ptr::null_mut::<T>(),
250-
data.as_mut_ptr() as *const _ as *const c_void,
250+
data.as_mut_ptr(),
251251
)
252252
};
253253
Errno::result(res)?;

src/sys/quota.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ pub fn quotactl_on<P: ?Sized + NixPath>(
264264
) -> Result<()> {
265265
quota_file.with_nix_path(|path| {
266266
let mut path_copy = path.to_bytes_with_nul().to_owned();
267-
let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char;
267+
let p: *mut c_char = path_copy.as_mut_ptr().cast();
268268
quotactl(
269269
QuotaCmd(QuotaSubCmd::Q_QUOTAON, which),
270270
Some(special),
@@ -308,12 +308,12 @@ pub fn quotactl_get<P: ?Sized + NixPath>(
308308
special: &P,
309309
id: c_int,
310310
) -> Result<Dqblk> {
311-
let mut dqblk = mem::MaybeUninit::uninit();
311+
let mut dqblk = mem::MaybeUninit::<libc::dqblk>::uninit();
312312
quotactl(
313313
QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which),
314314
Some(special),
315315
id,
316-
dqblk.as_mut_ptr() as *mut c_char,
316+
dqblk.as_mut_ptr().cast(),
317317
)?;
318318
Ok(unsafe { Dqblk(dqblk.assume_init()) })
319319
}

src/sys/sendfile.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,22 +96,24 @@ cfg_if! {
9696
headers: Option<&'a [&'a [u8]]>,
9797
trailers: Option<&'a [&'a [u8]]>
9898
) -> SendfileHeaderTrailer<'a> {
99-
let header_iovecs: Option<Vec<IoSlice<'_>>> =
99+
let mut header_iovecs: Option<Vec<IoSlice<'_>>> =
100100
headers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect());
101-
let trailer_iovecs: Option<Vec<IoSlice<'_>>> =
101+
let mut trailer_iovecs: Option<Vec<IoSlice<'_>>> =
102102
trailers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect());
103103
SendfileHeaderTrailer(
104104
libc::sf_hdtr {
105105
headers: {
106106
header_iovecs
107-
.as_ref()
108-
.map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
107+
.as_mut()
108+
.map_or(ptr::null_mut(), |v| v.as_mut_ptr())
109+
.cast()
109110
},
110111
hdr_cnt: header_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32,
111112
trailers: {
112113
trailer_iovecs
113-
.as_ref()
114-
.map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
114+
.as_mut()
115+
.map_or(ptr::null_mut(), |v| v.as_mut_ptr())
116+
.cast()
115117
},
116118
trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32
117119
},

src/sys/signalfd.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl SignalFd {
109109

110110
let size = mem::size_of_val(&buffer);
111111
let res = Errno::result(unsafe {
112-
libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr() as *mut libc::c_void, size)
112+
libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr().cast(), size)
113113
})
114114
.map(|r| r as usize);
115115
match res {

0 commit comments

Comments
 (0)