Skip to content

Commit fbec632

Browse files
committed
tac: use mmap instead of reading temp file back into Vec
1 parent 4e74674 commit fbec632

File tree

1 file changed

+21
-12
lines changed

1 file changed

+21
-12
lines changed

src/uu/tac/src/tac.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use clap::{Arg, ArgAction, Command};
1010
use memchr::memmem;
1111
use memmap2::Mmap;
1212
use std::ffi::OsString;
13-
use std::io::{BufWriter, Read, Seek, Write, stdin, stdout};
13+
use std::io::{BufWriter, Read, Write, stdin, stdout};
1414
use std::{
1515
fs::{File, read},
1616
io::copy,
@@ -242,10 +242,14 @@ fn tac(filenames: &[OsString], before: bool, regex: bool, separator: &str) -> UR
242242
mmap = mmap1;
243243
&mmap
244244
} else {
245-
// Copy stdin to a temp file (respects TMPDIR), then read it back.
246-
// This allows proper error handling when disk space is exhausted.
247-
match read_stdin_to_buf() {
248-
Ok(buf1) => {
245+
// Copy stdin to a temp file (respects TMPDIR), then mmap it.
246+
// Falls back to Vec buffer if temp file creation fails (e.g., bad TMPDIR).
247+
match buffer_stdin() {
248+
Ok(StdinData::Mmap(mmap1)) => {
249+
mmap = mmap1;
250+
&mmap
251+
}
252+
Ok(StdinData::Vec(buf1)) => {
249253
buf = buf1;
250254
&buf
251255
}
@@ -309,22 +313,27 @@ fn try_mmap_stdin() -> Option<Mmap> {
309313
unsafe { Mmap::map(&stdin()).ok() }
310314
}
311315

312-
/// Copy stdin to a temp file, then read it into a buffer.
316+
enum StdinData {
317+
Mmap(Mmap),
318+
Vec(Vec<u8>),
319+
}
320+
321+
/// Copy stdin to a temp file, then memory-map it.
313322
/// Falls back to reading directly into memory if temp file creation fails.
314-
fn read_stdin_to_buf() -> std::io::Result<Vec<u8>> {
323+
fn buffer_stdin() -> std::io::Result<StdinData> {
315324
// Try to create a temp file (respects TMPDIR)
316325
if let Ok(mut tmp) = tempfile::tempfile() {
317326
// Temp file created - copy stdin to it, then read back
318327
copy(&mut stdin(), &mut tmp)?;
319-
tmp.rewind()?;
320-
let mut buf = Vec::new();
321-
tmp.read_to_end(&mut buf)?;
322-
Ok(buf)
328+
// SAFETY: If the file is truncated while we map it, SIGBUS will be raised
329+
// and our process will be terminated, thus preventing access of invalid memory.
330+
let mmap = unsafe { Mmap::map(&tmp)? };
331+
Ok(StdinData::Mmap(mmap))
323332
} else {
324333
// Fall back to reading directly into memory (e.g., bad TMPDIR)
325334
let mut buf = Vec::new();
326335
stdin().read_to_end(&mut buf)?;
327-
Ok(buf)
336+
Ok(StdinData::Vec(buf))
328337
}
329338
}
330339

0 commit comments

Comments
 (0)