22//! standard file descriptors (stdin/stdout/stderr).
33
44use std:: any:: Any ;
5- use std:: cell:: { Ref , RefCell , RefMut } ;
65use std:: collections:: BTreeMap ;
76use std:: io:: { self , ErrorKind , IsTerminal , Read , SeekFrom , Write } ;
7+ use std:: ops:: Deref ;
88use std:: rc:: Rc ;
99use std:: rc:: Weak ;
1010
@@ -27,9 +27,9 @@ pub trait FileDescription: std::fmt::Debug + Any {
2727
2828 /// Reads as much as possible into the given buffer, and returns the number of bytes read.
2929 fn read < ' tcx > (
30- & mut self ,
30+ & self ,
31+ _self_ref : & FileDescriptionRef ,
3132 _communicate_allowed : bool ,
32- _fd_id : FdId ,
3333 _bytes : & mut [ u8 ] ,
3434 _ecx : & mut MiriInterpCx < ' tcx > ,
3535 ) -> InterpResult < ' tcx , io:: Result < usize > > {
@@ -38,9 +38,9 @@ pub trait FileDescription: std::fmt::Debug + Any {
3838
3939 /// Writes as much as possible from the given buffer, and returns the number of bytes written.
4040 fn write < ' tcx > (
41- & mut self ,
41+ & self ,
42+ _self_ref : & FileDescriptionRef ,
4243 _communicate_allowed : bool ,
43- _fd_id : FdId ,
4444 _bytes : & [ u8 ] ,
4545 _ecx : & mut MiriInterpCx < ' tcx > ,
4646 ) -> InterpResult < ' tcx , io:: Result < usize > > {
@@ -50,7 +50,7 @@ pub trait FileDescription: std::fmt::Debug + Any {
5050 /// Reads as much as possible into the given buffer from a given offset,
5151 /// and returns the number of bytes read.
5252 fn pread < ' tcx > (
53- & mut self ,
53+ & self ,
5454 _communicate_allowed : bool ,
5555 _bytes : & mut [ u8 ] ,
5656 _offset : u64 ,
@@ -62,7 +62,7 @@ pub trait FileDescription: std::fmt::Debug + Any {
6262 /// Writes as much as possible from the given buffer starting at a given offset,
6363 /// and returns the number of bytes written.
6464 fn pwrite < ' tcx > (
65- & mut self ,
65+ & self ,
6666 _communicate_allowed : bool ,
6767 _bytes : & [ u8 ] ,
6868 _offset : u64 ,
@@ -74,7 +74,7 @@ pub trait FileDescription: std::fmt::Debug + Any {
7474 /// Seeks to the given offset (which can be relative to the beginning, end, or current position).
7575 /// Returns the new position from the start of the stream.
7676 fn seek < ' tcx > (
77- & mut self ,
77+ & self ,
7878 _communicate_allowed : bool ,
7979 _offset : SeekFrom ,
8080 ) -> InterpResult < ' tcx , io:: Result < u64 > > {
@@ -111,14 +111,9 @@ pub trait FileDescription: std::fmt::Debug + Any {
111111
112112impl dyn FileDescription {
113113 #[ inline( always) ]
114- pub fn downcast_ref < T : Any > ( & self ) -> Option < & T > {
114+ pub fn downcast < T : Any > ( & self ) -> Option < & T > {
115115 ( self as & dyn Any ) . downcast_ref ( )
116116 }
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- }
122117}
123118
124119impl FileDescription for io:: Stdin {
@@ -127,17 +122,17 @@ impl FileDescription for io::Stdin {
127122 }
128123
129124 fn read < ' tcx > (
130- & mut self ,
125+ & self ,
126+ _self_ref : & FileDescriptionRef ,
131127 communicate_allowed : bool ,
132- _fd_id : FdId ,
133128 bytes : & mut [ u8 ] ,
134129 _ecx : & mut MiriInterpCx < ' tcx > ,
135130 ) -> InterpResult < ' tcx , io:: Result < usize > > {
136131 if !communicate_allowed {
137132 // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
138133 helpers:: isolation_abort_error ( "`read` from stdin" ) ?;
139134 }
140- Ok ( Read :: read ( self , bytes) )
135+ Ok ( Read :: read ( & mut { self } , bytes) )
141136 }
142137
143138 fn is_tty ( & self , communicate_allowed : bool ) -> bool {
@@ -151,14 +146,14 @@ impl FileDescription for io::Stdout {
151146 }
152147
153148 fn write < ' tcx > (
154- & mut self ,
149+ & self ,
150+ _self_ref : & FileDescriptionRef ,
155151 _communicate_allowed : bool ,
156- _fd_id : FdId ,
157152 bytes : & [ u8 ] ,
158153 _ecx : & mut MiriInterpCx < ' tcx > ,
159154 ) -> InterpResult < ' tcx , io:: Result < usize > > {
160155 // We allow writing to stderr even with isolation enabled.
161- let result = Write :: write ( self , bytes) ;
156+ let result = Write :: write ( & mut { self } , bytes) ;
162157 // Stdout is buffered, flush to make sure it appears on the
163158 // screen. This is the write() syscall of the interpreted
164159 // program, we want it to correspond to a write() syscall on
@@ -180,9 +175,9 @@ impl FileDescription for io::Stderr {
180175 }
181176
182177 fn write < ' tcx > (
183- & mut self ,
178+ & self ,
179+ _self_ref : & FileDescriptionRef ,
184180 _communicate_allowed : bool ,
185- _fd_id : FdId ,
186181 bytes : & [ u8 ] ,
187182 _ecx : & mut MiriInterpCx < ' tcx > ,
188183 ) -> InterpResult < ' tcx , io:: Result < usize > > {
@@ -206,9 +201,9 @@ impl FileDescription for NullOutput {
206201 }
207202
208203 fn write < ' tcx > (
209- & mut self ,
204+ & self ,
205+ _self_ref : & FileDescriptionRef ,
210206 _communicate_allowed : bool ,
211- _fd_id : FdId ,
212207 bytes : & [ u8 ] ,
213208 _ecx : & mut MiriInterpCx < ' tcx > ,
214209 ) -> InterpResult < ' tcx , io:: Result < usize > > {
@@ -221,26 +216,23 @@ impl FileDescription for NullOutput {
221216#[ derive( Clone , Debug ) ]
222217pub struct FileDescWithId < T : FileDescription + ?Sized > {
223218 id : FdId ,
224- file_description : RefCell < Box < T > > ,
219+ file_description : Box < T > ,
225220}
226221
227222#[ derive( Clone , Debug ) ]
228223pub struct FileDescriptionRef ( Rc < FileDescWithId < dyn FileDescription > > ) ;
229224
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 ;
237227
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
240230 }
231+ }
241232
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) } ) )
244236 }
245237
246238 pub fn close < ' tcx > (
@@ -256,7 +248,7 @@ impl FileDescriptionRef {
256248 // Remove entry from the global epoll_event_interest table.
257249 ecx. machine . epoll_interests . remove ( id) ;
258250
259- RefCell :: into_inner ( fd. file_description ) . close ( communicate_allowed, ecx)
251+ fd. file_description . close ( communicate_allowed, ecx)
260252 }
261253 None => Ok ( Ok ( ( ) ) ) ,
262254 }
@@ -269,16 +261,6 @@ impl FileDescriptionRef {
269261 pub fn get_id ( & self ) -> FdId {
270262 self . 0 . id
271263 }
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- }
282264}
283265
284266/// Holds a weak reference to the actual file description.
@@ -334,11 +316,20 @@ impl FdTable {
334316 fds
335317 }
336318
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 {
339320 let file_handle = FileDescriptionRef :: new ( fd, self . next_file_description_id ) ;
340321 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 )
342333 }
343334
344335 /// Insert a file description, giving it a file descriptor that is at least `min_fd`.
@@ -368,17 +359,7 @@ impl FdTable {
368359 new_fd
369360 }
370361
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 > {
382363 let fd = self . fds . get ( & fd) ?;
383364 Some ( fd. clone ( ) )
384365 }
@@ -397,7 +378,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
397378 fn dup ( & mut self , old_fd : i32 ) -> InterpResult < ' tcx , Scalar > {
398379 let this = self . eval_context_mut ( ) ;
399380
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 {
401382 return Ok ( Scalar :: from_i32 ( this. fd_not_found ( ) ?) ) ;
402383 } ;
403384 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> {
406387 fn dup2 ( & mut self , old_fd : i32 , new_fd : i32 ) -> InterpResult < ' tcx , Scalar > {
407388 let this = self . eval_context_mut ( ) ;
408389
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 {
410391 return Ok ( Scalar :: from_i32 ( this. fd_not_found ( ) ?) ) ;
411392 } ;
412393 if new_fd != old_fd {
@@ -492,7 +473,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
492473 }
493474 let start = this. read_scalar ( & args[ 2 ] ) ?. to_i32 ( ) ?;
494475
495- match this. machine . fds . get_ref ( fd) {
476+ match this. machine . fds . get ( fd) {
496477 Some ( dup_fd) =>
497478 Ok ( Scalar :: from_i32 ( this. machine . fds . insert_ref_with_min_fd ( dup_fd, start) ) ) ,
498479 None => Ok ( Scalar :: from_i32 ( this. fd_not_found ( ) ?) ) ,
@@ -565,7 +546,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
565546 let communicate = this. machine . communicate ( ) ;
566547
567548 // 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 {
569550 trace ! ( "read: FD not found" ) ;
570551 return Ok ( Scalar :: from_target_isize ( this. fd_not_found ( ) ?, this) ) ;
571552 } ;
@@ -576,14 +557,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
576557 // `usize::MAX` because it is bounded by the host's `isize`.
577558 let mut bytes = vec ! [ 0 ; usize :: try_from( count) . unwrap( ) ] ;
578559 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) ,
580561 Some ( offset) => {
581562 let Ok ( offset) = u64:: try_from ( offset) else {
582563 let einval = this. eval_libc ( "EINVAL" ) ;
583564 this. set_last_error ( einval) ?;
584565 return Ok ( Scalar :: from_target_isize ( -1 , this) ) ;
585566 } ;
586- fd. borrow_mut ( ) . pread ( communicate, & mut bytes, offset, this)
567+ fd. pread ( communicate, & mut bytes, offset, this)
587568 }
588569 } ;
589570
@@ -629,19 +610,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
629610
630611 let bytes = this. read_bytes_ptr_strip_provenance ( buf, Size :: from_bytes ( count) ) ?. to_owned ( ) ;
631612 // 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 {
633614 return Ok ( Scalar :: from_target_isize ( this. fd_not_found ( ) ?, this) ) ;
634615 } ;
635616
636617 let result = match offset {
637- None => fd. borrow_mut ( ) . write ( communicate , fd . get_id ( ) , & bytes, this) ,
618+ None => fd. write ( & fd , communicate , & bytes, this) ,
638619 Some ( offset) => {
639620 let Ok ( offset) = u64:: try_from ( offset) else {
640621 let einval = this. eval_libc ( "EINVAL" ) ;
641622 this. set_last_error ( einval) ?;
642623 return Ok ( Scalar :: from_target_isize ( -1 , this) ) ;
643624 } ;
644- fd. borrow_mut ( ) . pwrite ( communicate, & bytes, offset, this)
625+ fd. pwrite ( communicate, & bytes, offset, this)
645626 }
646627 } ;
647628
0 commit comments