@@ -83,6 +83,48 @@ fn copies_append_mode_sink() -> Result<()> {
83
83
Ok ( ( ) )
84
84
}
85
85
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
+
86
128
#[ bench]
87
129
fn bench_file_to_file_copy ( b : & mut test:: Bencher ) {
88
130
const BYTES : usize = 128 * 1024 ;
0 commit comments