@@ -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