@@ -83,6 +83,48 @@ fn copies_append_mode_sink() -> Result<()> {
8383 Ok ( ( ) )
8484}
8585
86+ #[ test]
87+ fn dont_splice_pipes_from_files ( ) -> Result < ( ) > {
88+ // splicing to a pipe and then modifying the source could lead to changes
89+ // becoming visible in an unexpected order.
90+
91+ use crate :: io:: SeekFrom ;
92+ use crate :: os:: unix:: fs:: FileExt ;
93+ use crate :: process:: { ChildStdin , ChildStdout } ;
94+ use crate :: sys_common:: FromInner ;
95+
96+ let ( read_end, write_end) = crate :: sys:: pipe:: anon_pipe ( ) ?;
97+
98+ let mut read_end = ChildStdout :: from_inner ( read_end) ;
99+ let mut write_end = ChildStdin :: from_inner ( write_end) ;
100+
101+ let tmp_path = tmpdir ( ) ;
102+ let file = tmp_path. join ( "to_be_modified" ) ;
103+ let mut file =
104+ crate :: fs:: OpenOptions :: new ( ) . create_new ( true ) . read ( true ) . write ( true ) . open ( file) ?;
105+
106+ const SZ : usize = libc:: PIPE_BUF as usize ;
107+
108+ // put data in page cache
109+ let mut buf: [ u8 ; SZ ] = [ 0x01 ; SZ ] ;
110+ file. write_all ( & buf) . unwrap ( ) ;
111+
112+ // copy page into pipe
113+ file. seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
114+ assert ! ( io:: copy( & mut file, & mut write_end) . unwrap( ) == SZ as u64 ) ;
115+
116+ // modify file
117+ buf[ 0 ] = 0x02 ;
118+ file. write_at ( & buf, 0 ) . unwrap ( ) ;
119+
120+ // read from pipe
121+ read_end. read_exact ( buf. as_mut_slice ( ) ) . unwrap ( ) ;
122+
123+ assert_eq ! ( buf[ 0 ] , 0x01 , "data in pipe should reflect the original, not later modifications" ) ;
124+
125+ Ok ( ( ) )
126+ }
127+
86128#[ bench]
87129fn bench_file_to_file_copy ( b : & mut test:: Bencher ) {
88130 const BYTES : usize = 128 * 1024 ;
0 commit comments