Skip to content

Commit b1efc75

Browse files
committedDec 29, 2016
Auto merge of #38622 - alexcrichton:read-lengths, r=sfackler
std: Clamp max read/write sizes on Unix Turns out that even though all these functions take a `size_t` they don't actually work that well with anything larger than the maximum value of `ssize_t`, the return value. Furthermore it looks like OSX rejects any read/write requests larger than `INT_MAX - 1`. Handle all these cases by just clamping the maximum size of a read/write on Unix to a platform-specific value. Closes #38590
2 parents e7c788a + 917a9af commit b1efc75

File tree

2 files changed

+24
-12
lines changed

2 files changed

+24
-12
lines changed
 

‎src/libstd/sys/unix/fd.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010

1111
#![unstable(reason = "not public", issue = "0", feature = "fd")]
1212

13+
use cmp;
1314
use io::{self, Read};
14-
use libc::{self, c_int, c_void};
15+
use libc::{self, c_int, c_void, ssize_t};
1516
use mem;
1617
use sync::atomic::{AtomicBool, Ordering};
1718
use sys::cvt;
@@ -23,6 +24,22 @@ pub struct FileDesc {
2324
fd: c_int,
2425
}
2526

27+
fn max_len() -> usize {
28+
// The maximum read limit on most posix-like systems is `SSIZE_MAX`,
29+
// with the man page quoting that if the count of bytes to read is
30+
// greater than `SSIZE_MAX` the result is "unspecified".
31+
//
32+
// On OSX, however, apparently the 64-bit libc is either buggy or
33+
// intentionally showing odd behavior by rejecting any read with a size
34+
// larger than or equal to INT_MAX. To handle both of these the read
35+
// size is capped on both platforms.
36+
if cfg!(target_os = "macos") {
37+
<c_int>::max_value() as usize - 1
38+
} else {
39+
<ssize_t>::max_value() as usize
40+
}
41+
}
42+
2643
impl FileDesc {
2744
pub fn new(fd: c_int) -> FileDesc {
2845
FileDesc { fd: fd }
@@ -41,7 +58,7 @@ impl FileDesc {
4158
let ret = cvt(unsafe {
4259
libc::read(self.fd,
4360
buf.as_mut_ptr() as *mut c_void,
44-
buf.len())
61+
cmp::min(buf.len(), max_len()))
4562
})?;
4663
Ok(ret as usize)
4764
}
@@ -69,7 +86,7 @@ impl FileDesc {
6986
unsafe {
7087
cvt_pread64(self.fd,
7188
buf.as_mut_ptr() as *mut c_void,
72-
buf.len(),
89+
cmp::min(buf.len(), max_len()),
7390
offset as i64)
7491
.map(|n| n as usize)
7592
}
@@ -79,7 +96,7 @@ impl FileDesc {
7996
let ret = cvt(unsafe {
8097
libc::write(self.fd,
8198
buf.as_ptr() as *const c_void,
82-
buf.len())
99+
cmp::min(buf.len(), max_len()))
83100
})?;
84101
Ok(ret as usize)
85102
}
@@ -102,7 +119,7 @@ impl FileDesc {
102119
unsafe {
103120
cvt_pwrite64(self.fd,
104121
buf.as_ptr() as *const c_void,
105-
buf.len(),
122+
cmp::min(buf.len(), max_len()),
106123
offset as i64)
107124
.map(|n| n as usize)
108125
}

‎src/libstd/sys/windows/handle.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use ptr;
1919
use sys::c;
2020
use sys::cvt;
2121
use sys_common::io::read_to_end_uninitialized;
22-
use u32;
2322

2423
/// An owned container for `HANDLE` object, closing them on Drop.
2524
///
@@ -83,9 +82,7 @@ impl RawHandle {
8382

8483
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
8584
let mut read = 0;
86-
// ReadFile takes a DWORD (u32) for the length so it only supports
87-
// reading u32::MAX bytes at a time.
88-
let len = cmp::min(buf.len(), u32::MAX as usize) as c::DWORD;
85+
let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
8986
let res = cvt(unsafe {
9087
c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID,
9188
len, &mut read, ptr::null_mut())
@@ -181,9 +178,7 @@ impl RawHandle {
181178

182179
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
183180
let mut amt = 0;
184-
// WriteFile takes a DWORD (u32) for the length so it only supports
185-
// writing u32::MAX bytes at a time.
186-
let len = cmp::min(buf.len(), u32::MAX as usize) as c::DWORD;
181+
let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
187182
cvt(unsafe {
188183
c::WriteFile(self.0, buf.as_ptr() as c::LPVOID,
189184
len, &mut amt, ptr::null_mut())

0 commit comments

Comments
 (0)