Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix p{read,write}v{,v2}'s encoding of the offset argument on Linux. #896

Merged
merged 1 commit into from Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
269 changes: 98 additions & 171 deletions src/backend/libc/c.rs
Expand Up @@ -224,25 +224,6 @@ pub(super) unsafe fn prlimit(
prlimit64(pid, resource, new_limit, old_limit)
}

// 64-bit offsets on 32-bit platforms are passed in endianness-specific
// lo/hi pairs. See src/backend/linux_raw/conv.rs for details.
#[cfg(all(linux_kernel, target_endian = "little", target_pointer_width = "32"))]
fn lo(x: i64) -> usize {
(x >> 32) as usize
}
#[cfg(all(linux_kernel, target_endian = "little", target_pointer_width = "32"))]
fn hi(x: i64) -> usize {
x as usize
}
#[cfg(all(linux_kernel, target_endian = "big", target_pointer_width = "32"))]
fn lo(x: i64) -> usize {
x as usize
}
#[cfg(all(linux_kernel, target_endian = "big", target_pointer_width = "32"))]
fn hi(x: i64) -> usize {
(x >> 32) as usize
}

#[cfg(target_os = "android")]
mod readwrite_pv64 {
use super::*;
Expand All @@ -263,31 +244,18 @@ mod readwrite_pv64 {
if let Some(fun) = preadv64.get() {
fun(fd, iov, iovcnt, offset)
} else {
#[cfg(target_pointer_width = "32")]
{
syscall! {
fn preadv(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset_hi: usize,
offset_lo: usize
) via SYS_preadv -> libc::ssize_t
}
preadv(fd, iov, iovcnt, hi(offset), lo(offset))
}
#[cfg(target_pointer_width = "64")]
{
syscall! {
fn preadv(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset: libc::off_t
) via SYS_preadv -> libc::ssize_t
}
preadv(fd, iov, iovcnt, offset)
// Unlike the plain "p" functions, the "pv" functions pass their
// offset in an endian-independent way, and always in two registers.
syscall! {
fn preadv(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset_lo: usize,
offset_hi: usize
) via SYS_preadv -> libc::ssize_t
}
preadv(fd, iov, iovcnt, offset as usize, (offset >> 32) as usize)
}
}
pub(in super::super) unsafe fn pwritev64(
Expand All @@ -303,31 +271,18 @@ mod readwrite_pv64 {
if let Some(fun) = pwritev64.get() {
fun(fd, iov, iovcnt, offset)
} else {
#[cfg(target_pointer_width = "32")]
{
syscall! {
fn pwritev(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset_hi: usize,
offset_lo: usize
) via SYS_pwritev -> libc::ssize_t
}
pwritev(fd, iov, iovcnt, hi(offset), lo(offset))
}
#[cfg(target_pointer_width = "64")]
{
syscall! {
fn pwritev(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset: libc::off_t
) via SYS_pwritev -> libc::ssize_t
}
pwritev(fd, iov, iovcnt, offset)
// Unlike the plain "p" functions, the "pv" functions pass their
// offset in an endian-independent way, and always in two registers.
syscall! {
fn pwritev(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset_lo: usize,
offset_hi: usize
) via SYS_pwritev -> libc::ssize_t
}
pwritev(fd, iov, iovcnt, offset as usize, (offset >> 32) as usize)
}
}
}
Expand Down Expand Up @@ -378,33 +333,26 @@ mod readwrite_pv64v2 {
if let Some(fun) = preadv64v2.get() {
fun(fd, iov, iovcnt, offset, flags)
} else {
#[cfg(target_pointer_width = "32")]
{
syscall! {
fn preadv2(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset_hi: usize,
offset_lo: usize,
flags: libc::c_int
) via SYS_preadv2 -> libc::ssize_t
}
preadv2(fd, iov, iovcnt, hi(offset), lo(offset), flags)
}
#[cfg(target_pointer_width = "64")]
{
syscall! {
fn preadv2(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset: libc::off_t,
flags: libc::c_int
) via SYS_preadv2 -> libc::ssize_t
}
preadv2(fd, iov, iovcnt, offset, flags)
// Unlike the plain "p" functions, the "pv" functions pass their
// offset in an endian-independent way, and always in two registers.
syscall! {
fn preadv2(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset_lo: usize,
offset_hi: usize,
flags: libc::c_int
) via SYS_preadv2 -> libc::ssize_t
}
preadv2(
fd,
iov,
iovcnt,
offset as usize,
(offset >> 32) as usize,
flags,
)
}
}
pub(in super::super) unsafe fn pwritev64v2(
Expand All @@ -421,33 +369,26 @@ mod readwrite_pv64v2 {
if let Some(fun) = pwritev64v2.get() {
fun(fd, iov, iovcnt, offset, flags)
} else {
#[cfg(target_pointer_width = "32")]
{
syscall! {
fn pwritev2(
fd: libc::c_int,
iov: *const libc::iovec,
iovec: libc::c_int,
offset_hi: usize,
offset_lo: usize,
flags: libc::c_int
) via SYS_pwritev2 -> libc::ssize_t
}
pwritev2(fd, iov, iovcnt, hi(offset), lo(offset), flags)
}
#[cfg(target_pointer_width = "64")]
{
syscall! {
fn pwritev2(
fd: libc::c_int,
iov:*const libc::iovec,
iovcnt: libc::c_int,
offset: libc::off_t,
flags: libc::c_int
) via SYS_pwritev2 -> libc::ssize_t
}
pwritev2(fd, iov, iovcnt, offset, flags)
// Unlike the plain "p" functions, the "pv" functions pass their
// offset in an endian-independent way, and always in two registers.
syscall! {
fn pwritev2(
fd: libc::c_int,
iov: *const libc::iovec,
iovec: libc::c_int,
offset_lo: usize,
offset_hi: usize,
flags: libc::c_int
) via SYS_pwritev2 -> libc::ssize_t
}
pwritev2(
fd,
iov,
iovcnt,
offset as usize,
(offset >> 32) as usize,
flags,
)
}
}
}
Expand All @@ -470,33 +411,26 @@ mod readwrite_pv64v2 {
offset: libc::off64_t,
flags: libc::c_int,
) -> libc::ssize_t {
#[cfg(target_pointer_width = "32")]
{
syscall! {
fn preadv2(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset_hi: usize,
offset_lo: usize,
flags: libc::c_int
) via SYS_preadv2 -> libc::ssize_t
}
preadv2(fd, iov, iovcnt, hi(offset), lo(offset), flags)
}
#[cfg(target_pointer_width = "64")]
{
syscall! {
fn preadv2(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset: libc::off_t,
flags: libc::c_int
) via SYS_preadv2 -> libc::ssize_t
}
preadv2(fd, iov, iovcnt, offset, flags)
// Unlike the plain "p" functions, the "pv" functions pass their offset
// in an endian-independent way, and always in two registers.
syscall! {
fn preadv2(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset_lo: usize,
offset_hi: usize,
flags: libc::c_int
) via SYS_preadv2 -> libc::ssize_t
}
preadv2(
fd,
iov,
iovcnt,
offset as usize,
(offset >> 32) as usize,
flags,
)
}
pub(in super::super) unsafe fn pwritev64v2(
fd: libc::c_int,
Expand All @@ -505,33 +439,26 @@ mod readwrite_pv64v2 {
offset: libc::off64_t,
flags: libc::c_int,
) -> libc::ssize_t {
#[cfg(target_pointer_width = "32")]
{
syscall! {
fn pwritev2(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset_hi: usize,
offset_lo: usize,
flags: libc::c_int
) via SYS_pwritev2 -> libc::ssize_t
}
pwritev2(fd, iov, iovcnt, hi(offset), lo(offset), flags)
}
#[cfg(target_pointer_width = "64")]
{
syscall! {
fn pwritev2(
fd: libc::c_int,
iov:*const libc::iovec,
iovcnt: libc::c_int,
offset: libc::off_t,
flags: libc::c_int
) via SYS_pwritev2 -> libc::ssize_t
}
pwritev2(fd, iov, iovcnt, offset, flags)
// Unlike the plain "p" functions, the "pv" functions pass their offset
// in an endian-independent way, and always in two registers.
syscall! {
fn pwritev2(
fd: libc::c_int,
iov: *const libc::iovec,
iovcnt: libc::c_int,
offset_lo: usize,
offset_hi: usize,
flags: libc::c_int
) via SYS_pwritev2 -> libc::ssize_t
}
pwritev2(
fd,
iov,
iovcnt,
offset as usize,
(offset >> 32) as usize,
flags,
)
}
}
#[cfg(any(
Expand Down