Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 710048f

Browse files
committedFeb 25, 2024
Auto merge of #121579 - RalfJung:miri, r=RalfJung
Miri subtree update r? `@ghost`
2 parents a2f3c0c + 9577051 commit 710048f

20 files changed

+460
-322
lines changed
 

‎Cargo.lock

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3308,13 +3308,14 @@ dependencies = [
33083308

33093309
[[package]]
33103310
name = "rustc-build-sysroot"
3311-
version = "0.4.4"
3311+
version = "0.4.5"
33123312
source = "registry+https://github.com/rust-lang/crates.io-index"
3313-
checksum = "39dcf8d82b1f79a179bdb284dc44db440a9666eefa5a6df5ef282d6db930d544"
3313+
checksum = "a26170e1d79ea32f7ccec3188dd13cfc1f18c82764a9cbc1071667c0f865a4ea"
33143314
dependencies = [
33153315
"anyhow",
33163316
"rustc_version",
33173317
"tempfile",
3318+
"walkdir",
33183319
]
33193320

33203321
[[package]]

‎src/tools/miri/Cargo.lock

Lines changed: 85 additions & 159 deletions
Large diffs are not rendered by default.

‎src/tools/miri/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ Miri builds and vice-versa.
279279

280280
You may be running `cargo miri` with a different compiler version than the one
281281
used to build the custom libstd that Miri uses, and Miri failed to detect that.
282-
Try deleting `~/.cache/miri`.
282+
Try running `cargo miri clean`.
283283

284284
#### "no mir for `std::rt::lang_start_internal`"
285285

@@ -465,7 +465,7 @@ Moreover, Miri recognizes some environment variables:
465465
must point to the `library` subdirectory of a `rust-lang/rust` repository
466466
checkout. Note that changing files in that directory does not automatically
467467
trigger a re-build of the standard library; you have to clear the Miri build
468-
cache manually (on Linux, `rm -rf ~/.cache/miri`;
468+
cache with `cargo miri clean` or deleting it manually (on Linux, `rm -rf ~/.cache/miri`;
469469
on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri\cache"`;
470470
and on macOS, `rm -rf ~/Library/Caches/org.rust-lang.miri`).
471471
* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When

‎src/tools/miri/cargo-miri/Cargo.lock

Lines changed: 113 additions & 63 deletions
Large diffs are not rendered by default.

‎src/tools/miri/cargo-miri/src/phases.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Subcommands:
2020
test, t Run tests
2121
nextest Run tests with nextest (requires cargo-nextest installed)
2222
setup Only perform automatic setup, but without asking questions (for getting a proper libstd)
23+
clean Clean the Miri cache & target directory
2324
2425
The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively.
2526
@@ -74,14 +75,15 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
7475
// We cannot know which of those flags take arguments and which do not,
7576
// so we cannot detect subcommands later.
7677
let Some(subcommand) = args.next() else {
77-
show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`)");
78+
show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`, `clean`)");
7879
};
7980
let subcommand = match &*subcommand {
8081
"setup" => MiriCommand::Setup,
8182
"test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand),
83+
"clean" => MiriCommand::Clean,
8284
_ =>
8385
show_error!(
84-
"`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`."
86+
"`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, `clean`, and `setup`."
8587
),
8688
};
8789
let verbose = num_arg_flag("-v");
@@ -93,6 +95,16 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
9395
let target = get_arg_flag_value("--target");
9496
let target = target.as_ref().unwrap_or(host);
9597

98+
// If cleaning the the target directory & sysroot cache,
99+
// delete them then exit. There is no reason to setup a new
100+
// sysroot in this execution.
101+
if let MiriCommand::Clean = subcommand {
102+
let metadata = get_cargo_metadata();
103+
clean_target_dir(&metadata);
104+
clean_sysroot();
105+
return;
106+
}
107+
96108
// We always setup.
97109
let miri_sysroot = setup(&subcommand, target, &rustc_version, verbose);
98110

@@ -110,6 +122,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
110122
let cargo_cmd = match subcommand {
111123
MiriCommand::Forward(s) => s,
112124
MiriCommand::Setup => return, // `cargo miri setup` stops here.
125+
MiriCommand::Clean => unreachable!(),
113126
};
114127
let metadata = get_cargo_metadata();
115128
let mut cmd = cargo();
@@ -142,11 +155,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
142155
.arg(format!("target.'cfg(all())'.runner=[{cargo_miri_path_for_toml}, 'runner']"));
143156

144157
// Set `--target-dir` to `miri` inside the original target directory.
145-
let mut target_dir = match get_arg_flag_value("--target-dir") {
146-
Some(dir) => PathBuf::from(dir),
147-
None => metadata.target_directory.clone().into_std_path_buf(),
148-
};
149-
target_dir.push("miri");
158+
let target_dir = get_target_dir(&metadata);
150159
cmd.arg("--target-dir").arg(target_dir);
151160

152161
// *After* we set all the flags that need setting, forward everything else. Make sure to skip

‎src/tools/miri/cargo-miri/src/setup.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,8 @@ pub fn setup(
6767
}
6868

6969
// Determine where to put the sysroot.
70-
let sysroot_dir = match std::env::var_os("MIRI_SYSROOT") {
71-
Some(dir) => PathBuf::from(dir),
72-
None => {
73-
let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
74-
user_dirs.cache_dir().to_owned()
75-
}
76-
};
70+
let sysroot_dir = get_sysroot_dir();
71+
7772
// Sysroot configuration and build details.
7873
let no_std = match std::env::var_os("MIRI_NO_STD") {
7974
None =>

‎src/tools/miri/cargo-miri/src/util.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ pub enum MiriCommand {
7474
Setup,
7575
/// A command to be forwarded to cargo.
7676
Forward(String),
77+
/// Clean the miri cache
78+
Clean,
7779
}
7880

7981
/// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax.
@@ -249,3 +251,65 @@ pub fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) {
249251
}
250252
eprintln!("{prefix} running command: {cmd:?}");
251253
}
254+
255+
/// Get the target directory for miri output.
256+
///
257+
/// Either in an argument passed-in, or from cargo metadata.
258+
pub fn get_target_dir(meta: &Metadata) -> PathBuf {
259+
let mut output = match get_arg_flag_value("--target-dir") {
260+
Some(dir) => PathBuf::from(dir),
261+
None => meta.target_directory.clone().into_std_path_buf(),
262+
};
263+
output.push("miri");
264+
output
265+
}
266+
267+
/// Determines where the sysroot of this exeuction is
268+
///
269+
/// Either in a user-specified spot by an envar, or in a default cache location.
270+
pub fn get_sysroot_dir() -> PathBuf {
271+
match std::env::var_os("MIRI_SYSROOT") {
272+
Some(dir) => PathBuf::from(dir),
273+
None => {
274+
let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
275+
user_dirs.cache_dir().to_owned()
276+
}
277+
}
278+
}
279+
280+
/// An idempotent version of the stdlib's remove_dir_all
281+
/// it is considered a success if the directory was not there.
282+
fn remove_dir_all_idem(dir: &Path) -> std::io::Result<()> {
283+
match std::fs::remove_dir_all(dir) {
284+
Ok(_) => Ok(()),
285+
// If the directory doesn't exist, it is still a success.
286+
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(()),
287+
Err(err) => Err(err),
288+
}
289+
}
290+
291+
/// Deletes the Miri sysroot cache
292+
/// Returns an error if the MIRI_SYSROOT env var is set.
293+
pub fn clean_sysroot() {
294+
if std::env::var_os("MIRI_SYSROOT").is_some() {
295+
show_error!(
296+
"MIRI_SYSROOT is set. Please clean your custom sysroot cache directory manually."
297+
)
298+
}
299+
300+
let sysroot_dir = get_sysroot_dir();
301+
302+
eprintln!("Cleaning sysroot cache at {}", sysroot_dir.display());
303+
304+
// Keep it simple, just remove the directory.
305+
remove_dir_all_idem(&sysroot_dir).unwrap_or_else(|err| show_error!("{}", err));
306+
}
307+
308+
/// Deletes the Miri target directory
309+
pub fn clean_target_dir(meta: &Metadata) {
310+
let target_dir = get_target_dir(meta);
311+
312+
eprintln!("Cleaning target directory at {}", target_dir.display());
313+
314+
remove_dir_all_idem(&target_dir).unwrap_or_else(|err| show_error!("{}", err))
315+
}

‎src/tools/miri/miri-script/Cargo.lock

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change

‎src/tools/miri/miri.bat

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
:: This makes execution of ./miri on Linux and Windows the same.
2+
:: Windows will not execute the bash script, and select this.
3+
@echo off
4+
set MIRI_SCRIPT_TARGET_DIR=%0\..\miri-script\target
5+
cargo build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml
6+
7+
:: Forwards all arguments to this file to the executable.
8+
:: We invoke the binary directly to avoid going through rustup, which would set some extra
9+
:: env vars that we do not want.
10+
%MIRI_SCRIPT_TARGET_DIR%\debug\miri-script %*

‎src/tools/miri/rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4316d0c6252cb1f833e582dfa68adb98efd5ddfb
1+
c5f69bdd5173a948e0131f934fa7c4cbf5e0b55f

‎src/tools/miri/tests/compiletest.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,18 +99,15 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
9999
};
100100

101101
if with_dependencies {
102+
// Set the `cargo-miri` binary, which we expect to be in the same folder as the `miri` binary.
103+
// (It's a separate crate, so we don't get an env var from cargo.)
104+
let mut prog = miri_path();
105+
prog.set_file_name("cargo-miri");
106+
config.dependency_builder.program = prog;
107+
let builder_args = ["miri", "run"]; // There is no `cargo miri build` so we just use `cargo miri run`.
108+
config.dependency_builder.args = builder_args.into_iter().map(Into::into).collect();
102109
config.dependencies_crate_manifest_path =
103110
Some(Path::new("test_dependencies").join("Cargo.toml"));
104-
let mut builder_args = vec!["run".into()];
105-
builder_args.extend(flagsplit(&env::var("CARGO_EXTRA_FLAGS").unwrap_or_default()));
106-
builder_args.extend([
107-
"--manifest-path".into(),
108-
"cargo-miri/Cargo.toml".into(),
109-
"--".into(),
110-
"miri".into(),
111-
"run".into(), // There is no `cargo miri build` so we just use `cargo miri run`.
112-
]);
113-
config.dependency_builder.args = builder_args.into_iter().map(Into::into).collect();
114111
// Reset `RUSTFLAGS` to work around <https://github.com/rust-lang/rust/pull/119574#issuecomment-1876878344>.
115112
config.dependency_builder.envs.push(("RUSTFLAGS".into(), None));
116113
}

‎src/tools/miri/tests/pass-dep/shims/mmap.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,9 @@ fn test_mremap() {
155155

156156
// Test all of our error conditions
157157
// Not aligned
158-
let ptr =
159-
unsafe { libc::mremap(ptr::without_provenance_mut(1), page_size, page_size, libc::MREMAP_MAYMOVE) };
158+
let ptr = unsafe {
159+
libc::mremap(ptr::without_provenance_mut(1), page_size, page_size, libc::MREMAP_MAYMOVE)
160+
};
160161
assert_eq!(ptr, libc::MAP_FAILED);
161162
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
162163

‎src/tools/miri/tests/pass-dep/shims/pthread-sync.rs

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
#![feature(sync_unsafe_cell)]
55

66
use std::cell::SyncUnsafeCell;
7-
use std::thread;
8-
use std::{mem, ptr};
7+
use std::mem::MaybeUninit;
8+
use std::{mem, ptr, thread};
99

1010
fn main() {
1111
test_mutex_libc_init_recursive();
@@ -15,9 +15,10 @@ fn main() {
1515
#[cfg(target_os = "linux")]
1616
test_mutex_libc_static_initializer_recursive();
1717

18-
test_mutex();
18+
check_mutex();
1919
check_rwlock_write();
2020
check_rwlock_read_no_deadlock();
21+
check_cond();
2122
}
2223

2324
fn test_mutex_libc_init_recursive() {
@@ -119,7 +120,7 @@ impl<T> Clone for SendPtr<T> {
119120
}
120121
}
121122

122-
fn test_mutex() {
123+
fn check_mutex() {
123124
// Specifically *not* using `Arc` to make sure there is no synchronization apart from the mutex.
124125
unsafe {
125126
let data = SyncUnsafeCell::new((libc::PTHREAD_MUTEX_INITIALIZER, 0));
@@ -213,6 +214,53 @@ fn check_rwlock_read_no_deadlock() {
213214
}
214215
}
215216

217+
fn check_cond() {
218+
unsafe {
219+
let mut cond: MaybeUninit<libc::pthread_cond_t> = MaybeUninit::uninit();
220+
assert_eq!(libc::pthread_cond_init(cond.as_mut_ptr(), ptr::null()), 0);
221+
let cond = SendPtr { ptr: cond.as_mut_ptr() };
222+
223+
let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
224+
let mutex = SendPtr { ptr: &mut mutex };
225+
226+
let mut data = 0;
227+
let data = SendPtr { ptr: &mut data };
228+
229+
let t = thread::spawn(move || {
230+
let mutex = mutex; // circumvent per-field closure capture
231+
let cond = cond;
232+
let data = data;
233+
assert_eq!(libc::pthread_mutex_lock(mutex.ptr), 0);
234+
assert!(data.ptr.read() == 0);
235+
data.ptr.write(1);
236+
libc::pthread_cond_wait(cond.ptr, mutex.ptr);
237+
assert!(data.ptr.read() == 3);
238+
data.ptr.write(4);
239+
assert_eq!(libc::pthread_mutex_unlock(mutex.ptr), 0);
240+
});
241+
242+
thread::yield_now();
243+
244+
assert_eq!(libc::pthread_mutex_lock(mutex.ptr), 0);
245+
assert!(data.ptr.read() == 1);
246+
data.ptr.write(2);
247+
assert_eq!(libc::pthread_cond_signal(cond.ptr), 0);
248+
thread::yield_now(); // the other thread wakes up but can't get the lock yet
249+
assert!(data.ptr.read() == 2);
250+
data.ptr.write(3);
251+
assert_eq!(libc::pthread_mutex_unlock(mutex.ptr), 0);
252+
253+
thread::yield_now(); // now the other thread gets the lock back
254+
255+
assert_eq!(libc::pthread_mutex_lock(mutex.ptr), 0);
256+
assert!(data.ptr.read() == 4);
257+
assert_eq!(libc::pthread_cond_broadcast(cond.ptr), 0); // just a smoke test
258+
assert_eq!(libc::pthread_mutex_unlock(mutex.ptr), 0);
259+
260+
t.join().unwrap();
261+
}
262+
}
263+
216264
// std::sync::RwLock does not even used pthread_rwlock any more.
217265
// Do some smoke testing of the API surface.
218266
fn test_rwlock_libc_static_initializer() {

‎src/tools/miri/tests/pass/concurrency/sync.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ fn check_conditional_variables_timed_wait_timeout() {
6363
let cvar = Condvar::new();
6464
let guard = lock.lock().unwrap();
6565
let now = Instant::now();
66-
let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap();
66+
let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(10)).unwrap();
6767
assert!(timeout.timed_out());
6868
let elapsed_time = now.elapsed().as_millis();
69-
assert!(100 <= elapsed_time && elapsed_time <= 1000);
69+
assert!(10 <= elapsed_time && elapsed_time <= 1000);
7070
}
7171

7272
/// Test that signaling a conditional variable when waiting with a timeout works
@@ -79,7 +79,7 @@ fn check_conditional_variables_timed_wait_notimeout() {
7979
let guard = lock.lock().unwrap();
8080

8181
let handle = thread::spawn(move || {
82-
thread::sleep(Duration::from_millis(100)); // Make sure the other thread is waiting by the time we call `notify`.
82+
thread::sleep(Duration::from_millis(1)); // Make sure the other thread is waiting by the time we call `notify`.
8383
let (_lock, cvar) = &*pair2;
8484
cvar.notify_one();
8585
});

‎src/tools/miri/tests/pass/overflow_checks_off.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
// Miri does not implement the codegen-time hack that backs `#[rustc_inherit_overflow_checks]`.
88
// use std::ops::*;
99

10-
1110
// Disable _compile-time_ overflow linting
1211
// so that we can test runtime overflow checks
13-
#![allow(arithmetic_overflow)]
12+
#![allow(arithmetic_overflow)]
1413

1514
fn main() {
1615
assert_eq!(-{ -0x80i8 }, -0x80);

‎src/tools/miri/tests/pass/portable-simd.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -268,15 +268,11 @@ fn simd_mask() {
268268
}
269269

270270
// This used to cause an ICE. It exercises simd_select_bitmask with an array as input.
271-
if cfg!(target_endian = "little") {
272-
// FIXME this test currently fails on big-endian:
273-
// <https://github.com/rust-lang/portable-simd/issues/379>
274-
let bitmask = u8x4::from_array([0b00001101, 0, 0, 0]);
275-
assert_eq!(
276-
mask32x4::from_bitmask_vector(bitmask),
277-
mask32x4::from_array([true, false, true, true]),
278-
);
279-
}
271+
let bitmask = u8x4::from_array([0b00001101, 0, 0, 0]);
272+
assert_eq!(
273+
mask32x4::from_bitmask_vector(bitmask),
274+
mask32x4::from_array([true, false, true, true]),
275+
);
280276
let bitmask = u8x8::from_array([0b01000101, 0, 0, 0, 0, 0, 0, 0]);
281277
assert_eq!(
282278
mask32x8::from_bitmask_vector(bitmask),
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//@only-target-windows: this directly tests windows only random functions
2+
use core::ffi::c_void;
3+
use core::mem::size_of_val;
4+
use core::ptr::null_mut;
5+
6+
// Windows API definitions.
7+
type NTSTATUS = i32;
8+
type BOOLEAN = u8;
9+
const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;
10+
const BCRYPT_RNG_ALG_HANDLE: *mut c_void = 0x81 as *mut c_void;
11+
#[link(name = "bcrypt")]
12+
extern "system" {
13+
fn BCryptGenRandom(
14+
halgorithm: *mut c_void,
15+
pbbuffer: *mut u8,
16+
cbbuffer: u32,
17+
dwflags: u32,
18+
) -> NTSTATUS;
19+
}
20+
#[link(name = "advapi32")]
21+
extern "system" {
22+
#[link_name = "SystemFunction036"]
23+
fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> BOOLEAN;
24+
}
25+
26+
fn main() {
27+
let mut key = [0u8; 24];
28+
let len: u32 = size_of_val(&key).try_into().unwrap();
29+
let ret = unsafe {
30+
BCryptGenRandom(null_mut(), key.as_mut_ptr(), len, BCRYPT_USE_SYSTEM_PREFERRED_RNG)
31+
};
32+
// NTSTATUS codes use the high bit to indicate an error
33+
assert!(ret >= 0);
34+
35+
let ret = unsafe { BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, key.as_mut_ptr(), len, 0) };
36+
assert!(ret >= 0);
37+
38+
let ret = unsafe { RtlGenRandom(key.as_mut_ptr(), len) };
39+
// RtlGenRandom returns a BOOLEAN where 0 indicates an error
40+
assert_ne!(ret, 0);
41+
}

‎src/tools/miri/tests/pass/slices.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ fn slice_of_zst() {
2929

3030
// In a slice of zero-size elements the pointer is meaningless.
3131
// Ensure iteration still works even if the pointer is at the end of the address space.
32-
let slice: &[()] = unsafe { slice::from_raw_parts(ptr::without_provenance(-5isize as usize), 10) };
32+
let slice: &[()] =
33+
unsafe { slice::from_raw_parts(ptr::without_provenance(-5isize as usize), 10) };
3334
assert_eq!(slice.len(), 10);
3435
assert_eq!(slice.iter().count(), 10);
3536

0 commit comments

Comments
 (0)
Please sign in to comment.