Skip to content

Commit b4173c8

Browse files
committed
Auto merge of #133339 - jieyouxu:rollup-gav0nvr, r=jieyouxu
Rollup of 8 pull requests Successful merges: - #133238 (re-export `is_loongarch_feature_detected`) - #133288 (Support `each_ref` and `each_mut` in `[T; N]` in constant expressions.) - #133311 (Miri subtree update) - #133313 (Use arc4random of libc for RTEMS target) - #133319 (Simplify `fulfill_implication`) - #133323 (Bail in effects in old solver if self ty is ty var) - #133330 (library: update comment around close()) - #133337 (Fix typo in `std::thread::Scope::spawn` documentation.) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 03ada5d + d028825 commit b4173c8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1530
-763
lines changed

.cargo/config.toml

-9
This file was deleted.

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,7 @@ Definite bugs found:
548548
* [Incorrect offset computation for highly-aligned types in `portable-atomic-util`](https://github.com/taiki-e/portable-atomic/pull/138)
549549
* [Occasional memory leak in `std::mpsc` channels](https://github.com/rust-lang/rust/issues/121582) (original code in [crossbeam](https://github.com/crossbeam-rs/crossbeam/pull/1084))
550550
* [Weak-memory-induced memory leak in Windows thread-local storage](https://github.com/rust-lang/rust/pull/124281)
551+
* [A bug in the new `RwLock::downgrade` implementation](https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/Miri.20error.20library.20test) (caught by Miri before it landed in the Rust repo)
551552

552553
Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):
553554

miri

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
#!/usr/bin/env bash
22
set -e
33
# We want to call the binary directly, so we need to know where it ends up.
4-
MIRI_SCRIPT_TARGET_DIR="$(dirname "$0")"/miri-script/target
4+
ROOT_DIR="$(dirname "$0")"
5+
MIRI_SCRIPT_TARGET_DIR="$ROOT_DIR"/miri-script/target
56
# If stdout is not a terminal and we are not on CI, assume that we are being invoked by RA, and use JSON output.
67
if ! [ -t 1 ] && [ -z "$CI" ]; then
78
MESSAGE_FORMAT="--message-format=json"
89
fi
9-
# We need a nightly toolchain, for the `profile-rustflags` cargo feature.
10-
cargo +nightly build $CARGO_EXTRA_FLAGS --manifest-path "$(dirname "$0")"/miri-script/Cargo.toml \
10+
# We need a nightly toolchain, for `-Zroot-dir`.
11+
cargo +nightly build $CARGO_EXTRA_FLAGS --manifest-path "$ROOT_DIR"/miri-script/Cargo.toml \
12+
-Zroot-dir="$ROOT_DIR" \
1113
-q --target-dir "$MIRI_SCRIPT_TARGET_DIR" $MESSAGE_FORMAT || \
1214
( echo "Failed to build miri-script. Is the 'nightly' toolchain installed?"; exit 1 )
1315
# Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly. Invoking `cargo run` goes through

miri-script/src/util.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,16 @@ impl MiriEnv {
105105

106106
// Get extra flags for cargo.
107107
let cargo_extra_flags = std::env::var("CARGO_EXTRA_FLAGS").unwrap_or_default();
108-
let cargo_extra_flags = flagsplit(&cargo_extra_flags);
108+
let mut cargo_extra_flags = flagsplit(&cargo_extra_flags);
109109
if cargo_extra_flags.iter().any(|a| a == "--release" || a.starts_with("--profile")) {
110110
// This makes binaries end up in different paths, let's not do that.
111111
eprintln!(
112112
"Passing `--release` or `--profile` in `CARGO_EXTRA_FLAGS` will totally confuse miri-script, please don't do that."
113113
);
114114
std::process::exit(1);
115115
}
116+
// Also set `-Zroot-dir` for cargo, to print diagnostics relative to the miri dir.
117+
cargo_extra_flags.push(format!("-Zroot-dir={}", miri_dir.display()));
116118

117119
Ok(MiriEnv { miri_dir, toolchain, sh, sysroot, cargo_extra_flags, libdir })
118120
}

rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
668959740f97e7a22ae340742886d330ab63950f
1+
2d0ea7956c45de6e421fd579e2ded27be405dec6

src/concurrency/sync.rs

+70-48
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::cell::RefCell;
22
use std::collections::VecDeque;
33
use std::collections::hash_map::Entry;
4+
use std::default::Default;
45
use std::ops::Not;
56
use std::rc::Rc;
67
use std::time::Duration;
@@ -46,8 +47,6 @@ macro_rules! declare_id {
4647
}
4748
pub(super) use declare_id;
4849

49-
declare_id!(MutexId);
50-
5150
/// The mutex state.
5251
#[derive(Default, Debug)]
5352
struct Mutex {
@@ -61,6 +60,21 @@ struct Mutex {
6160
clock: VClock,
6261
}
6362

63+
#[derive(Default, Clone, Debug)]
64+
pub struct MutexRef(Rc<RefCell<Mutex>>);
65+
66+
impl MutexRef {
67+
fn new() -> Self {
68+
MutexRef(Rc::new(RefCell::new(Mutex::default())))
69+
}
70+
}
71+
72+
impl VisitProvenance for MutexRef {
73+
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
74+
// Mutex contains no provenance.
75+
}
76+
}
77+
6478
declare_id!(RwLockId);
6579

6680
/// The read-write lock state.
@@ -144,7 +158,6 @@ struct FutexWaiter {
144158
/// The state of all synchronization objects.
145159
#[derive(Default, Debug)]
146160
pub struct SynchronizationObjects {
147-
mutexes: IndexVec<MutexId, Mutex>,
148161
rwlocks: IndexVec<RwLockId, RwLock>,
149162
condvars: IndexVec<CondvarId, Condvar>,
150163
pub(super) init_onces: IndexVec<InitOnceId, InitOnce>,
@@ -155,17 +168,17 @@ impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
155168
pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
156169
fn condvar_reacquire_mutex(
157170
&mut self,
158-
mutex: MutexId,
171+
mutex_ref: &MutexRef,
159172
retval: Scalar,
160173
dest: MPlaceTy<'tcx>,
161174
) -> InterpResult<'tcx> {
162175
let this = self.eval_context_mut();
163-
if this.mutex_is_locked(mutex) {
164-
assert_ne!(this.mutex_get_owner(mutex), this.active_thread());
165-
this.mutex_enqueue_and_block(mutex, Some((retval, dest)));
176+
if this.mutex_is_locked(mutex_ref) {
177+
assert_ne!(this.mutex_get_owner(mutex_ref), this.active_thread());
178+
this.mutex_enqueue_and_block(mutex_ref, Some((retval, dest)));
166179
} else {
167180
// We can have it right now!
168-
this.mutex_lock(mutex);
181+
this.mutex_lock(mutex_ref);
169182
// Don't forget to write the return value.
170183
this.write_scalar(retval, &dest)?;
171184
}
@@ -174,10 +187,9 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
174187
}
175188

176189
impl SynchronizationObjects {
177-
pub fn mutex_create(&mut self) -> MutexId {
178-
self.mutexes.push(Default::default())
190+
pub fn mutex_create(&mut self) -> MutexRef {
191+
MutexRef::new()
179192
}
180-
181193
pub fn rwlock_create(&mut self) -> RwLockId {
182194
self.rwlocks.push(Default::default())
183195
}
@@ -209,12 +221,16 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
209221
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
210222
/// Helper for lazily initialized `alloc_extra.sync` data:
211223
/// this forces an immediate init.
212-
fn lazy_sync_init<T: 'static + Copy>(
213-
&mut self,
224+
/// Return a reference to the data in the machine state.
225+
fn lazy_sync_init<'a, T: 'static>(
226+
&'a mut self,
214227
primitive: &MPlaceTy<'tcx>,
215228
init_offset: Size,
216229
data: T,
217-
) -> InterpResult<'tcx> {
230+
) -> InterpResult<'tcx, &'a T>
231+
where
232+
'tcx: 'a,
233+
{
218234
let this = self.eval_context_mut();
219235

220236
let (alloc, offset, _) = this.ptr_get_alloc_id(primitive.ptr(), 0)?;
@@ -227,21 +243,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
227243
&init_field,
228244
AtomicWriteOrd::Relaxed,
229245
)?;
230-
interp_ok(())
246+
interp_ok(this.get_alloc_extra(alloc)?.get_sync::<T>(offset).unwrap())
231247
}
232248

233249
/// Helper for lazily initialized `alloc_extra.sync` data:
234250
/// Checks if the primitive is initialized:
235251
/// - If yes, fetches the data from `alloc_extra.sync`, or calls `missing_data` if that fails
236252
/// and stores that in `alloc_extra.sync`.
237253
/// - Otherwise, calls `new_data` to initialize the primitive.
238-
fn lazy_sync_get_data<T: 'static + Copy>(
239-
&mut self,
254+
///
255+
/// Return a reference to the data in the machine state.
256+
fn lazy_sync_get_data<'a, T: 'static>(
257+
&'a mut self,
240258
primitive: &MPlaceTy<'tcx>,
241259
init_offset: Size,
242260
missing_data: impl FnOnce() -> InterpResult<'tcx, T>,
243261
new_data: impl FnOnce(&mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, T>,
244-
) -> InterpResult<'tcx, T> {
262+
) -> InterpResult<'tcx, &'a T>
263+
where
264+
'tcx: 'a,
265+
{
245266
let this = self.eval_context_mut();
246267

247268
// Check if this is already initialized. Needs to be atomic because we can race with another
@@ -265,17 +286,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
265286
// or else it has been moved illegally.
266287
let (alloc, offset, _) = this.ptr_get_alloc_id(primitive.ptr(), 0)?;
267288
let (alloc_extra, _machine) = this.get_alloc_extra_mut(alloc)?;
268-
if let Some(data) = alloc_extra.get_sync::<T>(offset) {
269-
interp_ok(*data)
270-
} else {
289+
// Due to borrow checker reasons, we have to do the lookup twice.
290+
if alloc_extra.get_sync::<T>(offset).is_none() {
271291
let data = missing_data()?;
272292
alloc_extra.sync.insert(offset, Box::new(data));
273-
interp_ok(data)
274293
}
294+
interp_ok(alloc_extra.get_sync::<T>(offset).unwrap())
275295
} else {
276296
let data = new_data(this)?;
277-
this.lazy_sync_init(primitive, init_offset, data)?;
278-
interp_ok(data)
297+
this.lazy_sync_init(primitive, init_offset, data)
279298
}
280299
}
281300

@@ -311,23 +330,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
311330

312331
#[inline]
313332
/// Get the id of the thread that currently owns this lock.
314-
fn mutex_get_owner(&mut self, id: MutexId) -> ThreadId {
315-
let this = self.eval_context_ref();
316-
this.machine.sync.mutexes[id].owner.unwrap()
333+
fn mutex_get_owner(&self, mutex_ref: &MutexRef) -> ThreadId {
334+
mutex_ref.0.borrow().owner.unwrap()
317335
}
318336

319337
#[inline]
320338
/// Check if locked.
321-
fn mutex_is_locked(&self, id: MutexId) -> bool {
322-
let this = self.eval_context_ref();
323-
this.machine.sync.mutexes[id].owner.is_some()
339+
fn mutex_is_locked(&self, mutex_ref: &MutexRef) -> bool {
340+
mutex_ref.0.borrow().owner.is_some()
324341
}
325342

326343
/// Lock by setting the mutex owner and increasing the lock count.
327-
fn mutex_lock(&mut self, id: MutexId) {
344+
fn mutex_lock(&mut self, mutex_ref: &MutexRef) {
328345
let this = self.eval_context_mut();
329346
let thread = this.active_thread();
330-
let mutex = &mut this.machine.sync.mutexes[id];
347+
let mut mutex = mutex_ref.0.borrow_mut();
331348
if let Some(current_owner) = mutex.owner {
332349
assert_eq!(thread, current_owner, "mutex already locked by another thread");
333350
assert!(
@@ -347,9 +364,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
347364
/// count. If the lock count reaches 0, release the lock and potentially
348365
/// give to a new owner. If the lock was not locked by the current thread,
349366
/// return `None`.
350-
fn mutex_unlock(&mut self, id: MutexId) -> InterpResult<'tcx, Option<usize>> {
367+
fn mutex_unlock(&mut self, mutex_ref: &MutexRef) -> InterpResult<'tcx, Option<usize>> {
351368
let this = self.eval_context_mut();
352-
let mutex = &mut this.machine.sync.mutexes[id];
369+
let mut mutex = mutex_ref.0.borrow_mut();
353370
interp_ok(if let Some(current_owner) = mutex.owner {
354371
// Mutex is locked.
355372
if current_owner != this.machine.threads.active_thread() {
@@ -367,8 +384,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
367384
mutex.clock.clone_from(clock)
368385
});
369386
}
370-
if let Some(thread) = this.machine.sync.mutexes[id].queue.pop_front() {
371-
this.unblock_thread(thread, BlockReason::Mutex(id))?;
387+
let thread_id = mutex.queue.pop_front();
388+
// We need to drop our mutex borrow before unblock_thread
389+
// because it will be borrowed again in the unblock callback.
390+
drop(mutex);
391+
if thread_id.is_some() {
392+
this.unblock_thread(thread_id.unwrap(), BlockReason::Mutex)?;
372393
}
373394
}
374395
Some(old_lock_count)
@@ -385,24 +406,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
385406
#[inline]
386407
fn mutex_enqueue_and_block(
387408
&mut self,
388-
id: MutexId,
409+
mutex_ref: &MutexRef,
389410
retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
390411
) {
391412
let this = self.eval_context_mut();
392-
assert!(this.mutex_is_locked(id), "queing on unlocked mutex");
413+
assert!(this.mutex_is_locked(mutex_ref), "queuing on unlocked mutex");
393414
let thread = this.active_thread();
394-
this.machine.sync.mutexes[id].queue.push_back(thread);
415+
mutex_ref.0.borrow_mut().queue.push_back(thread);
416+
let mutex_ref = mutex_ref.clone();
395417
this.block_thread(
396-
BlockReason::Mutex(id),
418+
BlockReason::Mutex,
397419
None,
398420
callback!(
399421
@capture<'tcx> {
400-
id: MutexId,
422+
mutex_ref: MutexRef,
401423
retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
402424
}
403425
@unblock = |this| {
404-
assert!(!this.mutex_is_locked(id));
405-
this.mutex_lock(id);
426+
assert!(!this.mutex_is_locked(&mutex_ref));
427+
this.mutex_lock(&mutex_ref);
406428

407429
if let Some((retval, dest)) = retval_dest {
408430
this.write_scalar(retval, &dest)?;
@@ -623,14 +645,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
623645
fn condvar_wait(
624646
&mut self,
625647
condvar: CondvarId,
626-
mutex: MutexId,
648+
mutex_ref: MutexRef,
627649
timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>,
628650
retval_succ: Scalar,
629651
retval_timeout: Scalar,
630652
dest: MPlaceTy<'tcx>,
631653
) -> InterpResult<'tcx> {
632654
let this = self.eval_context_mut();
633-
if let Some(old_locked_count) = this.mutex_unlock(mutex)? {
655+
if let Some(old_locked_count) = this.mutex_unlock(&mutex_ref)? {
634656
if old_locked_count != 1 {
635657
throw_unsup_format!(
636658
"awaiting a condvar on a mutex acquired multiple times is not supported"
@@ -650,7 +672,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
650672
callback!(
651673
@capture<'tcx> {
652674
condvar: CondvarId,
653-
mutex: MutexId,
675+
mutex_ref: MutexRef,
654676
retval_succ: Scalar,
655677
retval_timeout: Scalar,
656678
dest: MPlaceTy<'tcx>,
@@ -665,15 +687,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
665687
}
666688
// Try to acquire the mutex.
667689
// The timeout only applies to the first wait (until the signal), not for mutex acquisition.
668-
this.condvar_reacquire_mutex(mutex, retval_succ, dest)
690+
this.condvar_reacquire_mutex(&mutex_ref, retval_succ, dest)
669691
}
670692
@timeout = |this| {
671693
// We have to remove the waiter from the queue again.
672694
let thread = this.active_thread();
673695
let waiters = &mut this.machine.sync.condvars[condvar].waiters;
674696
waiters.retain(|waiter| *waiter != thread);
675697
// Now get back the lock.
676-
this.condvar_reacquire_mutex(mutex, retval_timeout, dest)
698+
this.condvar_reacquire_mutex(&mutex_ref, retval_timeout, dest)
677699
}
678700
),
679701
);

src/concurrency/thread.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ impl ThreadId {
113113
self.0
114114
}
115115

116+
/// Create a new thread id from a `u32` without checking if this thread exists.
117+
pub fn new_unchecked(id: u32) -> Self {
118+
Self(id)
119+
}
120+
116121
pub const MAIN_THREAD: ThreadId = ThreadId(0);
117122
}
118123

@@ -141,7 +146,7 @@ pub enum BlockReason {
141146
/// Waiting for time to pass.
142147
Sleep,
143148
/// Blocked on a mutex.
144-
Mutex(MutexId),
149+
Mutex,
145150
/// Blocked on a condition variable.
146151
Condvar(CondvarId),
147152
/// Blocked on a reader-writer lock.
@@ -152,6 +157,8 @@ pub enum BlockReason {
152157
InitOnce(InitOnceId),
153158
/// Blocked on epoll.
154159
Epoll,
160+
/// Blocked on eventfd.
161+
Eventfd,
155162
}
156163

157164
/// The state of a thread.

src/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ pub fn prune_stacktrace<'tcx>(
195195
// This len check ensures that we don't somehow remove every frame, as doing so breaks
196196
// the primary error message.
197197
while stacktrace.len() > 1
198-
&& stacktrace.last().map_or(false, |frame| !machine.is_local(frame))
198+
&& stacktrace.last().is_some_and(|frame| !machine.is_local(frame))
199199
{
200200
stacktrace.pop();
201201
}

0 commit comments

Comments
 (0)