@@ -151,7 +151,11 @@ impl FileDescription for io::Stdin {
151151 helpers:: isolation_abort_error ( "`read` from stdin" ) ?;
152152 }
153153 let result = Read :: read ( & mut { self } , & mut bytes) ;
154- ecx. return_read_bytes_and_count ( ptr, & bytes, result, dest)
154+ match result {
155+ Ok ( rw_bytes) =>
156+ ecx. return_read_write_success ( Some ( ptr) , Some ( & bytes) , true , rw_bytes, dest) ,
157+ Err ( e) => ecx. return_read_write_error ( e, dest) ,
158+ }
155159 }
156160
157161 fn is_tty ( & self , communicate_allowed : bool ) -> bool {
@@ -182,7 +186,10 @@ impl FileDescription for io::Stdout {
182186 // the host -- there is no good in adding extra buffering
183187 // here.
184188 io:: stdout ( ) . flush ( ) . unwrap ( ) ;
185- ecx. return_written_byte_count_or_error ( result, dest)
189+ match result {
190+ Ok ( rw_bytes) => ecx. return_read_write_success ( None , None , false , rw_bytes, dest) ,
191+ Err ( e) => ecx. return_read_write_error ( e, dest) ,
192+ }
186193 }
187194
188195 fn is_tty ( & self , communicate_allowed : bool ) -> bool {
@@ -208,7 +215,10 @@ impl FileDescription for io::Stderr {
208215 // We allow writing to stderr even with isolation enabled.
209216 // No need to flush, stderr is not buffered.
210217 let result = Write :: write ( & mut { self } , bytes) ;
211- ecx. return_written_byte_count_or_error ( result, dest)
218+ match result {
219+ Ok ( rw_bytes) => ecx. return_read_write_success ( None , None , false , rw_bytes, dest) ,
220+ Err ( e) => ecx. return_read_write_error ( e, dest) ,
221+ }
212222 }
213223
214224 fn is_tty ( & self , communicate_allowed : bool ) -> bool {
@@ -235,8 +245,7 @@ impl FileDescription for NullOutput {
235245 ecx : & mut MiriInterpCx < ' tcx > ,
236246 ) -> InterpResult < ' tcx > {
237247 // We just don't write anything, but report to the user that we did.
238- let result = Ok ( len) ;
239- ecx. return_written_byte_count_or_error ( result, dest)
248+ ecx. return_read_write_success ( None , None , false , len, dest)
240249 }
241250}
242251
@@ -655,47 +664,44 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
655664 Ok ( ( ) )
656665 }
657666
658- /// Helper to implement `FileDescription::read`:
659- /// `result` should be the return value of some underlying `read` call that used `bytes` as its output buffer.
667+ /// Helper to implement `FileDescription::read/write`:
660668 /// The length of `bytes` must not exceed either the host's or the target's `isize`.
661- /// If `Result` indicates success, `bytes` is written to `buf` and the size is written to `dest`.
662- /// Otherwise, `-1` is written to `dest` and the last libc error is set appropriately.
663- fn return_read_bytes_and_count (
669+ /// `is_read` is used to indicate if this helper is used for `read`.
670+ /// If it is `read`, `bytes` is written to `buf`.
671+ /// For both `read` and `write`,`actual_rw_size`, which is the actual read/write size,
672+ /// is written to `dest`.
673+ fn return_read_write_success (
664674 & mut self ,
665- buf : Pointer ,
666- bytes : & [ u8 ] ,
667- result : io:: Result < usize > ,
675+ buf : Option < Pointer > ,
676+ bytes : Option < & [ u8 ] > ,
677+ is_read : bool ,
678+ actual_rw_size : usize ,
668679 dest : & MPlaceTy < ' tcx > ,
669680 ) -> InterpResult < ' tcx > {
670681 let this = self . eval_context_mut ( ) ;
671- match result {
672- Ok ( read_bytes) => {
673- // If reading to `bytes` did not fail, we write those bytes to the buffer.
674- // Crucially, if fewer than `bytes.len()` bytes were read, only write
675- // that much into the output buffer!
676- this. write_bytes_ptr ( buf, bytes[ ..read_bytes] . iter ( ) . copied ( ) ) ?;
677- // The actual read size is always less than what got originally requested so this cannot fail.
678- this. write_int ( u64:: try_from ( read_bytes) . unwrap ( ) , dest) ?;
679- Ok ( ( ) )
680- }
681- Err ( e) => {
682- this. set_last_error_from_io_error ( e) ?;
683- this. write_int ( -1 , dest) ?;
684- Ok ( ( ) )
685- }
682+ if is_read {
683+ let bytes = bytes. unwrap ( ) ;
684+ // If reading to `bytes` did not fail, we write those bytes to the buffer.
685+ // Crucially, if fewer than `bytes.len()` bytes were read, only write
686+ // that much into the output buffer!
687+ this. write_bytes_ptr ( buf. unwrap ( ) , bytes[ ..actual_rw_size] . iter ( ) . copied ( ) ) ?;
686688 }
689+ // The actual read/write size is always less than what got originally requested so this cannot fail.
690+ this. write_int ( u64:: try_from ( actual_rw_size) . unwrap ( ) , dest) ?;
691+ Ok ( ( ) )
687692 }
688693
689- /// This function writes the number of written bytes (given in `result`) to `dest`, or sets the
690- /// last libc error and writes -1 to dest.
691- fn return_written_byte_count_or_error (
694+ /// Helper to implement `FileDescription::read/write`.
695+ /// This is only used when there is a read/write error.
696+ ///`-1` is written to `dest` and the last libc error is set appropriately.
697+ fn return_read_write_error (
692698 & mut self ,
693- result : io:: Result < usize > ,
699+ err : io:: Error ,
694700 dest : & MPlaceTy < ' tcx > ,
695701 ) -> InterpResult < ' tcx > {
696702 let this = self . eval_context_mut ( ) ;
697- let result = this. try_unwrap_io_result ( result . map ( |c| i64 :: try_from ( c ) . unwrap ( ) ) ) ?;
698- this. write_int ( result , dest) ?;
703+ this. set_last_error ( this . io_error_to_errnum ( err ) ? ) ?;
704+ this. write_int ( - 1 , dest) ?;
699705 Ok ( ( ) )
700706 }
701707}
0 commit comments