Skip to content

Commit 1ab21e6

Browse files
authored
Fix p{read,write}v{,v2}'s encoding of the offset argument on Linux. (#896)
Unlike with `p{read,write}`, Linux's `p{read,write}v` syscall's offset argument is not passed in an endian-specific order. And, the expectation is for syscall wrappers to always pass both the high and low halves of the offset as separate arguments, even though on 64-bit architectures the low half is passed throgh as a 64-bit value containing the full offset and the kernel doesn't mask it. And `p{read,write}v2` follow the behavior of `p{read,write}`.
1 parent 0b7ccf4 commit 1ab21e6

File tree

4 files changed

+251
-227
lines changed

4 files changed

+251
-227
lines changed

src/backend/libc/c.rs

Lines changed: 98 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -224,25 +224,6 @@ pub(super) unsafe fn prlimit(
224224
prlimit64(pid, resource, new_limit, old_limit)
225225
}
226226

227-
// 64-bit offsets on 32-bit platforms are passed in endianness-specific
228-
// lo/hi pairs. See src/backend/linux_raw/conv.rs for details.
229-
#[cfg(all(linux_kernel, target_endian = "little", target_pointer_width = "32"))]
230-
fn lo(x: i64) -> usize {
231-
(x >> 32) as usize
232-
}
233-
#[cfg(all(linux_kernel, target_endian = "little", target_pointer_width = "32"))]
234-
fn hi(x: i64) -> usize {
235-
x as usize
236-
}
237-
#[cfg(all(linux_kernel, target_endian = "big", target_pointer_width = "32"))]
238-
fn lo(x: i64) -> usize {
239-
x as usize
240-
}
241-
#[cfg(all(linux_kernel, target_endian = "big", target_pointer_width = "32"))]
242-
fn hi(x: i64) -> usize {
243-
(x >> 32) as usize
244-
}
245-
246227
#[cfg(target_os = "android")]
247228
mod readwrite_pv64 {
248229
use super::*;
@@ -263,31 +244,18 @@ mod readwrite_pv64 {
263244
if let Some(fun) = preadv64.get() {
264245
fun(fd, iov, iovcnt, offset)
265246
} else {
266-
#[cfg(target_pointer_width = "32")]
267-
{
268-
syscall! {
269-
fn preadv(
270-
fd: libc::c_int,
271-
iov: *const libc::iovec,
272-
iovcnt: libc::c_int,
273-
offset_hi: usize,
274-
offset_lo: usize
275-
) via SYS_preadv -> libc::ssize_t
276-
}
277-
preadv(fd, iov, iovcnt, hi(offset), lo(offset))
278-
}
279-
#[cfg(target_pointer_width = "64")]
280-
{
281-
syscall! {
282-
fn preadv(
283-
fd: libc::c_int,
284-
iov: *const libc::iovec,
285-
iovcnt: libc::c_int,
286-
offset: libc::off_t
287-
) via SYS_preadv -> libc::ssize_t
288-
}
289-
preadv(fd, iov, iovcnt, offset)
247+
// Unlike the plain "p" functions, the "pv" functions pass their
248+
// offset in an endian-independent way, and always in two registers.
249+
syscall! {
250+
fn preadv(
251+
fd: libc::c_int,
252+
iov: *const libc::iovec,
253+
iovcnt: libc::c_int,
254+
offset_lo: usize,
255+
offset_hi: usize
256+
) via SYS_preadv -> libc::ssize_t
290257
}
258+
preadv(fd, iov, iovcnt, offset as usize, (offset >> 32) as usize)
291259
}
292260
}
293261
pub(in super::super) unsafe fn pwritev64(
@@ -303,31 +271,18 @@ mod readwrite_pv64 {
303271
if let Some(fun) = pwritev64.get() {
304272
fun(fd, iov, iovcnt, offset)
305273
} else {
306-
#[cfg(target_pointer_width = "32")]
307-
{
308-
syscall! {
309-
fn pwritev(
310-
fd: libc::c_int,
311-
iov: *const libc::iovec,
312-
iovcnt: libc::c_int,
313-
offset_hi: usize,
314-
offset_lo: usize
315-
) via SYS_pwritev -> libc::ssize_t
316-
}
317-
pwritev(fd, iov, iovcnt, hi(offset), lo(offset))
318-
}
319-
#[cfg(target_pointer_width = "64")]
320-
{
321-
syscall! {
322-
fn pwritev(
323-
fd: libc::c_int,
324-
iov: *const libc::iovec,
325-
iovcnt: libc::c_int,
326-
offset: libc::off_t
327-
) via SYS_pwritev -> libc::ssize_t
328-
}
329-
pwritev(fd, iov, iovcnt, offset)
274+
// Unlike the plain "p" functions, the "pv" functions pass their
275+
// offset in an endian-independent way, and always in two registers.
276+
syscall! {
277+
fn pwritev(
278+
fd: libc::c_int,
279+
iov: *const libc::iovec,
280+
iovcnt: libc::c_int,
281+
offset_lo: usize,
282+
offset_hi: usize
283+
) via SYS_pwritev -> libc::ssize_t
330284
}
285+
pwritev(fd, iov, iovcnt, offset as usize, (offset >> 32) as usize)
331286
}
332287
}
333288
}
@@ -378,33 +333,26 @@ mod readwrite_pv64v2 {
378333
if let Some(fun) = preadv64v2.get() {
379334
fun(fd, iov, iovcnt, offset, flags)
380335
} else {
381-
#[cfg(target_pointer_width = "32")]
382-
{
383-
syscall! {
384-
fn preadv2(
385-
fd: libc::c_int,
386-
iov: *const libc::iovec,
387-
iovcnt: libc::c_int,
388-
offset_hi: usize,
389-
offset_lo: usize,
390-
flags: libc::c_int
391-
) via SYS_preadv2 -> libc::ssize_t
392-
}
393-
preadv2(fd, iov, iovcnt, hi(offset), lo(offset), flags)
394-
}
395-
#[cfg(target_pointer_width = "64")]
396-
{
397-
syscall! {
398-
fn preadv2(
399-
fd: libc::c_int,
400-
iov: *const libc::iovec,
401-
iovcnt: libc::c_int,
402-
offset: libc::off_t,
403-
flags: libc::c_int
404-
) via SYS_preadv2 -> libc::ssize_t
405-
}
406-
preadv2(fd, iov, iovcnt, offset, flags)
336+
// Unlike the plain "p" functions, the "pv" functions pass their
337+
// offset in an endian-independent way, and always in two registers.
338+
syscall! {
339+
fn preadv2(
340+
fd: libc::c_int,
341+
iov: *const libc::iovec,
342+
iovcnt: libc::c_int,
343+
offset_lo: usize,
344+
offset_hi: usize,
345+
flags: libc::c_int
346+
) via SYS_preadv2 -> libc::ssize_t
407347
}
348+
preadv2(
349+
fd,
350+
iov,
351+
iovcnt,
352+
offset as usize,
353+
(offset >> 32) as usize,
354+
flags,
355+
)
408356
}
409357
}
410358
pub(in super::super) unsafe fn pwritev64v2(
@@ -421,33 +369,26 @@ mod readwrite_pv64v2 {
421369
if let Some(fun) = pwritev64v2.get() {
422370
fun(fd, iov, iovcnt, offset, flags)
423371
} else {
424-
#[cfg(target_pointer_width = "32")]
425-
{
426-
syscall! {
427-
fn pwritev2(
428-
fd: libc::c_int,
429-
iov: *const libc::iovec,
430-
iovec: libc::c_int,
431-
offset_hi: usize,
432-
offset_lo: usize,
433-
flags: libc::c_int
434-
) via SYS_pwritev2 -> libc::ssize_t
435-
}
436-
pwritev2(fd, iov, iovcnt, hi(offset), lo(offset), flags)
437-
}
438-
#[cfg(target_pointer_width = "64")]
439-
{
440-
syscall! {
441-
fn pwritev2(
442-
fd: libc::c_int,
443-
iov:*const libc::iovec,
444-
iovcnt: libc::c_int,
445-
offset: libc::off_t,
446-
flags: libc::c_int
447-
) via SYS_pwritev2 -> libc::ssize_t
448-
}
449-
pwritev2(fd, iov, iovcnt, offset, flags)
372+
// Unlike the plain "p" functions, the "pv" functions pass their
373+
// offset in an endian-independent way, and always in two registers.
374+
syscall! {
375+
fn pwritev2(
376+
fd: libc::c_int,
377+
iov: *const libc::iovec,
378+
iovec: libc::c_int,
379+
offset_lo: usize,
380+
offset_hi: usize,
381+
flags: libc::c_int
382+
) via SYS_pwritev2 -> libc::ssize_t
450383
}
384+
pwritev2(
385+
fd,
386+
iov,
387+
iovcnt,
388+
offset as usize,
389+
(offset >> 32) as usize,
390+
flags,
391+
)
451392
}
452393
}
453394
}
@@ -470,33 +411,26 @@ mod readwrite_pv64v2 {
470411
offset: libc::off64_t,
471412
flags: libc::c_int,
472413
) -> libc::ssize_t {
473-
#[cfg(target_pointer_width = "32")]
474-
{
475-
syscall! {
476-
fn preadv2(
477-
fd: libc::c_int,
478-
iov: *const libc::iovec,
479-
iovcnt: libc::c_int,
480-
offset_hi: usize,
481-
offset_lo: usize,
482-
flags: libc::c_int
483-
) via SYS_preadv2 -> libc::ssize_t
484-
}
485-
preadv2(fd, iov, iovcnt, hi(offset), lo(offset), flags)
486-
}
487-
#[cfg(target_pointer_width = "64")]
488-
{
489-
syscall! {
490-
fn preadv2(
491-
fd: libc::c_int,
492-
iov: *const libc::iovec,
493-
iovcnt: libc::c_int,
494-
offset: libc::off_t,
495-
flags: libc::c_int
496-
) via SYS_preadv2 -> libc::ssize_t
497-
}
498-
preadv2(fd, iov, iovcnt, offset, flags)
414+
// Unlike the plain "p" functions, the "pv" functions pass their offset
415+
// in an endian-independent way, and always in two registers.
416+
syscall! {
417+
fn preadv2(
418+
fd: libc::c_int,
419+
iov: *const libc::iovec,
420+
iovcnt: libc::c_int,
421+
offset_lo: usize,
422+
offset_hi: usize,
423+
flags: libc::c_int
424+
) via SYS_preadv2 -> libc::ssize_t
499425
}
426+
preadv2(
427+
fd,
428+
iov,
429+
iovcnt,
430+
offset as usize,
431+
(offset >> 32) as usize,
432+
flags,
433+
)
500434
}
501435
pub(in super::super) unsafe fn pwritev64v2(
502436
fd: libc::c_int,
@@ -505,33 +439,26 @@ mod readwrite_pv64v2 {
505439
offset: libc::off64_t,
506440
flags: libc::c_int,
507441
) -> libc::ssize_t {
508-
#[cfg(target_pointer_width = "32")]
509-
{
510-
syscall! {
511-
fn pwritev2(
512-
fd: libc::c_int,
513-
iov: *const libc::iovec,
514-
iovcnt: libc::c_int,
515-
offset_hi: usize,
516-
offset_lo: usize,
517-
flags: libc::c_int
518-
) via SYS_pwritev2 -> libc::ssize_t
519-
}
520-
pwritev2(fd, iov, iovcnt, hi(offset), lo(offset), flags)
521-
}
522-
#[cfg(target_pointer_width = "64")]
523-
{
524-
syscall! {
525-
fn pwritev2(
526-
fd: libc::c_int,
527-
iov:*const libc::iovec,
528-
iovcnt: libc::c_int,
529-
offset: libc::off_t,
530-
flags: libc::c_int
531-
) via SYS_pwritev2 -> libc::ssize_t
532-
}
533-
pwritev2(fd, iov, iovcnt, offset, flags)
442+
// Unlike the plain "p" functions, the "pv" functions pass their offset
443+
// in an endian-independent way, and always in two registers.
444+
syscall! {
445+
fn pwritev2(
446+
fd: libc::c_int,
447+
iov: *const libc::iovec,
448+
iovcnt: libc::c_int,
449+
offset_lo: usize,
450+
offset_hi: usize,
451+
flags: libc::c_int
452+
) via SYS_pwritev2 -> libc::ssize_t
534453
}
454+
pwritev2(
455+
fd,
456+
iov,
457+
iovcnt,
458+
offset as usize,
459+
(offset >> 32) as usize,
460+
flags,
461+
)
535462
}
536463
}
537464
#[cfg(any(

0 commit comments

Comments
 (0)