@@ -10,7 +10,7 @@ use clap::{Arg, ArgAction, Command};
1010use memchr:: memmem;
1111use memmap2:: Mmap ;
1212use std:: ffi:: OsString ;
13- use std:: io:: { BufWriter , Read , Seek , Write , stdin, stdout} ;
13+ use std:: io:: { BufWriter , Read , Write , stdin, stdout} ;
1414use 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