Skip to content

Commit acbcf30

Browse files
committed
fix: handle integer overflows
Passing huge values might lead to integer overflows during calculations.
1 parent 61a813b commit acbcf30

File tree

3 files changed

+29
-8
lines changed

3 files changed

+29
-8
lines changed

src/spooled.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,11 @@ impl Write for SpooledTempFile {
157157
// roll over to file if necessary
158158
if matches! {
159159
&self.inner, SpooledData::InMemory(cursor)
160-
if cursor.position() as usize + buf.len() > self.max_size
160+
if cursor
161+
.position()
162+
.checked_add(buf.len() as u64)
163+
.filter(|&val| val <= self.max_size as u64)
164+
.is_none()
161165
} {
162166
self.roll()?;
163167
}
@@ -172,9 +176,11 @@ impl Write for SpooledTempFile {
172176
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
173177
if matches! {
174178
&self.inner, SpooledData::InMemory(cursor)
175-
// Borrowed from the rust standard library.
176-
if cursor.position() as usize + bufs.iter()
177-
.fold(0usize, |a, b| a.saturating_add(b.len())) > self.max_size
179+
if bufs
180+
.iter()
181+
.try_fold(cursor.position(), |a, b| a.checked_add(b.len() as u64))
182+
.filter(|&val| val <= self.max_size as u64)
183+
.is_none()
178184
} {
179185
self.roll()?;
180186
}

src/util.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ use std::{io, iter::repeat_with};
44

55
use crate::error::IoResultExt;
66

7-
fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> OsString {
8-
let mut buf = OsString::with_capacity(prefix.len() + suffix.len() + rand_len);
7+
fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> io::Result<OsString> {
8+
let capacity = prefix
9+
.len()
10+
.checked_add(suffix.len())
11+
.and_then(|value| value.checked_add(rand_len))
12+
.ok_or(io::Error::new(io::ErrorKind::InvalidInput, "name too long"))?;
13+
let mut buf = OsString::with_capacity(capacity);
914
buf.push(prefix);
1015
let mut char_buf = [0u8; 4];
1116
for c in repeat_with(fastrand::alphanumeric).take(rand_len) {
1217
buf.push(c.encode_utf8(&mut char_buf));
1318
}
1419
buf.push(suffix);
15-
buf
20+
Ok(buf)
1621
}
1722

1823
pub fn create_helper<R>(
@@ -30,7 +35,7 @@ pub fn create_helper<R>(
3035
};
3136

3237
for _ in 0..num_retries {
33-
let path = base.join(tmpname(prefix, suffix, random_len));
38+
let path = base.join(tmpname(prefix, suffix, random_len)?);
3439
return match f(path, permissions) {
3540
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists && num_retries > 1 => continue,
3641
// AddrInUse can happen if we're creating a UNIX domain socket and

tests/namedtempfile.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,16 @@ fn test_customnamed() {
104104
assert_eq!(name.len(), 18);
105105
}
106106

107+
#[test]
108+
fn test_customnamed_too_long() {
109+
assert!(Builder::new()
110+
.prefix("tmp")
111+
.suffix(&".rs")
112+
.rand_bytes(usize::MAX)
113+
.tempfile()
114+
.is_err());
115+
}
116+
107117
#[test]
108118
fn test_append() {
109119
let mut tmpfile = Builder::new().append(true).tempfile().unwrap();

0 commit comments

Comments
 (0)