@@ -28,6 +28,7 @@ trait FileDescriptor : std::fmt::Debug {
28
28
fn read < ' tcx > ( & mut self , communicate_allowed : bool , bytes : & mut [ u8 ] ) -> InterpResult < ' tcx , io:: Result < usize > > ;
29
29
fn write < ' tcx > ( & mut self , communicate_allowed : bool , bytes : & [ u8 ] ) -> InterpResult < ' tcx , io:: Result < usize > > ;
30
30
fn seek < ' tcx > ( & mut self , communicate_allowed : bool , offset : SeekFrom ) -> InterpResult < ' tcx , io:: Result < u64 > > ;
31
+ fn close < ' tcx > ( & mut self , communicate_allowed : bool ) -> InterpResult < ' tcx , io:: Result < i32 > > ;
31
32
}
32
33
33
34
impl FileDescriptor for FileHandle {
@@ -49,6 +50,29 @@ impl FileDescriptor for FileHandle {
49
50
assert ! ( communicate_allowed, "isolation should have prevented even opening a file" ) ;
50
51
Ok ( self . file . seek ( offset) )
51
52
}
53
+
54
+ fn close < ' tcx > ( & mut self , communicate_allowed : bool ) -> InterpResult < ' tcx , io:: Result < i32 > > {
55
+ assert ! ( communicate_allowed, "isolation should have prevented even opening a file" ) ;
56
+ // We sync the file if it was opened in a mode different than read-only.
57
+ if self . writable {
58
+ // `File::sync_all` does the checks that are done when closing a file. We do this to
59
+ // to handle possible errors correctly.
60
+ let result = self . file . sync_all ( ) . map ( |_| 0i32 ) ;
61
+ // Now we actually close the file.
62
+ drop ( self ) ;
63
+ // And return the result.
64
+ Ok ( result)
65
+ } else {
66
+ // We drop the file, this closes it but ignores any errors
67
+ // produced when closing it. This is done because
68
+ // `File::sync_all` cannot be done over files like
69
+ // `/dev/urandom` which are read-only. Check
70
+ // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
71
+ // for a deeper discussion.
72
+ drop ( self ) ;
73
+ Ok ( Ok ( 0 ) )
74
+ }
75
+ }
52
76
}
53
77
54
78
impl FileDescriptor for io:: Stdin {
@@ -71,6 +95,11 @@ impl FileDescriptor for io::Stdin {
71
95
fn seek < ' tcx > ( & mut self , _communicate_allowed : bool , _offset : SeekFrom ) -> InterpResult < ' tcx , io:: Result < u64 > > {
72
96
throw_unsup_format ! ( "cannot seek on stdin" ) ;
73
97
}
98
+
99
+ fn close < ' tcx > ( & mut self , _communicate_allowed : bool ) -> InterpResult < ' tcx , io:: Result < i32 > > {
100
+ drop ( io:: stdin ( ) ) ;
101
+ Ok ( Ok ( 0 ) )
102
+ }
74
103
}
75
104
76
105
impl FileDescriptor for io:: Stdout {
@@ -98,6 +127,11 @@ impl FileDescriptor for io::Stdout {
98
127
fn seek < ' tcx > ( & mut self , _communicate_allowed : bool , _offset : SeekFrom ) -> InterpResult < ' tcx , io:: Result < u64 > > {
99
128
throw_unsup_format ! ( "cannot seek on stdout" ) ;
100
129
}
130
+
131
+ fn close < ' tcx > ( & mut self , _communicate_allowed : bool ) -> InterpResult < ' tcx , io:: Result < i32 > > {
132
+ drop ( io:: stdout ( ) ) ;
133
+ Ok ( Ok ( 0 ) )
134
+ }
101
135
}
102
136
103
137
impl FileDescriptor for io:: Stderr {
@@ -118,6 +152,11 @@ impl FileDescriptor for io::Stderr {
118
152
fn seek < ' tcx > ( & mut self , _communicate_allowed : bool , _offset : SeekFrom ) -> InterpResult < ' tcx , io:: Result < u64 > > {
119
153
throw_unsup_format ! ( "cannot seek on stderr" ) ;
120
154
}
155
+
156
+ fn close < ' tcx > ( & mut self , _communicate_allowed : bool ) -> InterpResult < ' tcx , io:: Result < i32 > > {
157
+ drop ( io:: stderr ( ) ) ;
158
+ Ok ( Ok ( 0 ) )
159
+ }
121
160
}
122
161
123
162
#[ derive( Debug ) ]
@@ -539,27 +578,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
539
578
540
579
let fd = this. read_scalar ( fd_op) ?. to_i32 ( ) ?;
541
580
542
- if let Some ( file_descriptor) = this. machine . file_handler . handles . remove ( & fd) {
543
- // FIXME: Support `close` for all FDs(stdin, etc)
544
- let FileHandle { file, writable } = file_descriptor. as_file_handle ( ) ?;
545
- // We sync the file if it was opened in a mode different than read-only.
546
- if * writable {
547
- // `File::sync_all` does the checks that are done when closing a file. We do this to
548
- // to handle possible errors correctly.
549
- let result = this. try_unwrap_io_result ( file. sync_all ( ) . map ( |_| 0i32 ) ) ;
550
- // Now we actually close the file.
551
- drop ( file) ;
552
- // And return the result.
553
- result
554
- } else {
555
- // We drop the file, this closes it but ignores any errors produced when closing
556
- // it. This is done because `File::sync_all` cannot be done over files like
557
- // `/dev/urandom` which are read-only. Check
558
- // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper
559
- // discussion.
560
- drop ( file) ;
561
- Ok ( 0 )
562
- }
581
+ if let Some ( mut file_descriptor) = this. machine . file_handler . handles . remove ( & fd) {
582
+ let result = file_descriptor. close ( this. machine . communicate ) ?
583
+ . map ( |c| i32:: try_from ( c) . unwrap ( ) ) ;
584
+
585
+ this. try_unwrap_io_result ( result)
563
586
} else {
564
587
this. handle_not_found ( )
565
588
}
0 commit comments