11use std:: any:: Any ;
22use std:: collections:: BTreeMap ;
33use std:: io:: { IsTerminal , Read , SeekFrom , Write } ;
4+ use std:: marker:: CoercePointee ;
45use std:: ops:: Deref ;
56use std:: rc:: { Rc , Weak } ;
67use std:: { fs, io} ;
@@ -10,16 +11,126 @@ use rustc_abi::Size;
1011use crate :: shims:: unix:: UnixFileDescription ;
1112use crate :: * ;
1213
14+ /// A unique id for file descriptions. While we could use the address, considering that
15+ /// is definitely unique, the address would expose interpreter internal state when used
16+ /// for sorting things. So instead we generate a unique id per file description is the name
17+ /// for all `dup`licates and is never reused.
18+ #[ derive( Debug , Copy , Clone , Default , Eq , PartialEq , Ord , PartialOrd ) ]
19+ pub struct FdId ( usize ) ;
20+
21+ #[ derive( Debug , Clone ) ]
22+ struct FdIdWith < T : ?Sized > {
23+ id : FdId ,
24+ inner : T ,
25+ }
26+
27+ /// A refcounted pointer to a file description, also tracking the
28+ /// globally unique ID of this file description.
29+ #[ repr( transparent) ]
30+ #[ derive( CoercePointee , Debug ) ]
31+ pub struct FileDescriptionRef < T : ?Sized > ( Rc < FdIdWith < T > > ) ;
32+
33+ impl < T : ?Sized > Clone for FileDescriptionRef < T > {
34+ fn clone ( & self ) -> Self {
35+ FileDescriptionRef ( self . 0 . clone ( ) )
36+ }
37+ }
38+
39+ impl < T : ?Sized > Deref for FileDescriptionRef < T > {
40+ type Target = T ;
41+ fn deref ( & self ) -> & T {
42+ & self . 0 . inner
43+ }
44+ }
45+
46+ impl < T : ?Sized > FileDescriptionRef < T > {
47+ pub fn id ( & self ) -> FdId {
48+ self . 0 . id
49+ }
50+ }
51+
52+ /// Holds a weak reference to the actual file description.
53+ #[ derive( Clone , Debug ) ]
54+ pub struct WeakFileDescriptionRef < T : ?Sized > ( Weak < FdIdWith < T > > ) ;
55+
56+ impl < T : ?Sized > FileDescriptionRef < T > {
57+ pub fn downgrade ( this : & Self ) -> WeakFileDescriptionRef < T > {
58+ WeakFileDescriptionRef ( Rc :: downgrade ( & this. 0 ) )
59+ }
60+ }
61+
62+ impl < T : ?Sized > WeakFileDescriptionRef < T > {
63+ pub fn upgrade ( & self ) -> Option < FileDescriptionRef < T > > {
64+ self . 0 . upgrade ( ) . map ( FileDescriptionRef )
65+ }
66+ }
67+
68+ impl < T > VisitProvenance for WeakFileDescriptionRef < T > {
69+ fn visit_provenance ( & self , _visit : & mut VisitWith < ' _ > ) {
70+ // A weak reference can never be the only reference to some pointer or place.
71+ // Since the actual file description is tracked by strong ref somewhere,
72+ // it is ok to make this a NOP operation.
73+ }
74+ }
75+
76+ /// A helper trait to indirectly allow downcasting on `Rc<FdIdWith<dyn _>>`.
77+ /// Ideally we'd just add a `FdIdWith<Self>: Any` bound to the `FileDescription` trait,
78+ /// but that does not allow upcasting.
79+ pub trait FileDescriptionExt : ' static {
80+ fn into_rc_any ( self : FileDescriptionRef < Self > ) -> Rc < dyn Any > ;
81+
82+ /// We wrap the regular `close` function generically, so both handle `Rc::into_inner`
83+ /// and epoll interest management.
84+ fn close_ref < ' tcx > (
85+ self : FileDescriptionRef < Self > ,
86+ communicate_allowed : bool ,
87+ ecx : & mut MiriInterpCx < ' tcx > ,
88+ ) -> InterpResult < ' tcx , io:: Result < ( ) > > ;
89+ }
90+
91+ impl < T : FileDescription + ' static > FileDescriptionExt for T {
92+ fn into_rc_any ( self : FileDescriptionRef < Self > ) -> Rc < dyn Any > {
93+ self . 0
94+ }
95+
96+ fn close_ref < ' tcx > (
97+ self : FileDescriptionRef < Self > ,
98+ communicate_allowed : bool ,
99+ ecx : & mut MiriInterpCx < ' tcx > ,
100+ ) -> InterpResult < ' tcx , io:: Result < ( ) > > {
101+ match Rc :: into_inner ( self . 0 ) {
102+ Some ( fd) => {
103+ // Remove entry from the global epoll_event_interest table.
104+ ecx. machine . epoll_interests . remove ( fd. id ) ;
105+
106+ fd. inner . close ( communicate_allowed, ecx)
107+ }
108+ None => {
109+ // Not the last reference.
110+ interp_ok ( Ok ( ( ) ) )
111+ }
112+ }
113+ }
114+ }
115+
116+ pub type DynFileDescriptionRef = FileDescriptionRef < dyn FileDescription > ;
117+
118+ impl FileDescriptionRef < dyn FileDescription > {
119+ pub fn downcast < T : FileDescription + ' static > ( self ) -> Option < FileDescriptionRef < T > > {
120+ let inner = self . into_rc_any ( ) . downcast :: < FdIdWith < T > > ( ) . ok ( ) ?;
121+ Some ( FileDescriptionRef ( inner) )
122+ }
123+ }
124+
13125/// Represents an open file description.
14- pub trait FileDescription : std:: fmt:: Debug + Any {
126+ pub trait FileDescription : std:: fmt:: Debug + FileDescriptionExt {
15127 fn name ( & self ) -> & ' static str ;
16128
17129 /// Reads as much as possible into the given buffer `ptr`.
18130 /// `len` indicates how many bytes we should try to read.
19131 /// `dest` is where the return value should be stored: number of bytes read, or `-1` in case of error.
20132 fn read < ' tcx > (
21- & self ,
22- _self_ref : & FileDescriptionRef ,
133+ self : FileDescriptionRef < Self > ,
23134 _communicate_allowed : bool ,
24135 _ptr : Pointer ,
25136 _len : usize ,
@@ -33,8 +144,7 @@ pub trait FileDescription: std::fmt::Debug + Any {
33144 /// `len` indicates how many bytes we should try to write.
34145 /// `dest` is where the return value should be stored: number of bytes written, or `-1` in case of error.
35146 fn write < ' tcx > (
36- & self ,
37- _self_ref : & FileDescriptionRef ,
147+ self : FileDescriptionRef < Self > ,
38148 _communicate_allowed : bool ,
39149 _ptr : Pointer ,
40150 _len : usize ,
@@ -54,11 +164,15 @@ pub trait FileDescription: std::fmt::Debug + Any {
54164 throw_unsup_format ! ( "cannot seek on {}" , self . name( ) ) ;
55165 }
56166
167+ /// Close the file descriptor.
57168 fn close < ' tcx > (
58- self : Box < Self > ,
169+ self ,
59170 _communicate_allowed : bool ,
60171 _ecx : & mut MiriInterpCx < ' tcx > ,
61- ) -> InterpResult < ' tcx , io:: Result < ( ) > > {
172+ ) -> InterpResult < ' tcx , io:: Result < ( ) > >
173+ where
174+ Self : Sized ,
175+ {
62176 throw_unsup_format ! ( "cannot close {}" , self . name( ) ) ;
63177 }
64178
@@ -77,21 +191,13 @@ pub trait FileDescription: std::fmt::Debug + Any {
77191 }
78192}
79193
80- impl dyn FileDescription {
81- #[ inline( always) ]
82- pub fn downcast < T : Any > ( & self ) -> Option < & T > {
83- ( self as & dyn Any ) . downcast_ref ( )
84- }
85- }
86-
87194impl FileDescription for io:: Stdin {
88195 fn name ( & self ) -> & ' static str {
89196 "stdin"
90197 }
91198
92199 fn read < ' tcx > (
93- & self ,
94- _self_ref : & FileDescriptionRef ,
200+ self : FileDescriptionRef < Self > ,
95201 communicate_allowed : bool ,
96202 ptr : Pointer ,
97203 len : usize ,
@@ -103,7 +209,7 @@ impl FileDescription for io::Stdin {
103209 // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
104210 helpers:: isolation_abort_error ( "`read` from stdin" ) ?;
105211 }
106- let result = Read :: read ( & mut { self } , & mut bytes) ;
212+ let result = Read :: read ( & mut & * self , & mut bytes) ;
107213 match result {
108214 Ok ( read_size) => ecx. return_read_success ( ptr, & bytes, read_size, dest) ,
109215 Err ( e) => ecx. set_last_error_and_return ( e, dest) ,
@@ -121,8 +227,7 @@ impl FileDescription for io::Stdout {
121227 }
122228
123229 fn write < ' tcx > (
124- & self ,
125- _self_ref : & FileDescriptionRef ,
230+ self : FileDescriptionRef < Self > ,
126231 _communicate_allowed : bool ,
127232 ptr : Pointer ,
128233 len : usize ,
@@ -131,7 +236,7 @@ impl FileDescription for io::Stdout {
131236 ) -> InterpResult < ' tcx > {
132237 let bytes = ecx. read_bytes_ptr_strip_provenance ( ptr, Size :: from_bytes ( len) ) ?;
133238 // We allow writing to stderr even with isolation enabled.
134- let result = Write :: write ( & mut { self } , bytes) ;
239+ let result = Write :: write ( & mut & * self , bytes) ;
135240 // Stdout is buffered, flush to make sure it appears on the
136241 // screen. This is the write() syscall of the interpreted
137242 // program, we want it to correspond to a write() syscall on
@@ -155,8 +260,7 @@ impl FileDescription for io::Stderr {
155260 }
156261
157262 fn write < ' tcx > (
158- & self ,
159- _self_ref : & FileDescriptionRef ,
263+ self : FileDescriptionRef < Self > ,
160264 _communicate_allowed : bool ,
161265 ptr : Pointer ,
162266 len : usize ,
@@ -166,7 +270,7 @@ impl FileDescription for io::Stderr {
166270 let bytes = ecx. read_bytes_ptr_strip_provenance ( ptr, Size :: from_bytes ( len) ) ?;
167271 // We allow writing to stderr even with isolation enabled.
168272 // No need to flush, stderr is not buffered.
169- let result = Write :: write ( & mut { self } , bytes) ;
273+ let result = Write :: write ( & mut & * self , bytes) ;
170274 match result {
171275 Ok ( write_size) => ecx. return_write_success ( write_size, dest) ,
172276 Err ( e) => ecx. set_last_error_and_return ( e, dest) ,
@@ -188,8 +292,7 @@ impl FileDescription for NullOutput {
188292 }
189293
190294 fn write < ' tcx > (
191- & self ,
192- _self_ref : & FileDescriptionRef ,
295+ self : FileDescriptionRef < Self > ,
193296 _communicate_allowed : bool ,
194297 _ptr : Pointer ,
195298 len : usize ,
@@ -201,91 +304,10 @@ impl FileDescription for NullOutput {
201304 }
202305}
203306
204- /// Structure contains both the file description and its unique identifier.
205- #[ derive( Clone , Debug ) ]
206- pub struct FileDescWithId < T : FileDescription + ?Sized > {
207- id : FdId ,
208- file_description : Box < T > ,
209- }
210-
211- #[ derive( Clone , Debug ) ]
212- pub struct FileDescriptionRef ( Rc < FileDescWithId < dyn FileDescription > > ) ;
213-
214- impl Deref for FileDescriptionRef {
215- type Target = dyn FileDescription ;
216-
217- fn deref ( & self ) -> & Self :: Target {
218- & * self . 0 . file_description
219- }
220- }
221-
222- impl FileDescriptionRef {
223- fn new ( fd : impl FileDescription , id : FdId ) -> Self {
224- FileDescriptionRef ( Rc :: new ( FileDescWithId { id, file_description : Box :: new ( fd) } ) )
225- }
226-
227- pub fn close < ' tcx > (
228- self ,
229- communicate_allowed : bool ,
230- ecx : & mut MiriInterpCx < ' tcx > ,
231- ) -> InterpResult < ' tcx , io:: Result < ( ) > > {
232- // Destroy this `Rc` using `into_inner` so we can call `close` instead of
233- // implicitly running the destructor of the file description.
234- let id = self . get_id ( ) ;
235- match Rc :: into_inner ( self . 0 ) {
236- Some ( fd) => {
237- // Remove entry from the global epoll_event_interest table.
238- ecx. machine . epoll_interests . remove ( id) ;
239-
240- fd. file_description . close ( communicate_allowed, ecx)
241- }
242- None => interp_ok ( Ok ( ( ) ) ) ,
243- }
244- }
245-
246- pub fn downgrade ( & self ) -> WeakFileDescriptionRef {
247- WeakFileDescriptionRef { weak_ref : Rc :: downgrade ( & self . 0 ) }
248- }
249-
250- pub fn get_id ( & self ) -> FdId {
251- self . 0 . id
252- }
253- }
254-
255- /// Holds a weak reference to the actual file description.
256- #[ derive( Clone , Debug , Default ) ]
257- pub struct WeakFileDescriptionRef {
258- weak_ref : Weak < FileDescWithId < dyn FileDescription > > ,
259- }
260-
261- impl WeakFileDescriptionRef {
262- pub fn upgrade ( & self ) -> Option < FileDescriptionRef > {
263- if let Some ( file_desc_with_id) = self . weak_ref . upgrade ( ) {
264- return Some ( FileDescriptionRef ( file_desc_with_id) ) ;
265- }
266- None
267- }
268- }
269-
270- impl VisitProvenance for WeakFileDescriptionRef {
271- fn visit_provenance ( & self , _visit : & mut VisitWith < ' _ > ) {
272- // A weak reference can never be the only reference to some pointer or place.
273- // Since the actual file description is tracked by strong ref somewhere,
274- // it is ok to make this a NOP operation.
275- }
276- }
277-
278- /// A unique id for file descriptions. While we could use the address, considering that
279- /// is definitely unique, the address would expose interpreter internal state when used
280- /// for sorting things. So instead we generate a unique id per file description is the name
281- /// for all `dup`licates and is never reused.
282- #[ derive( Debug , Copy , Clone , Default , Eq , PartialEq , Ord , PartialOrd ) ]
283- pub struct FdId ( usize ) ;
284-
285307/// The file descriptor table
286308#[ derive( Debug ) ]
287309pub struct FdTable {
288- pub fds : BTreeMap < i32 , FileDescriptionRef > ,
310+ pub fds : BTreeMap < i32 , DynFileDescriptionRef > ,
289311 /// Unique identifier for file description, used to differentiate between various file description.
290312 next_file_description_id : FdId ,
291313}
@@ -313,8 +335,9 @@ impl FdTable {
313335 fds
314336 }
315337
316- pub fn new_ref ( & mut self , fd : impl FileDescription ) -> FileDescriptionRef {
317- let file_handle = FileDescriptionRef :: new ( fd, self . next_file_description_id ) ;
338+ pub fn new_ref < T : FileDescription > ( & mut self , fd : T ) -> FileDescriptionRef < T > {
339+ let file_handle =
340+ FileDescriptionRef ( Rc :: new ( FdIdWith { id : self . next_file_description_id , inner : fd } ) ) ;
318341 self . next_file_description_id = FdId ( self . next_file_description_id . 0 . strict_add ( 1 ) ) ;
319342 file_handle
320343 }
@@ -325,12 +348,16 @@ impl FdTable {
325348 self . insert ( fd_ref)
326349 }
327350
328- pub fn insert ( & mut self , fd_ref : FileDescriptionRef ) -> i32 {
351+ pub fn insert ( & mut self , fd_ref : DynFileDescriptionRef ) -> i32 {
329352 self . insert_with_min_num ( fd_ref, 0 )
330353 }
331354
332355 /// Insert a file description, giving it a file descriptor that is at least `min_fd_num`.
333- pub fn insert_with_min_num ( & mut self , file_handle : FileDescriptionRef , min_fd_num : i32 ) -> i32 {
356+ pub fn insert_with_min_num (
357+ & mut self ,
358+ file_handle : DynFileDescriptionRef ,
359+ min_fd_num : i32 ,
360+ ) -> i32 {
334361 // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in
335362 // between used FDs, the find_map combinator will return it. If the first such unused FD
336363 // is after all other used FDs, the find_map combinator will return None, and we will use
@@ -356,12 +383,12 @@ impl FdTable {
356383 new_fd_num
357384 }
358385
359- pub fn get ( & self , fd_num : i32 ) -> Option < FileDescriptionRef > {
386+ pub fn get ( & self , fd_num : i32 ) -> Option < DynFileDescriptionRef > {
360387 let fd = self . fds . get ( & fd_num) ?;
361388 Some ( fd. clone ( ) )
362389 }
363390
364- pub fn remove ( & mut self , fd_num : i32 ) -> Option < FileDescriptionRef > {
391+ pub fn remove ( & mut self , fd_num : i32 ) -> Option < DynFileDescriptionRef > {
365392 self . fds . remove ( & fd_num)
366393 }
367394
0 commit comments