Skip to content

Commit

Permalink
Rollup merge of #106639 - RalfJung:miri, r=RalfJung
Browse files Browse the repository at this point in the history
update Miri

Notable PRs:
- rust-lang#2748
- rust-lang#2752

r? `@ghost`
  • Loading branch information
Yuki Okushi authored Jan 9, 2023
2 parents b0b9556 + 6a682a7 commit 768e138
Show file tree
Hide file tree
Showing 17 changed files with 246 additions and 35 deletions.
2 changes: 1 addition & 1 deletion cargo-miri/src/phases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
// explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the
// bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host
// builds.
cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap());
cmd.env("RUSTC", fs::canonicalize(find_miri()).unwrap());
cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases!

// Set rustdoc to us as well, so we can run doctests.
Expand Down
3 changes: 2 additions & 1 deletion ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ case $HOST_TARGET in
MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var
MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer
MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings
MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings
MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture
MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std # JSON target file
;;
Expand Down
2 changes: 1 addition & 1 deletion rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4f4d0586ad20c66a16d547581ca379beafece93a
c54c8cbac882e149e04a9e1f2d146fd548ae30ae
12 changes: 4 additions & 8 deletions src/borrow_tracker/stacked_borrows/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,7 @@ impl fmt::Display for InvalidationCause {
match self {
InvalidationCause::Access(kind) => write!(f, "{kind}"),
InvalidationCause::Retag(perm, kind) =>
if *kind == RetagCause::FnEntry {
write!(f, "{perm:?} FnEntry retag")
} else {
write!(f, "{perm:?} retag")
},
write!(f, "{perm:?} {retag}", retag = kind.summary()),
}
}
}
Expand Down Expand Up @@ -193,7 +189,7 @@ struct RetagOp {
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum RetagCause {
Normal,
FnReturn,
FnReturnPlace,
FnEntry,
TwoPhase,
}
Expand Down Expand Up @@ -495,8 +491,8 @@ impl RetagCause {
fn summary(&self) -> String {
match self {
RetagCause::Normal => "retag",
RetagCause::FnEntry => "FnEntry retag",
RetagCause::FnReturn => "FnReturn retag",
RetagCause::FnEntry => "function-entry retag",
RetagCause::FnReturnPlace => "return-place retag",
RetagCause::TwoPhase => "two-phase retag",
}
.to_string()
Expand Down
2 changes: 1 addition & 1 deletion src/borrow_tracker/stacked_borrows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -998,7 +998,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
access: Some(AccessKind::Write),
protector: Some(ProtectorKind::StrongProtector),
};
let val = this.sb_retag_reference(&val, new_perm, RetagCause::FnReturn)?;
let val = this.sb_retag_reference(&val, new_perm, RetagCause::FnReturnPlace)?;
// And use reborrowed pointer for return place.
let return_place = this.ref_to_mplace(&val)?;
this.frame_mut().return_place = return_place.into();
Expand Down
11 changes: 10 additions & 1 deletion src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
link_name: Symbol,
) -> InterpResult<'tcx, ()> {
self.check_abi(abi, exp_abi)?;
if let Some((body, _)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
// If compiler-builtins is providing the symbol, then don't treat it as a clash.
// We'll use our built-in implementation in `emulate_foreign_item_by_name` for increased
// performance. Note that this means we won't catch any undefined behavior in
// compiler-builtins when running other crates, but Miri can still be run on
// compiler-builtins itself (or any crate that uses it as a normal dependency)
if self.eval_context_ref().tcx.is_compiler_builtins(instance.def_id().krate) {
return Ok(());
}

throw_machine_stop!(TerminationInfo::SymbolShimClashing {
link_name,
span: body.span.data(),
Expand Down
1 change: 0 additions & 1 deletion src/range_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ mod tests {
/// Query the map at every offset in the range and collect the results.
fn to_vec<T: Copy>(map: &RangeMap<T>, offset: u64, len: u64) -> Vec<T> {
(offset..offset + len)
.into_iter()
.map(|i| {
map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap()
})
Expand Down
6 changes: 4 additions & 2 deletions src/shims/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// `buf_size` represents the size in characters.
let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?);
Scalar::from_u32(windows_check_buffer_size(
this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?,
this.write_os_str_to_wide_str(
&var, buf_ptr, buf_size, /*truncate*/ false,
)?,
))
}
None => {
Expand Down Expand Up @@ -366,7 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
match env::current_dir() {
Ok(cwd) =>
return Ok(Scalar::from_u32(windows_check_buffer_size(
this.write_path_to_wide_str(&cwd, buf, size)?,
this.write_path_to_wide_str(&cwd, buf, size, /*truncate*/ false)?,
))),
Err(e) => this.set_last_error_from_io_error(e.kind())?,
}
Expand Down
51 changes: 41 additions & 10 deletions src/shims/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
self.eval_context_mut().write_c_str(bytes, ptr, size)
}

/// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what
/// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying
/// to write if `size` is not large enough to fit the contents of `os_string` plus a null
/// terminator. It returns `Ok((true, length))` if the writing process was successful. The
/// string length returned does include the null terminator. Length is measured in units of
/// `u16.`
/// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the
/// Windows APIs usually handle.
///
/// If `truncate == false` (the usual mode of operation), this function returns `Ok((false,
/// length))` without trying to write if `size` is not large enough to fit the contents of
/// `os_string` plus a null terminator. It returns `Ok((true, length))` if the writing process
/// was successful. The string length returned does include the null terminator. Length is
/// measured in units of `u16.`
///
/// If `truncate == true`, then in case `size` is not large enough it *will* write the first
/// `size.saturating_sub(1)` many items, followed by a null terminator (if `size > 0`).
fn write_os_str_to_wide_str(
&mut self,
os_str: &OsStr,
ptr: Pointer<Option<Provenance>>,
size: u64,
truncate: bool,
) -> InterpResult<'tcx, (bool, u64)> {
#[cfg(windows)]
fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec<u16>> {
Expand All @@ -129,7 +135,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}

let u16_vec = os_str_to_u16vec(os_str)?;
self.eval_context_mut().write_wide_str(&u16_vec, ptr, size)
let (written, size_needed) = self.eval_context_mut().write_wide_str(&u16_vec, ptr, size)?;
if truncate && !written && size > 0 {
// Write the truncated part that fits.
let truncated_data = &u16_vec[..size.saturating_sub(1).try_into().unwrap()];
let (written, written_len) =
self.eval_context_mut().write_wide_str(truncated_data, ptr, size)?;
assert!(written && written_len == size);
}
Ok((written, size_needed))
}

/// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.
Expand All @@ -143,7 +157,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

let arg_type = this.tcx.mk_array(this.tcx.types.u8, size);
let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0);
let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap();
assert!(written);
Ok(arg_place.ptr)
}

Expand All @@ -158,7 +173,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

let arg_type = this.tcx.mk_array(this.tcx.types.u16, size);
let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0);
let (written, _) =
self.write_os_str_to_wide_str(os_str, arg_place.ptr, size, /*truncate*/ false).unwrap();
assert!(written);
Ok(arg_place.ptr)
}

Expand Down Expand Up @@ -212,11 +229,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
path: &Path,
ptr: Pointer<Option<Provenance>>,
size: u64,
truncate: bool,
) -> InterpResult<'tcx, (bool, u64)> {
let this = self.eval_context_mut();
let os_str =
this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
this.write_os_str_to_wide_str(&os_str, ptr, size)
this.write_os_str_to_wide_str(&os_str, ptr, size, truncate)
}

/// Allocate enough memory to store a Path as a null-terminated sequence of bytes,
Expand All @@ -232,6 +250,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.alloc_os_str_as_c_str(&os_str, memkind)
}

/// Allocate enough memory to store a Path as a null-terminated sequence of `u16`s,
/// adjusting path separators if needed.
fn alloc_path_as_wide_str(
&mut self,
path: &Path,
memkind: MemoryKind<MiriMemoryKind>,
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
let this = self.eval_context_mut();
let os_str =
this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
this.alloc_os_str_as_wide_str(&os_str, memkind)
}

#[allow(clippy::get_first)]
fn convert_path<'a>(
&self,
Expand Down
40 changes: 40 additions & 0 deletions src/shims/windows/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,46 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

this.write_scalar(Scalar::from_u32(1), dest)?;
}
"GetModuleFileNameW" => {
let [handle, filename, size] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.check_no_isolation("`GetModuleFileNameW`")?;

let handle = this.read_machine_usize(handle)?;
let filename = this.read_pointer(filename)?;
let size = this.read_scalar(size)?.to_u32()?;

if handle != 0 {
throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
}

// Using the host current_exe is a bit off, but consistent with Linux
// (where stdlib reads /proc/self/exe).
// Unfortunately this Windows function has a crazy behavior so we can't just use
// `write_path_to_wide_str`...
let path = std::env::current_exe().unwrap();
let (all_written, size_needed) = this.write_path_to_wide_str(
&path,
filename,
size.into(),
/*truncate*/ true,
)?;

if all_written {
// If the function succeeds, the return value is the length of the string that
// is copied to the buffer, in characters, not including the terminating null
// character.
this.write_int(size_needed.checked_sub(1).unwrap(), dest)?;
} else {
// If the buffer is too small to hold the module name, the string is truncated
// to nSize characters including the terminating null character, the function
// returns nSize, and the function sets the last error to
// ERROR_INSUFFICIENT_BUFFER.
this.write_int(size, dest)?;
let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
this.set_last_error(insufficient_buffer)?;
}
}

// Threading
"CreateThread" => {
Expand Down
81 changes: 79 additions & 2 deletions test_dependencies/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions test_dependencies/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ libc = "0.2"
num_cpus = "1.10.1"

getrandom_1 = { package = "getrandom", version = "0.1" }
getrandom = { version = "0.2" }
getrandom = { version = "0.2", features = ["js"] }
rand = { version = "0.8", features = ["small_rng"] }

[target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
page_size = "0.5"
tokio = { version = "1.0", features = ["full"] }
tokio = { version = "1.23", features = ["full"] }

[workspace]
Loading

0 comments on commit 768e138

Please sign in to comment.