@@ -273,6 +273,32 @@ impl FdTable {
273273
274274impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
275275pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
276+ fn dup ( & mut self , old_fd : i32 ) -> InterpResult < ' tcx , i32 > {
277+ let this = self . eval_context_mut ( ) ;
278+
279+ let Some ( dup_fd) = this. machine . fds . dup ( old_fd) else {
280+ return this. fd_not_found ( ) ;
281+ } ;
282+ Ok ( this. machine . fds . insert_fd_with_min_fd ( dup_fd, 0 ) )
283+ }
284+
285+ fn dup2 ( & mut self , old_fd : i32 , new_fd : i32 ) -> InterpResult < ' tcx , i32 > {
286+ let this = self . eval_context_mut ( ) ;
287+
288+ let Some ( dup_fd) = this. machine . fds . dup ( old_fd) else {
289+ return this. fd_not_found ( ) ;
290+ } ;
291+ if new_fd != old_fd {
292+ // Close new_fd if it is previously opened.
293+ // If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive.
294+ if let Some ( file_descriptor) = this. machine . fds . fds . insert ( new_fd, dup_fd) {
295+ // Ignore close error (not interpreter's) according to dup2() doc.
296+ file_descriptor. close ( this. machine . communicate ( ) ) ?. ok ( ) ;
297+ }
298+ }
299+ Ok ( new_fd)
300+ }
301+
276302 fn fcntl ( & mut self , args : & [ OpTy < ' tcx > ] ) -> InterpResult < ' tcx , i32 > {
277303 let this = self . eval_context_mut ( ) ;
278304
@@ -334,14 +360,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
334360
335361 let fd = this. read_scalar ( fd_op) ?. to_i32 ( ) ?;
336362
337- Ok ( Scalar :: from_i32 ( if let Some ( file_descriptor) = this. machine . fds . remove ( fd) {
338- let result = file_descriptor. close ( this. machine . communicate ( ) ) ?;
339- // return `0` if close is successful
340- let result = result. map ( |( ) | 0i32 ) ;
341- this. try_unwrap_io_result ( result) ?
342- } else {
343- this. fd_not_found ( ) ?
344- } ) )
363+ let Some ( file_descriptor) = this. machine . fds . remove ( fd) else {
364+ return Ok ( Scalar :: from_i32 ( this. fd_not_found ( ) ?) ) ;
365+ } ;
366+ let result = file_descriptor. close ( this. machine . communicate ( ) ) ?;
367+ // return `0` if close is successful
368+ let result = result. map ( |( ) | 0i32 ) ;
369+ Ok ( Scalar :: from_i32 ( this. try_unwrap_io_result ( result) ?) )
345370 }
346371
347372 /// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets
0 commit comments