1
1
use std:: any:: Any ;
2
2
use std:: collections:: BTreeMap ;
3
- use std:: io:: { IsTerminal , Read , SeekFrom , Write } ;
3
+ use std:: io:: { IsTerminal , SeekFrom , Write } ;
4
4
use std:: marker:: CoercePointee ;
5
5
use std:: ops:: Deref ;
6
6
use std:: rc:: { Rc , Weak } ;
@@ -140,8 +140,8 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
140
140
_communicate_allowed : bool ,
141
141
_ptr : Pointer ,
142
142
_len : usize ,
143
- _dest : & MPlaceTy < ' tcx > ,
144
143
_ecx : & mut MiriInterpCx < ' tcx > ,
144
+ _finish : DynMachineCallback < ' tcx , Result < usize , IoError > > ,
145
145
) -> InterpResult < ' tcx > {
146
146
throw_unsup_format ! ( "cannot read from {}" , self . name( ) ) ;
147
147
}
@@ -154,8 +154,8 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
154
154
_communicate_allowed : bool ,
155
155
_ptr : Pointer ,
156
156
_len : usize ,
157
- _dest : & MPlaceTy < ' tcx > ,
158
157
_ecx : & mut MiriInterpCx < ' tcx > ,
158
+ _finish : DynMachineCallback < ' tcx , Result < usize , IoError > > ,
159
159
) -> InterpResult < ' tcx > {
160
160
throw_unsup_format ! ( "cannot write to {}" , self . name( ) ) ;
161
161
}
@@ -207,19 +207,16 @@ impl FileDescription for io::Stdin {
207
207
communicate_allowed : bool ,
208
208
ptr : Pointer ,
209
209
len : usize ,
210
- dest : & MPlaceTy < ' tcx > ,
211
210
ecx : & mut MiriInterpCx < ' tcx > ,
211
+ finish : DynMachineCallback < ' tcx , Result < usize , IoError > > ,
212
212
) -> InterpResult < ' tcx > {
213
- let mut bytes = vec ! [ 0 ; len] ;
214
213
if !communicate_allowed {
215
214
// We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
216
215
helpers:: isolation_abort_error ( "`read` from stdin" ) ?;
217
216
}
218
- let result = Read :: read ( & mut & * self , & mut bytes) ;
219
- match result {
220
- Ok ( read_size) => ecx. return_read_success ( ptr, & bytes, read_size, dest) ,
221
- Err ( e) => ecx. set_last_error_and_return ( e, dest) ,
222
- }
217
+
218
+ let result = ecx. read_from_host ( & * self , len, ptr) ?;
219
+ finish. call ( ecx, result)
223
220
}
224
221
225
222
fn is_tty ( & self , communicate_allowed : bool ) -> bool {
@@ -237,22 +234,19 @@ impl FileDescription for io::Stdout {
237
234
_communicate_allowed : bool ,
238
235
ptr : Pointer ,
239
236
len : usize ,
240
- dest : & MPlaceTy < ' tcx > ,
241
237
ecx : & mut MiriInterpCx < ' tcx > ,
238
+ finish : DynMachineCallback < ' tcx , Result < usize , IoError > > ,
242
239
) -> InterpResult < ' tcx > {
243
- let bytes = ecx. read_bytes_ptr_strip_provenance ( ptr, Size :: from_bytes ( len) ) ?;
244
- // We allow writing to stderr even with isolation enabled.
245
- let result = Write :: write ( & mut & * self , bytes) ;
240
+ // We allow writing to stdout even with isolation enabled.
241
+ let result = ecx. write_to_host ( & * self , len, ptr) ?;
246
242
// Stdout is buffered, flush to make sure it appears on the
247
243
// screen. This is the write() syscall of the interpreted
248
244
// program, we want it to correspond to a write() syscall on
249
245
// the host -- there is no good in adding extra buffering
250
246
// here.
251
247
io:: stdout ( ) . flush ( ) . unwrap ( ) ;
252
- match result {
253
- Ok ( write_size) => ecx. return_write_success ( write_size, dest) ,
254
- Err ( e) => ecx. set_last_error_and_return ( e, dest) ,
255
- }
248
+
249
+ finish. call ( ecx, result)
256
250
}
257
251
258
252
fn is_tty ( & self , communicate_allowed : bool ) -> bool {
@@ -270,17 +264,13 @@ impl FileDescription for io::Stderr {
270
264
_communicate_allowed : bool ,
271
265
ptr : Pointer ,
272
266
len : usize ,
273
- dest : & MPlaceTy < ' tcx > ,
274
267
ecx : & mut MiriInterpCx < ' tcx > ,
268
+ finish : DynMachineCallback < ' tcx , Result < usize , IoError > > ,
275
269
) -> InterpResult < ' tcx > {
276
- let bytes = ecx. read_bytes_ptr_strip_provenance ( ptr, Size :: from_bytes ( len) ) ?;
277
270
// We allow writing to stderr even with isolation enabled.
271
+ let result = ecx. write_to_host ( & * self , len, ptr) ?;
278
272
// No need to flush, stderr is not buffered.
279
- let result = Write :: write ( & mut & * self , bytes) ;
280
- match result {
281
- Ok ( write_size) => ecx. return_write_success ( write_size, dest) ,
282
- Err ( e) => ecx. set_last_error_and_return ( e, dest) ,
283
- }
273
+ finish. call ( ecx, result)
284
274
}
285
275
286
276
fn is_tty ( & self , communicate_allowed : bool ) -> bool {
@@ -302,11 +292,11 @@ impl FileDescription for NullOutput {
302
292
_communicate_allowed : bool ,
303
293
_ptr : Pointer ,
304
294
len : usize ,
305
- dest : & MPlaceTy < ' tcx > ,
306
295
ecx : & mut MiriInterpCx < ' tcx > ,
296
+ finish : DynMachineCallback < ' tcx , Result < usize , IoError > > ,
307
297
) -> InterpResult < ' tcx > {
308
298
// We just don't write anything, but report to the user that we did.
309
- ecx . return_write_success ( len , dest )
299
+ finish . call ( ecx , Ok ( len ) )
310
300
}
311
301
}
312
302
@@ -405,40 +395,41 @@ impl FdTable {
405
395
406
396
impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
407
397
pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
408
- /// Helper to implement `FileDescription::read`:
409
- /// This is only used when `read` is successful.
410
- /// `actual_read_size` should be the return value of some underlying `read` call that used
411
- /// `bytes` as its output buffer.
412
- /// The length of `bytes` must not exceed either the host's or the target's `isize`.
413
- /// `bytes` is written to `buf` and the size is written to `dest`.
414
- fn return_read_success (
398
+ /// Read data from a host `Read` type, store the result into machine memory,
399
+ /// and return whether that worked.
400
+ fn read_from_host (
415
401
& mut self ,
416
- buf : Pointer ,
417
- bytes : & [ u8 ] ,
418
- actual_read_size : usize ,
419
- dest : & MPlaceTy < ' tcx > ,
420
- ) -> InterpResult < ' tcx > {
402
+ mut file : impl io:: Read ,
403
+ len : usize ,
404
+ ptr : Pointer ,
405
+ ) -> InterpResult < ' tcx , Result < usize , IoError > > {
421
406
let this = self . eval_context_mut ( ) ;
422
- // If reading to `bytes` did not fail, we write those bytes to the buffer.
423
- // Crucially, if fewer than `bytes.len()` bytes were read, only write
424
- // that much into the output buffer!
425
- this. write_bytes_ptr ( buf, bytes[ ..actual_read_size] . iter ( ) . copied ( ) ) ?;
426
407
427
- // The actual read size is always less than what got originally requested so this cannot fail.
428
- this. write_int ( u64:: try_from ( actual_read_size) . unwrap ( ) , dest) ?;
429
- interp_ok ( ( ) )
408
+ let mut bytes = vec ! [ 0 ; len] ;
409
+ let result = file. read ( & mut bytes) ;
410
+ match result {
411
+ Ok ( read_size) => {
412
+ // If reading to `bytes` did not fail, we write those bytes to the buffer.
413
+ // Crucially, if fewer than `bytes.len()` bytes were read, only write
414
+ // that much into the output buffer!
415
+ this. write_bytes_ptr ( ptr, bytes[ ..read_size] . iter ( ) . copied ( ) ) ?;
416
+ interp_ok ( Ok ( read_size) )
417
+ }
418
+ Err ( e) => interp_ok ( Err ( IoError :: HostError ( e) ) ) ,
419
+ }
430
420
}
431
421
432
- /// Helper to implement `FileDescription::write`:
433
- /// This function is only used when `write` is successful, and writes `actual_write_size` to `dest`
434
- fn return_write_success (
422
+ /// Write data to a host `Write` type, withthe bytes taken from machine memory.
423
+ fn write_to_host (
435
424
& mut self ,
436
- actual_write_size : usize ,
437
- dest : & MPlaceTy < ' tcx > ,
438
- ) -> InterpResult < ' tcx > {
425
+ mut file : impl io:: Write ,
426
+ len : usize ,
427
+ ptr : Pointer ,
428
+ ) -> InterpResult < ' tcx , Result < usize , IoError > > {
439
429
let this = self . eval_context_mut ( ) ;
440
- // The actual write size is always less than what got originally requested so this cannot fail.
441
- this. write_int ( u64:: try_from ( actual_write_size) . unwrap ( ) , dest) ?;
442
- interp_ok ( ( ) )
430
+
431
+ let bytes = this. read_bytes_ptr_strip_provenance ( ptr, Size :: from_bytes ( len) ) ?;
432
+ let result = file. write ( bytes) ;
433
+ interp_ok ( result. map_err ( IoError :: HostError ) )
443
434
}
444
435
}
0 commit comments