@@ -9,7 +9,6 @@ use crate::*;
99
1010pub struct FileHandle {
1111 file : File ,
12- flag : i32 ,
1312}
1413
1514pub struct FileHandler {
@@ -44,27 +43,57 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
4443
4544 let mut options = OpenOptions :: new ( ) ;
4645
47- // The first two bits of the flag correspond to the access mode of the file in linux.
46+ let o_rdonly = this. eval_libc_i32 ( "O_RDONLY" ) ?;
47+ let o_wronly = this. eval_libc_i32 ( "O_WRONLY" ) ?;
48+ let o_rdwr = this. eval_libc_i32 ( "O_RDWR" ) ?;
49+ // The first two bits of the flag correspond to the access mode in linux, macOS and
50+ // windows. We need to check that in fact the access mode flags for the current platform
51+ // only use these two bits, otherwise we are in an unsupported platform and should error.
52+ if ( o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 {
53+ throw_unsup_format ! ( "Access mode flags on this platform are unsupported" ) ;
54+ }
55+ // Now we check the access mode
4856 let access_mode = flag & 0b11 ;
4957
50- if access_mode == this . eval_libc_i32 ( "O_RDONLY" ) ? {
58+ if access_mode == o_rdonly {
5159 options. read ( true ) ;
52- } else if access_mode == this . eval_libc_i32 ( "O_WRONLY" ) ? {
60+ } else if access_mode == o_wronly {
5361 options. write ( true ) ;
54- } else if access_mode == this . eval_libc_i32 ( "O_RDWR" ) ? {
62+ } else if access_mode == o_rdwr {
5563 options. read ( true ) . write ( true ) ;
5664 } else {
5765 throw_unsup_format ! ( "Unsupported access mode {:#x}" , access_mode) ;
5866 }
67+ // We need to check that there aren't unsupported options in `flag`. For this we try to
68+ // reproduce the content of `flag` in the `mirror` variable using only the supported
69+ // options.
70+ let mut mirror = access_mode;
5971
60- if flag & this. eval_libc_i32 ( "O_APPEND" ) ? != 0 {
72+ let o_append = this. eval_libc_i32 ( "O_APPEND" ) ?;
73+ if flag & o_append != 0 {
6174 options. append ( true ) ;
75+ mirror |= o_append;
6276 }
63- if flag & this. eval_libc_i32 ( "O_TRUNC" ) ? != 0 {
77+ let o_trunc = this. eval_libc_i32 ( "O_TRUNC" ) ?;
78+ if flag & o_trunc != 0 {
6479 options. truncate ( true ) ;
80+ mirror |= o_trunc;
6581 }
66- if flag & this. eval_libc_i32 ( "O_CREAT" ) ? != 0 {
82+ let o_creat = this. eval_libc_i32 ( "O_CREAT" ) ?;
83+ if flag & o_creat != 0 {
6784 options. create ( true ) ;
85+ mirror |= o_creat;
86+ }
87+ let o_cloexec = this. eval_libc_i32 ( "O_CLOEXEC" ) ?;
88+ if flag & o_cloexec != 0 {
89+ // We do not need to do anything for this flag because `std` already sets it.
90+ // (Technically we do not support *not* setting this flag, but we ignore that.)
91+ mirror |= o_cloexec;
92+ }
93+ // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`,
94+ // then we throw an error.
95+ if flag != mirror {
96+ throw_unsup_format ! ( "unsupported flags {:#x}" , flag & !mirror) ;
6897 }
6998
7099 let path_bytes = this
@@ -76,7 +105,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
76105 let fd = options. open ( path) . map ( |file| {
77106 let mut fh = & mut this. machine . file_handler ;
78107 fh. low += 1 ;
79- fh. handles . insert ( fh. low , FileHandle { file, flag } ) ;
108+ fh. handles . insert ( fh. low , FileHandle { file } ) ;
80109 fh. low
81110 } ) ;
82111
@@ -87,7 +116,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
87116 & mut self ,
88117 fd_op : OpTy < ' tcx , Tag > ,
89118 cmd_op : OpTy < ' tcx , Tag > ,
90- arg_op : Option < OpTy < ' tcx , Tag > > ,
119+ _arg1_op : Option < OpTy < ' tcx , Tag > > ,
91120 ) -> InterpResult < ' tcx , i32 > {
92121 let this = self . eval_context_mut ( ) ;
93122
@@ -97,29 +126,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
97126
98127 let fd = this. read_scalar ( fd_op) ?. to_i32 ( ) ?;
99128 let cmd = this. read_scalar ( cmd_op) ?. to_i32 ( ) ?;
100-
101- if cmd == this. eval_libc_i32 ( "F_SETFD " ) ? {
102- // This does not affect the file itself. Certain flags might require changing the file
103- // or the way it is accessed somehow.
104- let flag = this. read_scalar ( arg_op . unwrap ( ) ) ? . to_i32 ( ) ? ;
105- // The only usage of this in stdlib at the moment is to enable the `FD_CLOEXEC` flag .
129+ // We only support getting the flags for a descriptor
130+ if cmd == this. eval_libc_i32 ( "F_GETFD " ) ? {
131+ // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the
132+ // `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
133+ // always sets this flag when opening a file. However we still need to check that the
134+ // file itself is open .
106135 let fd_cloexec = this. eval_libc_i32 ( "FD_CLOEXEC" ) ?;
107- if let Some ( FileHandle { flag : old_flag, .. } ) =
108- this. machine . file_handler . handles . get_mut ( & fd)
109- {
110- // Check that the only difference between the old flag and the current flag is
111- // exactly the `FD_CLOEXEC` value.
112- if flag ^ * old_flag == fd_cloexec {
113- * old_flag = flag;
114- } else {
115- throw_unsup_format ! ( "Unsupported arg {:#x} for `F_SETFD`" , flag) ;
116- }
117- }
118- Ok ( 0 )
119- } else if cmd == this. eval_libc_i32 ( "F_GETFD" ) ? {
120- this. get_handle_and ( fd, |handle| Ok ( handle. flag ) )
136+ this. get_handle_and ( fd, |_| Ok ( fd_cloexec) )
121137 } else {
122- throw_unsup_format ! ( "Unsupported command {:#x}" , cmd) ;
138+ throw_unsup_format ! ( "The {:#x} command is not supported for `fcntl`) " , cmd) ;
123139 }
124140 }
125141
0 commit comments