@@ -44,7 +44,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
4444
4545 let mut options = OpenOptions :: new ( ) ;
4646
47- // The first two bits of the flag correspond to the access mode of the file in linux.
47+ // The first two bits of the flag correspond to the access mode of the file in linux. This
48+ // is done this way because `O_RDONLY` is zero in several platforms.
4849 let access_mode = flag & 0b11 ;
4950
5051 if access_mode == this. eval_libc_i32 ( "O_RDONLY" ) ? {
@@ -56,15 +57,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
5657 } else {
5758 throw_unsup_format ! ( "Unsupported access mode {:#x}" , access_mode) ;
5859 }
60+ // We need to check that there aren't unsupported options in `flag`. For this we try to
61+ // reproduce the content of `flag` in the `mirror` variable using only the supported
62+ // options.
63+ let mut mirror = access_mode;
5964
60- if flag & this. eval_libc_i32 ( "O_APPEND" ) ? != 0 {
65+ let o_append = this. eval_libc_i32 ( "O_APPEND" ) ?;
66+ if flag & o_append != 0 {
6167 options. append ( true ) ;
68+ mirror |= o_append;
6269 }
63- if flag & this. eval_libc_i32 ( "O_TRUNC" ) ? != 0 {
70+ let o_trunc = this. eval_libc_i32 ( "O_TRUNC" ) ?;
71+ if flag & o_trunc != 0 {
6472 options. truncate ( true ) ;
73+ mirror |= o_trunc;
6574 }
66- if flag & this. eval_libc_i32 ( "O_CREAT" ) ? != 0 {
75+ let o_creat = this. eval_libc_i32 ( "O_CREAT" ) ?;
76+ if flag & o_creat != 0 {
6777 options. create ( true ) ;
78+ mirror |= o_creat;
79+ }
80+ let o_cloexec = this. eval_libc_i32 ( "O_CLOEXEC" ) ?;
81+ if flag & o_cloexec != 0 {
82+ // This flag is a noop for now because `std` already sets it.
83+ mirror |= o_cloexec;
84+ }
85+ // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`,
86+ // then we throw an error.
87+ if flag != mirror {
88+ throw_unsup_format ! ( "unsupported flags {:#x}" , flag) ;
6889 }
6990
7091 let path_bytes = this
0 commit comments