@@ -13,6 +13,7 @@ use std::ffi::OsString;
1313use std:: io:: { BufWriter , Read , Write , stdin, stdout} ;
1414use std:: {
1515 fs:: { File , read} ,
16+ io:: copy,
1617 path:: Path ,
1718} ;
1819use uucore:: error:: UError ;
@@ -241,14 +242,22 @@ fn tac(filenames: &[OsString], before: bool, regex: bool, separator: &str) -> UR
241242 mmap = mmap1;
242243 & mmap
243244 } else {
244- let mut buf1 = Vec :: new ( ) ;
245- if let Err ( e) = stdin ( ) . read_to_end ( & mut buf1) {
246- let e: Box < dyn UError > = TacError :: ReadError ( OsString :: from ( "stdin" ) , e) . into ( ) ;
247- show ! ( e) ;
248- continue ;
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) ) => {
253+ buf = buf1;
254+ & buf
255+ }
256+ Err ( e) => {
257+ show ! ( TacError :: ReadError ( OsString :: from( "stdin" ) , e) ) ;
258+ continue ;
259+ }
249260 }
250- buf = buf1;
251- & buf
252261 }
253262 } else {
254263 let path = Path :: new ( filename) ;
@@ -304,6 +313,30 @@ fn try_mmap_stdin() -> Option<Mmap> {
304313 unsafe { Mmap :: map ( & stdin ( ) ) . ok ( ) }
305314}
306315
316+ enum StdinData {
317+ Mmap ( Mmap ) ,
318+ Vec ( Vec < u8 > ) ,
319+ }
320+
321+ /// Copy stdin to a temp file, then memory-map it.
322+ /// Falls back to reading directly into memory if temp file creation fails.
323+ fn buffer_stdin ( ) -> std:: io:: Result < StdinData > {
324+ // Try to create a temp file (respects TMPDIR)
325+ if let Ok ( mut tmp) = tempfile:: tempfile ( ) {
326+ // Temp file created - copy stdin to it, then read back
327+ copy ( & mut stdin ( ) , & mut tmp) ?;
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) )
332+ } else {
333+ // Fall back to reading directly into memory (e.g., bad TMPDIR)
334+ let mut buf = Vec :: new ( ) ;
335+ stdin ( ) . read_to_end ( & mut buf) ?;
336+ Ok ( StdinData :: Vec ( buf) )
337+ }
338+ }
339+
307340fn try_mmap_path ( path : & Path ) -> Option < Mmap > {
308341 let file = File :: open ( path) . ok ( ) ?;
309342
0 commit comments