Skip to content

Commit 045b177

Browse files
committed
Auto merge of #156118 - RalfJung:miri, r=RalfJung
miri subtree update Subtree update of `miri` to rust-lang/miri@0853747. Created using https://github.com/rust-lang/josh-sync. r? @ghost
2 parents ad3a598 + 7bcb8c1 commit 045b177

29 files changed

Lines changed: 441 additions & 107 deletions

File tree

src/tools/miri/.github/workflows/ci.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ jobs:
5858
env:
5959
HOST_TARGET: ${{ matrix.host_target }}
6060
steps:
61-
- uses: actions/checkout@v5
61+
- uses: actions/checkout@v6
6262
- name: install multiarch
6363
if: ${{ matrix.multiarch != '' }}
6464
run: |
@@ -105,7 +105,7 @@ jobs:
105105
name: style checks
106106
runs-on: ubuntu-latest
107107
steps:
108-
- uses: actions/checkout@v5
108+
- uses: actions/checkout@v6
109109
- uses: ./.github/workflows/setup
110110

111111
- name: rustfmt
@@ -121,7 +121,7 @@ jobs:
121121
name: bootstrap build
122122
runs-on: ubuntu-latest
123123
steps:
124-
- uses: actions/checkout@v5
124+
- uses: actions/checkout@v6
125125
# Deliberately skipping `./.github/workflows/setup` as we do our own setup
126126
- name: Add cache for cargo
127127
id: cache
@@ -156,7 +156,7 @@ jobs:
156156
name: coverage report
157157
runs-on: ubuntu-latest
158158
steps:
159-
- uses: actions/checkout@v5
159+
- uses: actions/checkout@v6
160160
- uses: ./.github/workflows/setup
161161
- name: coverage
162162
run: ./miri test --coverage
@@ -191,7 +191,7 @@ jobs:
191191
pull-requests: write
192192
if: ${{ github.event_name == 'schedule' }}
193193
steps:
194-
- uses: actions/checkout@v5
194+
- uses: actions/checkout@v6
195195
with:
196196
fetch-depth: 256 # get a bit more of the history
197197
- name: install josh-sync
@@ -205,7 +205,7 @@ jobs:
205205
- name: Install rustup-toolchain-install-master
206206
run: cargo install -f rustup-toolchain-install-master
207207
# Create a token for the next step so it can create a PR that actually runs CI.
208-
- uses: actions/create-github-app-token@v2
208+
- uses: actions/create-github-app-token@v3
209209
id: app-token
210210
with:
211211
app-id: ${{ vars.APP_CLIENT_ID }}

src/tools/miri/.github/workflows/sysroots.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
name: Build the sysroots
1414
runs-on: ubuntu-latest
1515
steps:
16-
- uses: actions/checkout@v4
16+
- uses: actions/checkout@v6
1717
- name: Build the sysroots
1818
run: |
1919
rustup toolchain install nightly
@@ -25,7 +25,7 @@ jobs:
2525
- name: Upload build errors
2626
# We don't want to skip this step on failure
2727
if: always()
28-
uses: actions/upload-artifact@v4
28+
uses: actions/upload-artifact@v7
2929
with:
3030
name: failures
3131
path: failures.tar.gz
@@ -38,7 +38,7 @@ jobs:
3838
steps:
3939
# Download our build error logs
4040
- name: Download build errors
41-
uses: actions/download-artifact@v4
41+
uses: actions/download-artifact@v8
4242
with:
4343
name: failures
4444
# Send a Zulip notification

src/tools/miri/rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
9836b06b55f5389f605ee7766eeecd9f17a86cb5
1+
44860d3e9ef700cac0b4a61d924f41f46bf1b447

src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_abi::Size;
2+
use rustc_hir::find_attr;
23
use rustc_middle::mir::Mutability;
34
use rustc_middle::ty::layout::HasTypingEnv;
45
use rustc_middle::ty::{self, Ty};
@@ -137,16 +138,23 @@ impl<'tcx> NewPermission {
137138
let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env());
138139
let is_protected = mode == RetagMode::FnEntry;
139140

140-
// Check if the implicit writes check has been enabled for this function using the `-Zmiri-tree-borrows-implicit-writes` flag
141-
let implicit_writes = cx
142-
.machine
143-
.borrow_tracker
144-
.as_ref()
145-
.unwrap()
146-
.borrow()
147-
.borrow_tracker_method
148-
.get_tree_borrows_params()
149-
.implicit_writes;
141+
// Check if the implicit writes feature is globally enabled, using the
142+
// `-Zmiri-tree-borrows-implicit-writes` flag, and not locally disabled using the
143+
// `#[rustc_no_writable]` attribute. For performance reasons, only performs the lookup if
144+
// is_protected is true as implicit writes are only performed for protected references.
145+
let implicit_writes_enabled = is_protected && {
146+
let implicit_writes = cx
147+
.machine
148+
.borrow_tracker
149+
.as_ref()
150+
.unwrap()
151+
.borrow()
152+
.borrow_tracker_method
153+
.get_tree_borrows_params()
154+
.implicit_writes;
155+
let def_id = cx.frame().instance().def_id();
156+
implicit_writes && !find_attr!(cx.tcx, def_id, RustcNoWritable)
157+
};
150158

151159
if matches!(ref_mutability, Some(Mutability::Mut) | None if !ty_is_unpin) {
152160
// Mutable reference / Box to pinning type: retagging is a NOP.
@@ -179,7 +187,7 @@ impl<'tcx> NewPermission {
179187
},
180188
// Mutable references
181189
Some(Mutability::Mut) => {
182-
if is_protected && implicit_writes && !matches!(part, Outside) {
190+
if implicit_writes_enabled && !matches!(part, Outside) {
183191
// We cannot use `Unique` for the outside part.
184192
Permission::new_unique()
185193
} else if is_protected || frozen {
@@ -191,8 +199,8 @@ impl<'tcx> NewPermission {
191199
}
192200
}
193201
// Boxes
194-
None =>
195-
if is_protected && implicit_writes && !matches!(part, Outside) {
202+
None => {
203+
if implicit_writes_enabled && !matches!(part, Outside) {
196204
// Boxes are treated the same as mutable references.
197205
Permission::new_unique()
198206
} else if is_protected || frozen {
@@ -201,7 +209,8 @@ impl<'tcx> NewPermission {
201209
Permission::new_reserved_frz()
202210
} else {
203211
Permission::new_reserved_im()
204-
},
212+
}
213+
}
205214
}
206215
};
207216

@@ -477,15 +486,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
477486
mode: RetagMode,
478487
) -> InterpResult<'tcx, Option<ImmTy<'tcx>>> {
479488
let this = self.eval_context_mut();
480-
let new_perm = match ty.kind() {
489+
let new_perm = match *ty.kind() {
481490
_ if ty.is_box_global(*this.tcx) => {
482491
// The `None` marks this as a Box.
483492
NewPermission::new(ty.builtin_deref(true).unwrap(), None, mode, this)
484493
}
485-
&ty::Ref(_, pointee, mutability) =>
494+
ty::Ref(_, pointee, mutability) =>
486495
NewPermission::new(pointee, Some(mutability), mode, this),
487496

488-
&ty::RawPtr(..) => {
497+
ty::RawPtr(..) => {
489498
assert!(mode == RetagMode::Raw);
490499
// We don't give new tags to raw pointers.
491500
None

src/tools/miri/src/concurrency/blocking_io.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
219219
let this = self.eval_context_mut();
220220
this.machine.blocking_io.register(
221221
source_fd,
222-
InterestReceiver::UnblockThread(this.machine.threads.active_thread()),
222+
InterestReceiver::UnblockThread(this.active_thread()),
223223
interests,
224224
);
225225
this.block_thread(BlockReason::IO, timeout, callback);

src/tools/miri/src/concurrency/thread.rs

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl From<ThreadId> for u64 {
9090
}
9191

9292
/// Keeps track of what the thread is blocked on.
93-
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
93+
#[derive(Debug, Clone, PartialEq, Eq)]
9494
pub enum BlockReason {
9595
/// The thread tried to join the specified thread and is blocked until that
9696
/// thread terminates.
@@ -151,8 +151,8 @@ impl<'tcx> ThreadState<'tcx> {
151151
matches!(self, ThreadState::Terminated)
152152
}
153153

154-
fn is_blocked_on(&self, reason: BlockReason) -> bool {
155-
matches!(*self, ThreadState::Blocked { reason: actual_reason, .. } if actual_reason == reason)
154+
fn is_blocked_on(&self, reason: &BlockReason) -> bool {
155+
matches!(self, ThreadState::Blocked { reason: actual_reason, .. } if actual_reason == reason)
156156
}
157157
}
158158

@@ -421,9 +421,14 @@ pub enum TimeoutAnchor {
421421
Absolute,
422422
}
423423

424-
/// An error signaling that the requested thread doesn't exist.
424+
/// An error signaling that the requested thread doesn't exist or has terminated.
425425
#[derive(Debug, Copy, Clone)]
426-
pub struct ThreadNotFound;
426+
pub enum ThreadLookupError {
427+
/// No thread with this ID exists.
428+
InvalidId,
429+
/// The thread exists but has already terminated.
430+
Terminated(ThreadId),
431+
}
427432

428433
/// A set of threads.
429434
#[derive(Debug)]
@@ -489,13 +494,21 @@ impl<'tcx> ThreadManager<'tcx> {
489494
}
490495
}
491496

492-
pub fn thread_id_try_from(&self, id: impl TryInto<u32>) -> Result<ThreadId, ThreadNotFound> {
497+
/// Returns the `ThreadId` for the given raw thread id.
498+
/// Returns `Err(ThreadNotFound::InvalidId)` if the id is out of range, or
499+
/// `Err(ThreadNotFound::Terminated(id))` if the thread exists but has terminated.
500+
pub fn thread_id_try_from(&self, id: impl TryInto<u32>) -> Result<ThreadId, ThreadLookupError> {
493501
if let Ok(id) = id.try_into()
494502
&& usize::try_from(id).is_ok_and(|id| id < self.threads.len())
495503
{
496-
Ok(ThreadId(id))
504+
let thread_id = ThreadId(id);
505+
if self.threads[thread_id].state.is_terminated() {
506+
Err(ThreadLookupError::Terminated(thread_id))
507+
} else {
508+
Ok(thread_id)
509+
}
497510
} else {
498-
Err(ThreadNotFound)
511+
Err(ThreadLookupError::InvalidId)
499512
}
500513
}
501514

@@ -696,7 +709,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
696709
// If a thread is blocked on GenMC, we have to implicitly unblock it when it gets scheduled again.
697710
if this.machine.threads.threads[next_thread_id]
698711
.state
699-
.is_blocked_on(BlockReason::Genmc)
712+
.is_blocked_on(&BlockReason::Genmc)
700713
{
701714
info!(
702715
"GenMC: scheduling blocked thread {next_thread_id:?}, so we unblock it now."
@@ -798,7 +811,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
798811
} else if thread_manager
799812
.threads
800813
.iter()
801-
.any(|thread| thread.state.is_blocked_on(BlockReason::IO))
814+
.any(|thread| thread.state.is_blocked_on(&BlockReason::IO))
802815
{
803816
// At least one thread is blocked on host I/O but doesn't
804817
// have a timeout set. Hence, we sleep indefinitely in the
@@ -884,7 +897,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
884897
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
885898
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
886899
#[inline]
887-
fn thread_id_try_from(&self, id: impl TryInto<u32>) -> Result<ThreadId, ThreadNotFound> {
900+
fn thread_id_try_from(&self, id: impl TryInto<u32>) -> Result<ThreadId, ThreadLookupError> {
888901
self.eval_context_ref().machine.threads.thread_id_try_from(id)
889902
}
890903

@@ -1059,11 +1072,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
10591072
let threads = &this.machine.threads.threads;
10601073
let joining_threads = threads
10611074
.iter_enumerated()
1062-
.filter(|(_, thread)| thread.state.is_blocked_on(unblock_reason))
1075+
.filter(|(_, thread)| thread.state.is_blocked_on(&unblock_reason))
10631076
.map(|(id, _)| id)
10641077
.collect::<Vec<_>>();
10651078
for thread in joining_threads {
1066-
this.unblock_thread(thread, unblock_reason)?;
1079+
this.unblock_thread(thread, unblock_reason.clone())?;
10671080
}
10681081

10691082
interp_ok(())
@@ -1231,9 +1244,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
12311244

12321245
// Sanity check `join_status`.
12331246
assert!(
1234-
threads
1235-
.iter()
1236-
.all(|thread| { !thread.state.is_blocked_on(BlockReason::Join(joined_thread_id)) }),
1247+
threads.iter().all(|thread| {
1248+
!thread.state.is_blocked_on(&BlockReason::Join(joined_thread_id))
1249+
}),
12371250
"this thread already has threads waiting for its termination"
12381251
);
12391252

src/tools/miri/src/shims/env.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::assert_matches;
12
use std::ffi::{OsStr, OsString};
23

34
use rustc_data_structures::fx::FxHashMap;
@@ -108,23 +109,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
108109
if this.machine.communicate() { std::process::id() } else { 1000 }
109110
}
110111

111-
/// Get an "OS" thread ID for the current thread.
112-
fn get_current_tid(&self) -> u32 {
112+
/// Get an "OS" thread ID for any thread.
113+
fn get_tid(&self, thread: ThreadId) -> u32 {
113114
let this = self.eval_context_ref();
114-
self.get_tid(this.machine.threads.active_thread())
115+
assert!(this.target_os_is_unix());
116+
// On Linux, the main thread has PID == TID so we uphold this. For simplicity we do it
117+
// everywhere. That also ensures this ID is different from what is returned by
118+
// `pthread_self`.
119+
this.get_pid().strict_add(thread.to_u32())
115120
}
116121

117-
/// Get an "OS" thread ID for any thread.
118-
fn get_tid(&self, thread: ThreadId) -> u32 {
122+
/// Convert TID back to a `ThreadId`, or `None` if it is invalid or the thread has terminated.
123+
fn get_thread_id_from_linux_tid(&self, tid: u32) -> Option<ThreadId> {
119124
let this = self.eval_context_ref();
120-
let index = thread.to_u32();
121-
let target_os = &this.tcx.sess.target.os;
122-
if matches!(target_os, Os::Linux | Os::Android) {
123-
// On Linux, the main thread has PID == TID so we uphold this.
124-
this.get_pid().strict_add(index)
125-
} else {
126-
// Other platforms do not display any relationship between PID and TID.
127-
index
128-
}
125+
assert_matches!(this.tcx.sess.target.os, Os::Linux | Os::Android);
126+
// TID = PID + thread_index => index = TID - PID.
127+
let id = tid.checked_sub(this.get_pid())?;
128+
this.machine.threads.thread_id_try_from(id).ok()
129129
}
130130
}

src/tools/miri/src/shims/foreign_items.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
459459
)?;
460460

461461
let thread = this.read_target_usize(thread_id)?;
462-
if let Ok(thread) = this.thread_id_try_from(thread) {
462+
// Joining a terminated thread is valid.
463+
use crate::concurrency::thread::ThreadLookupError;
464+
let thread = match this.thread_id_try_from(thread) {
465+
Ok(id) | Err(ThreadLookupError::Terminated(id)) => Some(id),
466+
Err(ThreadLookupError::InvalidId) => None,
467+
};
468+
if let Some(thread) = thread {
463469
this.join_thread_exclusive(
464470
thread,
465471
/* success_retval */ Scalar::from_bool(true),

src/tools/miri/src/shims/io_error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
251251
fn io_error_to_errnum(&self, err: std::io::Error) -> InterpResult<'tcx, Scalar> {
252252
let this = self.eval_context_ref();
253253
let target = &this.tcx.sess.target;
254+
254255
if target.families.iter().any(|f| f == "unix") {
255256
for &(name, kind) in UNIX_IO_ERROR_TABLE {
256257
if err.kind() == kind {

src/tools/miri/src/shims/unix/env.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
269269

270270
// For most platforms the return type is an `i32`, but some are unsigned. The TID
271271
// will always be positive so we don't need to differentiate.
272-
interp_ok(Scalar::from_u32(this.get_current_tid()))
272+
interp_ok(Scalar::from_u32(this.get_tid(this.active_thread())))
273273
}
274274

275275
/// `fields_size`, if present, says how large each field of the struct is.
@@ -323,7 +323,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
323323
/// allows querying the ID for arbitrary threads, identified by their pthread_t.
324324
///
325325
/// API documentation: <https://www.manpagez.com/man/3/pthread_threadid_np/>.
326-
fn apple_pthread_threadip_np(
326+
fn apple_pthread_threadid_np(
327327
&mut self,
328328
thread_op: &OpTy<'tcx>,
329329
tid_op: &OpTy<'tcx>,
@@ -349,6 +349,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
349349
thread
350350
};
351351

352+
// This returns an `int`, not a `pthread_t`, so we treat it like we treat `gettid` on Linux.
352353
let tid = this.get_tid(thread);
353354
let tid_dest = this.deref_pointer_as(tid_op, this.machine.layouts.u64)?;
354355
this.write_int(tid, &tid_dest)?;

0 commit comments

Comments
 (0)