@@ -33,6 +33,11 @@ impl FileHandler {
33
33
34
34
fn insert_fd_with_min_fd ( & mut self , file_handle : FileHandle , min_fd : i32 ) -> i32 {
35
35
let min_fd = std:: cmp:: max ( min_fd, 3 ) ;
36
+
37
+ // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in
38
+ // between used FDs, the find_map combinator will return it. If the first such unused FD
39
+ // is after all other used FDs, the find_map combinator will return None, and we will use
40
+ // the FD following the greatest FD thus far.
36
41
let candidate_new_fd = self
37
42
. handles
38
43
. range ( min_fd..)
@@ -50,8 +55,9 @@ impl FileHandler {
50
55
let new_fd = candidate_new_fd. unwrap_or_else ( || {
51
56
// find_map ran out of BTreeMap entries before finding a free fd, use one plus the
52
57
// maximum fd in the map
53
- self . handles . keys ( ) . rev ( ) . next ( ) . map ( |last_fd| last_fd + 1 ) . unwrap_or ( min_fd)
58
+ self . handles . last_entry ( ) . map ( |entry| entry . key ( ) + 1 ) . unwrap_or ( min_fd)
54
59
} ) ;
60
+
55
61
self . handles . insert ( new_fd, file_handle) . unwrap_none ( ) ;
56
62
new_fd
57
63
}
@@ -153,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
153
159
& mut self ,
154
160
fd_op : OpTy < ' tcx , Tag > ,
155
161
cmd_op : OpTy < ' tcx , Tag > ,
156
- arg_op : Option < OpTy < ' tcx , Tag > > ,
162
+ start_op : Option < OpTy < ' tcx , Tag > > ,
157
163
) -> InterpResult < ' tcx , i32 > {
158
164
let this = self . eval_context_mut ( ) ;
159
165
@@ -179,20 +185,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
179
185
// because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only
180
186
// differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor,
181
187
// thus they can share the same implementation here.
182
- let arg_op = arg_op . ok_or_else ( || {
188
+ let start_op = start_op . ok_or_else ( || {
183
189
err_unsup_format ! (
184
190
"fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"
185
191
)
186
192
} ) ?;
187
- let arg = this. read_scalar ( arg_op ) ?. to_i32 ( ) ?;
193
+ let start = this. read_scalar ( start_op ) ?. to_i32 ( ) ?;
188
194
let fh = & mut this. machine . file_handler ;
189
195
let ( file_result, writable) = match fh. handles . get ( & fd) {
190
196
Some ( FileHandle :: File { file, writable } ) => ( file. try_clone ( ) , * writable) ,
191
197
Some ( _) => throw_unsup_format ! ( "Duplicating file descriptors for stdin, stdout, or stderr is not supported" ) ,
192
198
None => return this. handle_not_found ( ) ,
193
199
} ;
194
200
let fd_result = file_result. map ( |duplicated| {
195
- fh. insert_fd_with_min_fd ( FileHandle :: File { file : duplicated, writable } , arg )
201
+ fh. insert_fd_with_min_fd ( FileHandle :: File { file : duplicated, writable } , start )
196
202
} ) ;
197
203
this. try_unwrap_io_result ( fd_result)
198
204
} else {
0 commit comments