/// Miri-provided extern function to deallocate memory.
fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
+
+ /// Convert a path from the host Miri runs on to the target Miri interprets.
+ /// Performs conversion of path separators as needed.
+ ///
+ /// Usually Miri performs this kind of conversion automatically. However, manual conversion
+ /// might be necessary when reading an environment variable that was set of the host
+ /// (such as TMPDIR) and using it as a target path.
+ ///
+ /// Only works with isolation disabled.
+ ///
+ /// `in` must point to a null-terminated string, and will be read as the input host path.
+ /// `out` must point to at least `out_size` many bytes, and the result will be stored there
+ /// with a null terminator.
+ /// Returns 0 if the `out` buffer was large enough, and the required size otherwise.
+ fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
}
```
-use std::{collections::hash_map::Entry, io::Write, iter};
+use std::{collections::hash_map::Entry, io::Write, iter, path::Path};
use log::trace;
}
this.machine.static_roots.push(alloc_id);
}
+ "miri_host_to_target_path" => {
+ let [ptr, out, out_size] = this.check_shim(abi, Abi::Rust, link_name, args)?;
+ let ptr = this.read_pointer(ptr)?;
+ let out = this.read_pointer(out)?;
+ let out_size = this.read_scalar(out_size)?.to_machine_usize(this)?;
+
+ // The host affects program behavior here, so this requires isolation to be disabled.
+ this.check_no_isolation("`miri_host_to_target_path`")?;
+
+ // We read this as a plain OsStr and write it as a path, which will convert it to the target.
+ let path = this.read_os_str_from_c_str(ptr)?.to_owned();
+ let (success, needed_size) = this.write_path_to_c_str(Path::new(&path), out, out_size)?;
+ // Return value: 0 on success, otherwise the size it would have needed.
+ this.write_int(if success { 0 } else { needed_size }, dest)?;
+ }
// Obtains the size of a Miri backtrace. See the README for details.
"miri_backtrace_size" => {
#![feature(io_error_uncategorized)]
use std::convert::TryInto;
-use std::ffi::CString;
+use std::ffi::{CStr, CString};
use std::fs::{canonicalize, remove_dir_all, remove_file, File};
use std::io::{Error, ErrorKind, Write};
use std::os::unix::ffi::OsStrExt;
}
fn tmp() -> PathBuf {
- std::env::var("MIRI_TEMP")
- .map(|tmp| {
- // MIRI_TEMP is set outside of our emulated
- // program, so it may have path separators that don't
- // correspond to our target platform. We normalize them here
- // before constructing a `PathBuf`
-
- #[cfg(windows)]
- return PathBuf::from(tmp.replace("/", "\\"));
-
- #[cfg(not(windows))]
- return PathBuf::from(tmp.replace("\\", "/"));
- })
- .unwrap_or_else(|_| std::env::temp_dir())
+ let path = std::env::var("MIRI_TEMP")
+ .unwrap_or_else(|_| std::env::temp_dir().into_os_string().into_string().unwrap());
+ // These are host paths. We need to convert them to the target.
+ let path = CString::new(path).unwrap();
+ let mut out = Vec::with_capacity(1024);
+
+ unsafe {
+ extern "Rust" {
+ fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
+ }
+ let ret = miri_host_to_target_path(path.as_ptr(), out.as_mut_ptr(), out.capacity());
+ assert_eq!(ret, 0);
+ let out = CStr::from_ptr(out.as_ptr()).to_str().unwrap();
+ PathBuf::from(out)
+ }
}
/// Prepare: compute filename and make sure the file does not exist.
use std::path::PathBuf;
fn tmp() -> PathBuf {
- std::env::var("MIRI_TEMP")
- .map(|tmp| {
- // MIRI_TEMP is set outside of our emulated
- // program, so it may have path separators that don't
- // correspond to our target platform. We normalize them here
- // before constructing a `PathBuf`
- return PathBuf::from(tmp.replace("\\", "/"));
- })
- .unwrap_or_else(|_| std::env::temp_dir())
+ use std::ffi::{CStr, CString};
+
+ let path = std::env::var("MIRI_TEMP")
+ .unwrap_or_else(|_| std::env::temp_dir().into_os_string().into_string().unwrap());
+ // These are host paths. We need to convert them to the target.
+ let path = CString::new(path).unwrap();
+ let mut out = Vec::with_capacity(1024);
+
+ unsafe {
+ extern "Rust" {
+ fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
+ }
+ let ret = miri_host_to_target_path(path.as_ptr(), out.as_mut_ptr(), out.capacity());
+ assert_eq!(ret, 0);
+ let out = CStr::from_ptr(out.as_ptr()).to_str().unwrap();
+ PathBuf::from(out)
+ }
}
/// Test allocating variant of `realpath`.
}
fn tmp() -> PathBuf {
- std::env::var("MIRI_TEMP")
- .map(|tmp| {
- // MIRI_TEMP is set outside of our emulated
- // program, so it may have path separators that don't
- // correspond to our target platform. We normalize them here
- // before constructing a `PathBuf`
-
- #[cfg(windows)]
- return PathBuf::from(tmp.replace("/", "\\"));
-
- #[cfg(not(windows))]
- return PathBuf::from(tmp.replace("\\", "/"));
- })
- .unwrap_or_else(|_| std::env::temp_dir())
+ use std::ffi::{CStr, CString};
+
+ let path = std::env::var("MIRI_TEMP")
+ .unwrap_or_else(|_| std::env::temp_dir().into_os_string().into_string().unwrap());
+ // These are host paths. We need to convert them to the target.
+ let path = CString::new(path).unwrap();
+ let mut out = Vec::with_capacity(1024);
+
+ unsafe {
+ extern "Rust" {
+ fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
+ }
+ let ret = miri_host_to_target_path(path.as_ptr(), out.as_mut_ptr(), out.capacity());
+ assert_eq!(ret, 0);
+ let out = CStr::from_ptr(out.as_ptr()).to_str().unwrap();
+ PathBuf::from(out)
+ }
}
/// Prepare: compute filename and make sure the file does not exist.