2
2
//! standard file descriptors (stdin/stdout/stderr).
3
3
4
4
use std:: any:: Any ;
5
- use std:: cell:: { Ref , RefCell , RefMut } ;
6
5
use std:: collections:: BTreeMap ;
7
6
use std:: io:: { self , ErrorKind , IsTerminal , Read , SeekFrom , Write } ;
7
+ use std:: ops:: Deref ;
8
8
use std:: rc:: Rc ;
9
9
use std:: rc:: Weak ;
10
10
@@ -27,9 +27,9 @@ pub trait FileDescription: std::fmt::Debug + Any {
27
27
28
28
/// Reads as much as possible into the given buffer, and returns the number of bytes read.
29
29
fn read < ' tcx > (
30
- & mut self ,
30
+ & self ,
31
+ _self_ref : & FileDescriptionRef ,
31
32
_communicate_allowed : bool ,
32
- _fd_id : FdId ,
33
33
_bytes : & mut [ u8 ] ,
34
34
_ecx : & mut MiriInterpCx < ' tcx > ,
35
35
) -> InterpResult < ' tcx , io:: Result < usize > > {
@@ -38,9 +38,9 @@ pub trait FileDescription: std::fmt::Debug + Any {
38
38
39
39
/// Writes as much as possible from the given buffer, and returns the number of bytes written.
40
40
fn write < ' tcx > (
41
- & mut self ,
41
+ & self ,
42
+ _self_ref : & FileDescriptionRef ,
42
43
_communicate_allowed : bool ,
43
- _fd_id : FdId ,
44
44
_bytes : & [ u8 ] ,
45
45
_ecx : & mut MiriInterpCx < ' tcx > ,
46
46
) -> InterpResult < ' tcx , io:: Result < usize > > {
@@ -50,7 +50,7 @@ pub trait FileDescription: std::fmt::Debug + Any {
50
50
/// Reads as much as possible into the given buffer from a given offset,
51
51
/// and returns the number of bytes read.
52
52
fn pread < ' tcx > (
53
- & mut self ,
53
+ & self ,
54
54
_communicate_allowed : bool ,
55
55
_bytes : & mut [ u8 ] ,
56
56
_offset : u64 ,
@@ -62,7 +62,7 @@ pub trait FileDescription: std::fmt::Debug + Any {
62
62
/// Writes as much as possible from the given buffer starting at a given offset,
63
63
/// and returns the number of bytes written.
64
64
fn pwrite < ' tcx > (
65
- & mut self ,
65
+ & self ,
66
66
_communicate_allowed : bool ,
67
67
_bytes : & [ u8 ] ,
68
68
_offset : u64 ,
@@ -74,7 +74,7 @@ pub trait FileDescription: std::fmt::Debug + Any {
74
74
/// Seeks to the given offset (which can be relative to the beginning, end, or current position).
75
75
/// Returns the new position from the start of the stream.
76
76
fn seek < ' tcx > (
77
- & mut self ,
77
+ & self ,
78
78
_communicate_allowed : bool ,
79
79
_offset : SeekFrom ,
80
80
) -> InterpResult < ' tcx , io:: Result < u64 > > {
@@ -111,14 +111,9 @@ pub trait FileDescription: std::fmt::Debug + Any {
111
111
112
112
impl dyn FileDescription {
113
113
#[ inline( always) ]
114
- pub fn downcast_ref < T : Any > ( & self ) -> Option < & T > {
114
+ pub fn downcast < T : Any > ( & self ) -> Option < & T > {
115
115
( self as & dyn Any ) . downcast_ref ( )
116
116
}
117
-
118
- #[ inline( always) ]
119
- pub fn downcast_mut < T : Any > ( & mut self ) -> Option < & mut T > {
120
- ( self as & mut dyn Any ) . downcast_mut ( )
121
- }
122
117
}
123
118
124
119
impl FileDescription for io:: Stdin {
@@ -127,17 +122,17 @@ impl FileDescription for io::Stdin {
127
122
}
128
123
129
124
fn read < ' tcx > (
130
- & mut self ,
125
+ & self ,
126
+ _self_ref : & FileDescriptionRef ,
131
127
communicate_allowed : bool ,
132
- _fd_id : FdId ,
133
128
bytes : & mut [ u8 ] ,
134
129
_ecx : & mut MiriInterpCx < ' tcx > ,
135
130
) -> InterpResult < ' tcx , io:: Result < usize > > {
136
131
if !communicate_allowed {
137
132
// We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
138
133
helpers:: isolation_abort_error ( "`read` from stdin" ) ?;
139
134
}
140
- Ok ( Read :: read ( self , bytes) )
135
+ Ok ( Read :: read ( & mut { self } , bytes) )
141
136
}
142
137
143
138
fn is_tty ( & self , communicate_allowed : bool ) -> bool {
@@ -151,14 +146,14 @@ impl FileDescription for io::Stdout {
151
146
}
152
147
153
148
fn write < ' tcx > (
154
- & mut self ,
149
+ & self ,
150
+ _self_ref : & FileDescriptionRef ,
155
151
_communicate_allowed : bool ,
156
- _fd_id : FdId ,
157
152
bytes : & [ u8 ] ,
158
153
_ecx : & mut MiriInterpCx < ' tcx > ,
159
154
) -> InterpResult < ' tcx , io:: Result < usize > > {
160
155
// We allow writing to stderr even with isolation enabled.
161
- let result = Write :: write ( self , bytes) ;
156
+ let result = Write :: write ( & mut { self } , bytes) ;
162
157
// Stdout is buffered, flush to make sure it appears on the
163
158
// screen. This is the write() syscall of the interpreted
164
159
// program, we want it to correspond to a write() syscall on
@@ -180,9 +175,9 @@ impl FileDescription for io::Stderr {
180
175
}
181
176
182
177
fn write < ' tcx > (
183
- & mut self ,
178
+ & self ,
179
+ _self_ref : & FileDescriptionRef ,
184
180
_communicate_allowed : bool ,
185
- _fd_id : FdId ,
186
181
bytes : & [ u8 ] ,
187
182
_ecx : & mut MiriInterpCx < ' tcx > ,
188
183
) -> InterpResult < ' tcx , io:: Result < usize > > {
@@ -206,9 +201,9 @@ impl FileDescription for NullOutput {
206
201
}
207
202
208
203
fn write < ' tcx > (
209
- & mut self ,
204
+ & self ,
205
+ _self_ref : & FileDescriptionRef ,
210
206
_communicate_allowed : bool ,
211
- _fd_id : FdId ,
212
207
bytes : & [ u8 ] ,
213
208
_ecx : & mut MiriInterpCx < ' tcx > ,
214
209
) -> InterpResult < ' tcx , io:: Result < usize > > {
@@ -221,26 +216,23 @@ impl FileDescription for NullOutput {
221
216
#[ derive( Clone , Debug ) ]
222
217
pub struct FileDescWithId < T : FileDescription + ?Sized > {
223
218
id : FdId ,
224
- file_description : RefCell < Box < T > > ,
219
+ file_description : Box < T > ,
225
220
}
226
221
227
222
#[ derive( Clone , Debug ) ]
228
223
pub struct FileDescriptionRef ( Rc < FileDescWithId < dyn FileDescription > > ) ;
229
224
230
- impl FileDescriptionRef {
231
- fn new ( fd : impl FileDescription , id : FdId ) -> Self {
232
- FileDescriptionRef ( Rc :: new ( FileDescWithId {
233
- id,
234
- file_description : RefCell :: new ( Box :: new ( fd) ) ,
235
- } ) )
236
- }
225
+ impl Deref for FileDescriptionRef {
226
+ type Target = dyn FileDescription ;
237
227
238
- pub fn borrow ( & self ) -> Ref < ' _ , dyn FileDescription > {
239
- Ref :: map ( self . 0 . file_description . borrow ( ) , |fd| fd . as_ref ( ) )
228
+ fn deref ( & self ) -> & Self :: Target {
229
+ & * self . 0 . file_description
240
230
}
231
+ }
241
232
242
- pub fn borrow_mut ( & self ) -> RefMut < ' _ , dyn FileDescription > {
243
- RefMut :: map ( self . 0 . file_description . borrow_mut ( ) , |fd| fd. as_mut ( ) )
233
+ impl FileDescriptionRef {
234
+ fn new ( fd : impl FileDescription , id : FdId ) -> Self {
235
+ FileDescriptionRef ( Rc :: new ( FileDescWithId { id, file_description : Box :: new ( fd) } ) )
244
236
}
245
237
246
238
pub fn close < ' tcx > (
@@ -256,7 +248,7 @@ impl FileDescriptionRef {
256
248
// Remove entry from the global epoll_event_interest table.
257
249
ecx. machine . epoll_interests . remove ( id) ;
258
250
259
- RefCell :: into_inner ( fd. file_description ) . close ( communicate_allowed, ecx)
251
+ fd. file_description . close ( communicate_allowed, ecx)
260
252
}
261
253
None => Ok ( Ok ( ( ) ) ) ,
262
254
}
@@ -269,16 +261,6 @@ impl FileDescriptionRef {
269
261
pub fn get_id ( & self ) -> FdId {
270
262
self . 0 . id
271
263
}
272
-
273
- /// Function used to retrieve the readiness events of a file description and insert
274
- /// an `EpollEventInstance` into the ready list if the file description is ready.
275
- pub ( crate ) fn check_and_update_readiness < ' tcx > (
276
- & self ,
277
- ecx : & mut InterpCx < ' tcx , MiriMachine < ' tcx > > ,
278
- ) -> InterpResult < ' tcx , ( ) > {
279
- use crate :: shims:: unix:: linux:: epoll:: EvalContextExt ;
280
- ecx. check_and_update_readiness ( self . get_id ( ) , || self . borrow_mut ( ) . get_epoll_ready_events ( ) )
281
- }
282
264
}
283
265
284
266
/// Holds a weak reference to the actual file description.
@@ -334,11 +316,20 @@ impl FdTable {
334
316
fds
335
317
}
336
318
337
- /// Insert a new file description to the FdTable.
338
- pub fn insert_new ( & mut self , fd : impl FileDescription ) -> i32 {
319
+ pub fn new_ref ( & mut self , fd : impl FileDescription ) -> FileDescriptionRef {
339
320
let file_handle = FileDescriptionRef :: new ( fd, self . next_file_description_id ) ;
340
321
self . next_file_description_id = FdId ( self . next_file_description_id . 0 . strict_add ( 1 ) ) ;
341
- self . insert_ref_with_min_fd ( file_handle, 0 )
322
+ file_handle
323
+ }
324
+
325
+ /// Insert a new file description to the FdTable.
326
+ pub fn insert_new ( & mut self , fd : impl FileDescription ) -> i32 {
327
+ let fd_ref = self . new_ref ( fd) ;
328
+ self . insert ( fd_ref)
329
+ }
330
+
331
+ pub fn insert ( & mut self , fd_ref : FileDescriptionRef ) -> i32 {
332
+ self . insert_ref_with_min_fd ( fd_ref, 0 )
342
333
}
343
334
344
335
/// Insert a file description, giving it a file descriptor that is at least `min_fd`.
@@ -368,17 +359,7 @@ impl FdTable {
368
359
new_fd
369
360
}
370
361
371
- pub fn get ( & self , fd : i32 ) -> Option < Ref < ' _ , dyn FileDescription > > {
372
- let fd = self . fds . get ( & fd) ?;
373
- Some ( fd. borrow ( ) )
374
- }
375
-
376
- pub fn get_mut ( & self , fd : i32 ) -> Option < RefMut < ' _ , dyn FileDescription > > {
377
- let fd = self . fds . get ( & fd) ?;
378
- Some ( fd. borrow_mut ( ) )
379
- }
380
-
381
- pub fn get_ref ( & self , fd : i32 ) -> Option < FileDescriptionRef > {
362
+ pub fn get ( & self , fd : i32 ) -> Option < FileDescriptionRef > {
382
363
let fd = self . fds . get ( & fd) ?;
383
364
Some ( fd. clone ( ) )
384
365
}
@@ -397,7 +378,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
397
378
fn dup ( & mut self , old_fd : i32 ) -> InterpResult < ' tcx , Scalar > {
398
379
let this = self . eval_context_mut ( ) ;
399
380
400
- let Some ( dup_fd) = this. machine . fds . get_ref ( old_fd) else {
381
+ let Some ( dup_fd) = this. machine . fds . get ( old_fd) else {
401
382
return Ok ( Scalar :: from_i32 ( this. fd_not_found ( ) ?) ) ;
402
383
} ;
403
384
Ok ( Scalar :: from_i32 ( this. machine . fds . insert_ref_with_min_fd ( dup_fd, 0 ) ) )
@@ -406,7 +387,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
406
387
fn dup2 ( & mut self , old_fd : i32 , new_fd : i32 ) -> InterpResult < ' tcx , Scalar > {
407
388
let this = self . eval_context_mut ( ) ;
408
389
409
- let Some ( dup_fd) = this. machine . fds . get_ref ( old_fd) else {
390
+ let Some ( dup_fd) = this. machine . fds . get ( old_fd) else {
410
391
return Ok ( Scalar :: from_i32 ( this. fd_not_found ( ) ?) ) ;
411
392
} ;
412
393
if new_fd != old_fd {
@@ -492,7 +473,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
492
473
}
493
474
let start = this. read_scalar ( & args[ 2 ] ) ?. to_i32 ( ) ?;
494
475
495
- match this. machine . fds . get_ref ( fd) {
476
+ match this. machine . fds . get ( fd) {
496
477
Some ( dup_fd) =>
497
478
Ok ( Scalar :: from_i32 ( this. machine . fds . insert_ref_with_min_fd ( dup_fd, start) ) ) ,
498
479
None => Ok ( Scalar :: from_i32 ( this. fd_not_found ( ) ?) ) ,
@@ -565,7 +546,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
565
546
let communicate = this. machine . communicate ( ) ;
566
547
567
548
// We temporarily dup the FD to be able to retain mutable access to `this`.
568
- let Some ( fd) = this. machine . fds . get_ref ( fd) else {
549
+ let Some ( fd) = this. machine . fds . get ( fd) else {
569
550
trace ! ( "read: FD not found" ) ;
570
551
return Ok ( Scalar :: from_target_isize ( this. fd_not_found ( ) ?, this) ) ;
571
552
} ;
@@ -576,14 +557,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
576
557
// `usize::MAX` because it is bounded by the host's `isize`.
577
558
let mut bytes = vec ! [ 0 ; usize :: try_from( count) . unwrap( ) ] ;
578
559
let result = match offset {
579
- None => fd. borrow_mut ( ) . read ( communicate , fd . get_id ( ) , & mut bytes, this) ,
560
+ None => fd. read ( & fd , communicate , & mut bytes, this) ,
580
561
Some ( offset) => {
581
562
let Ok ( offset) = u64:: try_from ( offset) else {
582
563
let einval = this. eval_libc ( "EINVAL" ) ;
583
564
this. set_last_error ( einval) ?;
584
565
return Ok ( Scalar :: from_target_isize ( -1 , this) ) ;
585
566
} ;
586
- fd. borrow_mut ( ) . pread ( communicate, & mut bytes, offset, this)
567
+ fd. pread ( communicate, & mut bytes, offset, this)
587
568
}
588
569
} ;
589
570
@@ -629,19 +610,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
629
610
630
611
let bytes = this. read_bytes_ptr_strip_provenance ( buf, Size :: from_bytes ( count) ) ?. to_owned ( ) ;
631
612
// We temporarily dup the FD to be able to retain mutable access to `this`.
632
- let Some ( fd) = this. machine . fds . get_ref ( fd) else {
613
+ let Some ( fd) = this. machine . fds . get ( fd) else {
633
614
return Ok ( Scalar :: from_target_isize ( this. fd_not_found ( ) ?, this) ) ;
634
615
} ;
635
616
636
617
let result = match offset {
637
- None => fd. borrow_mut ( ) . write ( communicate , fd . get_id ( ) , & bytes, this) ,
618
+ None => fd. write ( & fd , communicate , & bytes, this) ,
638
619
Some ( offset) => {
639
620
let Ok ( offset) = u64:: try_from ( offset) else {
640
621
let einval = this. eval_libc ( "EINVAL" ) ;
641
622
this. set_last_error ( einval) ?;
642
623
return Ok ( Scalar :: from_target_isize ( -1 , this) ) ;
643
624
} ;
644
- fd. borrow_mut ( ) . pwrite ( communicate, & bytes, offset, this)
625
+ fd. pwrite ( communicate, & bytes, offset, this)
645
626
}
646
627
} ;
647
628
0 commit comments