diff --git a/src/eval.rs b/src/eval.rs index 7a3945220f77..9ce3d2b08c23 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -169,7 +169,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { // FIXME: We always ignore leaks on some platforms where we do not // correctly implement TLS destructors. - let target_os = tcx.sess.target.target.target_os.to_lowercase(); + let target_os = tcx.sess.target.target.target_os.as_str(); let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos"; let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { diff --git a/src/helpers.rs b/src/helpers.rs index 2ae6910fce2d..5128176acb58 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -359,11 +359,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function used inside the shims of foreign functions to check that isolation is /// disabled. It returns an error using the `name` of the foreign function if this is not the /// case. - fn check_no_isolation(&mut self, name: &str) -> InterpResult<'tcx> { - if !self.eval_context_mut().machine.communicate { + fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> { + if !self.eval_context_ref().machine.communicate { throw_unsup_format!( "`{}` not available when isolation is enabled. Pass the flag `-Zmiri-disable-isolation` to disable it.", - name + name, ) } Ok(()) @@ -371,13 +371,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function used inside the shims of foreign functions to assert that the target /// platform is `platform`. It panics showing a message with the `name` of the foreign function /// if this is not the case. - fn assert_platform(&mut self, platform: &str, name: &str) { + fn assert_platform(&self, platform: &str, name: &str) { assert_eq!( - self.eval_context_mut().tcx.sess.target.target.target_os.to_lowercase(), + self.eval_context_ref().tcx.sess.target.target.target_os, platform, "`{}` is only available on the `{}` platform", name, - platform + platform, ) } @@ -389,8 +389,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Gets the last error variable. - fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); + fn get_last_error(&self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_ref(); let errno_place = this.machine.last_error.unwrap(); this.read_scalar(errno_place.into())?.not_undef() } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 37296132c038..3d8d3bd52607 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -455,7 +455,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } - _ => match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { + _ => match this.tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), target => throw_unsup_format!("The {} target platform is not supported", target), diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index a391baa0b22c..a8b4aad8819b 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -322,7 +322,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => { - match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { + match this.tcx.sess.target.target.target_os.as_str() { "linux" => return linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "macos" => return macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), _ => unreachable!(), diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 9da54b6d4070..4d3e1798ce14 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } - // File related shims + // File related shims (but also see "syscall" below for statx) // The only reason this is not in the `posix` module is because the `macos` item has a // different name. @@ -59,8 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // so skip over it. getrandom(this, &args[1..], dest)?; } - // `statx` is used by `libstd` to retrieve metadata information in `linux` - // instead of using `stat`,`lstat` or `fstat` as in the `macos` platform. + // `statx` is used by `libstd` to retrieve metadata information on `linux` + // instead of using `stat`,`lstat` or `fstat` as on `macos`. id if id == sys_statx => { // The first argument is the syscall id, // so skip over it. @@ -87,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Shims the linux 'getrandom()' syscall. +// Shims the linux `getrandom` syscall. fn getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a51a2f525085..aa562926686d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -63,6 +63,105 @@ impl FileHandler { } } +impl<'mir, 'tcx> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Emulate `stat` or `lstat` on the `macos` platform. This function is not intended to be + /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is + /// disabled or if the target platform is the correct one. Please use `macos_stat` or + /// `macos_lstat` instead. + fn macos_stat_or_lstat( + &mut self, + follow_symlink: bool, + path_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let path_scalar = this.read_scalar(path_op)?.not_undef()?; + let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); + + let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { + Some(metadata) => metadata, + None => return Ok(-1), + }; + this.macos_stat_write_buf(metadata, buf_op) + } + + fn macos_stat_write_buf( + &mut self, + metadata: FileMetadata, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let mode: u16 = metadata.mode.to_u16()?; + + let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); + let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); + let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); + + let dev_t_layout = this.libc_ty_layout("dev_t")?; + let mode_t_layout = this.libc_ty_layout("mode_t")?; + let nlink_t_layout = this.libc_ty_layout("nlink_t")?; + let ino_t_layout = this.libc_ty_layout("ino_t")?; + let uid_t_layout = this.libc_ty_layout("uid_t")?; + let gid_t_layout = this.libc_ty_layout("gid_t")?; + let time_t_layout = this.libc_ty_layout("time_t")?; + let long_layout = this.libc_ty_layout("c_long")?; + let off_t_layout = this.libc_ty_layout("off_t")?; + let blkcnt_t_layout = this.libc_ty_layout("blkcnt_t")?; + let blksize_t_layout = this.libc_ty_layout("blksize_t")?; + let uint32_t_layout = this.libc_ty_layout("uint32_t")?; + + // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. + let pad_layout = if this.tcx.sess.target.ptr_width == 64 { + uint32_t_layout + } else { + this.layout_of(this.tcx.mk_unit())? + }; + + let imms = [ + immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev + immty_from_uint_checked(mode, mode_t_layout)?, // st_mode + immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink + immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino + immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid + immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid + immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev + immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets + immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime + immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec + immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime + immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec + immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime + immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec + immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime + immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec + immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size + immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks + immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen + ]; + + let buf = this.deref_operand(buf_op)?; + this.write_packed_immediates(buf, &imms)?; + + Ok(0) + } + + /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets + /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses + /// `T: From` instead of `i32` directly because some fs functions return different integer + /// types (like `read`, that returns an `i64`). + fn handle_not_found>(&mut self) -> InterpResult<'tcx, T> { + let this = self.eval_context_mut(); + let ebadf = this.eval_libc("EBADF")?; + this.set_last_error(ebadf)?; + Ok((-1).into()) + } +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( @@ -432,29 +531,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(metadata) => metadata, None => return Ok(-1), }; - macos_stat_write_buf(this, metadata, buf_op) - } - - /// Emulate `stat` or `lstat` on the `macos` platform. This function is not intended to be - /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is - /// disabled or if the target platform is the correct one. Please use `macos_stat` or - /// `macos_lstat` instead. - fn macos_stat_or_lstat( - &mut self, - follow_symlink: bool, - path_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - - let path_scalar = this.read_scalar(path_op)?.not_undef()?; - let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); - - let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { - Some(metadata) => metadata, - None => return Ok(-1), - }; - macos_stat_write_buf(this, metadata, buf_op) + this.macos_stat_write_buf(metadata, buf_op) } fn linux_statx( @@ -620,17 +697,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets - /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses - /// `T: From` instead of `i32` directly because some fs functions return different integer - /// types (like `read`, that returns an `i64`). - fn handle_not_found>(&mut self) -> InterpResult<'tcx, T> { - let this = self.eval_context_mut(); - let ebadf = this.eval_libc("EBADF")?; - this.set_last_error(ebadf)?; - Ok((-1).into()) - } - fn rename( &mut self, oldpath_op: OpTy<'tcx, Tag>, @@ -743,64 +809,3 @@ impl FileMetadata { Ok(Some(FileMetadata { mode, size, created, accessed, modified })) } } - -fn macos_stat_write_buf<'tcx, 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - metadata: FileMetadata, - buf_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, i32> { - let mode: u16 = metadata.mode.to_u16()?; - - let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); - let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); - let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); - - let dev_t_layout = ecx.libc_ty_layout("dev_t")?; - let mode_t_layout = ecx.libc_ty_layout("mode_t")?; - let nlink_t_layout = ecx.libc_ty_layout("nlink_t")?; - let ino_t_layout = ecx.libc_ty_layout("ino_t")?; - let uid_t_layout = ecx.libc_ty_layout("uid_t")?; - let gid_t_layout = ecx.libc_ty_layout("gid_t")?; - let time_t_layout = ecx.libc_ty_layout("time_t")?; - let long_layout = ecx.libc_ty_layout("c_long")?; - let off_t_layout = ecx.libc_ty_layout("off_t")?; - let blkcnt_t_layout = ecx.libc_ty_layout("blkcnt_t")?; - let blksize_t_layout = ecx.libc_ty_layout("blksize_t")?; - let uint32_t_layout = ecx.libc_ty_layout("uint32_t")?; - - // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. - let pad_layout = if ecx.tcx.sess.target.ptr_width == 64 { - uint32_t_layout - } else { - ecx.layout_of(ecx.tcx.mk_unit())? - }; - - let imms = [ - immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev - immty_from_uint_checked(mode, mode_t_layout)?, // st_mode - immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink - immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino - immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid - immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid - immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets - immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime - immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec - immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime - immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec - immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime - immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec - immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime - immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size - immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks - immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen - ]; - - let buf = ecx.deref_operand(buf_op)?; - ecx.write_packed_immediates(buf, &imms)?; - - Ok(0) -}