Skip to content

Commit 9e9544d

Browse files
committed
Auto merge of #162612 - JonathanBrouwer:rollup-Ma0hPul, r=JonathanBrouwer
Rollup of 6 pull requests Successful merges: - #161334 (Fix soundness issues in std::sys::pal::sgx::waitqueue::unsafe_list) - #162346 (rustdoc: add missing CCI union logic) - #162273 (doc: replace `exceeding_bitshifts` with `arithmetic_overflow`) - #162539 (Update wasip2/wasip3 libstd crate dependencies) - #162542 (Gate ELF code in metadata.rs for ELF only) - #162604 (Update windows-gnu support docs)
2 parents 67eda61 + 013f1e3 commit 9e9544d

29 files changed

Lines changed: 1022 additions & 477 deletions

File tree

compiler/rustc_codegen_ssa/src/back/metadata.rs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,10 @@ pub(super) fn search_for_section<'a>(
129129
fn add_gnu_property_note(
130130
file: &mut write::Object<'static>,
131131
architecture: Architecture,
132-
binary_format: BinaryFormat,
133132
endianness: Endianness,
134133
) {
135-
// check bti protection
136-
if binary_format != BinaryFormat::Elf
137-
|| !matches!(architecture, Architecture::X86_64 | Architecture::Aarch64)
138-
{
134+
// Only X86_64 and Aarch64 require a GNU property note.
135+
if !matches!(architecture, Architecture::X86_64 | Architecture::Aarch64) {
139136
return;
140137
}
141138

@@ -253,12 +250,14 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
253250

254251
file.set_mangling(original_mangling);
255252
}
256-
let e_flags = elf_e_flags(architecture, sess);
257-
// adapted from LLVM's `MCELFObjectTargetWriter::getOSABI`
258-
let os_abi = elf_os_abi(sess);
259-
let abi_version = 0;
260-
add_gnu_property_note(&mut file, architecture, binary_format, endianness);
261-
file.flags = FileFlags::Elf { os_abi, abi_version, e_flags };
253+
if binary_format == BinaryFormat::Elf {
254+
let e_flags = elf_e_flags(architecture, sess);
255+
// adapted from LLVM's `MCELFObjectTargetWriter::getOSABI`
256+
let os_abi = elf_os_abi(sess);
257+
let abi_version = 0;
258+
add_gnu_property_note(&mut file, architecture, endianness);
259+
file.flags = FileFlags::Elf { os_abi, abi_version, e_flags };
260+
}
262261
Some(file)
263262
}
264263

@@ -382,7 +381,6 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
382381
}
383382
}
384383
Architecture::PowerPc64 => {
385-
const EF_PPC64_ABI_UNKNOWN: u32 = 0;
386384
const EF_PPC64_ABI_ELF_V1: u32 = 1;
387385
const EF_PPC64_ABI_ELF_V2: u32 = 2;
388386

@@ -392,11 +390,7 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
392390
// which leads to broken binaries if ELFv1 is used for the object files.
393391
LlvmAbi::ElfV1 => EF_PPC64_ABI_ELF_V1,
394392
LlvmAbi::ElfV2 => EF_PPC64_ABI_ELF_V2,
395-
_ if sess.target.options.binary_format.to_object() == BinaryFormat::Elf => {
396-
bug!("invalid ABI specified for this PPC64 ELF target");
397-
}
398-
// Fall back
399-
_ => EF_PPC64_ABI_UNKNOWN,
393+
_ => bug!("invalid ABI specified for this PPC64 ELF target"),
400394
}
401395
}
402396
Architecture::Sparc32Plus => elf::EF_SPARC_32PLUS,

compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub(crate) fn target() -> Target {
2727
metadata: TargetMetadata {
2828
description: Some("32-bit MinGW (Windows 10+)".into()),
2929
tier: Some(2),
30-
host_tools: Some(true),
30+
host_tools: Some(false),
3131
std: Some(true),
3232
},
3333
pointer_width: 32,

library/Cargo.lock

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -426,9 +426,9 @@ dependencies = [
426426

427427
[[package]]
428428
name = "wasip2"
429-
version = "1.0.4+wasi-0.2.12"
429+
version = "2.0.0+wasi-0.2.12"
430430
source = "registry+https://github.com/rust-lang/crates.io-index"
431-
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
431+
checksum = "96744b5e833bfd2d84c6faa7569693ce9e04a47c0a4d5519e6442f18af1a0fed"
432432
dependencies = [
433433
"rustc-std-workspace-alloc",
434434
"rustc-std-workspace-core",
@@ -437,9 +437,9 @@ dependencies = [
437437

438438
[[package]]
439439
name = "wasip3"
440-
version = "0.7.1+wasi-0.3.0"
440+
version = "0.8.0+wasi-0.3.0"
441441
source = "registry+https://github.com/rust-lang/crates.io-index"
442-
checksum = "75e9ed91ee5a995b6fe16c89d4511a8c12eb76967be20b57557618e02e781bcc"
442+
checksum = "42a999271e77c083825863fc85404197523b3f3cebe9b402aece658ebea90065"
443443
dependencies = [
444444
"rustc-std-workspace-alloc",
445445
"rustc-std-workspace-core",
@@ -456,9 +456,9 @@ version = "0.61.100"
456456

457457
[[package]]
458458
name = "wit-bindgen"
459-
version = "0.57.1"
459+
version = "0.61.1"
460460
source = "registry+https://github.com/rust-lang/crates.io-index"
461-
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
461+
checksum = "e473fd0095479f9689ac7d2a52c427cc96bb2b973ace50238dfcc1ab1cd52d93"
462462
dependencies = [
463463
"rustc-std-workspace-alloc",
464464
"rustc-std-workspace-core",

library/std/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,12 @@ wasip1 = { version = "1.0.0", features = [
8484
], default-features = false }
8585

8686
[target.'cfg(all(target_os = "wasi", target_env = "p2"))'.dependencies]
87-
wasip2 = { version = '1.0.3', features = [
87+
wasip2 = { version = '2.0.0', features = [
8888
'rustc-dep-of-std',
8989
], default-features = false }
9090

9191
[target.'cfg(all(target_os = "wasi", target_env = "p3"))'.dependencies]
92-
wasip3 = { version = '0.7.0', features = [
92+
wasip3 = { version = '0.8.0', features = [
9393
'rustc-dep-of-std',
9494
], default-features = false }
9595

library/std/src/sys/pal/sgx/abi/usercalls/mod.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
use crate::arch::x86_64::_rdrand64_step;
12
use crate::cmp;
23
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
3-
use crate::random::random;
44
use crate::time::{Duration, Instant};
55

66
pub(crate) mod alloc;
@@ -167,6 +167,12 @@ pub fn exit(panic: bool) -> ! {
167167
/// Usercall `wait`. See the ABI documentation for more information.
168168
#[unstable(feature = "sgx_platform", issue = "56975")]
169169
pub fn wait(event_mask: u64, mut timeout: u64) -> io::Result<u64> {
170+
fn try_rdrand() -> Option<u64> {
171+
let mut val: u64 = 0;
172+
// SAFETY: the rdrand feature is enabled on SGX targets
173+
if unsafe { _rdrand64_step(&mut val) } == 1 { Some(val) } else { None }
174+
}
175+
170176
if timeout != WAIT_NO && timeout != WAIT_INDEFINITE {
171177
// We don't want people to rely on accuracy of timeouts to make
172178
// security decisions in an SGX enclave. That's why we add a random
@@ -175,9 +181,14 @@ pub fn wait(event_mask: u64, mut timeout: u64) -> io::Result<u64> {
175181
// to make things work in other cases. Note that in the SGX threat
176182
// model the enclave runner which is serving the wait usercall is not
177183
// trusted to ensure accurate timeouts.
184+
//
185+
// Since the random timeout is only intended as defense-in-depth
186+
// protection at development/testing time, it's ok to continue if
187+
// randomness generation fails.
178188
if let Ok(timeout_signed) = i64::try_from(timeout) {
179189
let tenth = timeout_signed / 10;
180-
let deviation = random::<i64>(..).checked_rem(tenth).unwrap_or(0);
190+
let deviation =
191+
try_rdrand().and_then(|rnd| (rnd as i64).checked_rem(tenth)).unwrap_or(0);
181192
timeout = timeout_signed.saturating_add(deviation) as _;
182193
}
183194
}

library/std/src/sys/pal/sgx/waitqueue/mod.rs

Lines changed: 84 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@
1414
mod tests;
1515

1616
mod spin_mutex;
17-
mod unsafe_list;
1817

1918
use fortanix_sgx_abi::{EV_UNPARK, Tcs, WAIT_INDEFINITE};
2019

21-
pub use self::spin_mutex::{SpinMutex, SpinMutexGuard, try_lock_or_false};
22-
use self::unsafe_list::{UnsafeList, UnsafeListEntry};
20+
pub use self::spin_mutex::{SpinMutex, SpinMutexGuard};
2321
use super::abi::{thread, usercalls};
2422
use crate::num::NonZero;
2523
use crate::ops::{Deref, DerefMut};
2624
use crate::panic::{self, AssertUnwindSafe};
25+
use crate::pin::Pin;
26+
use crate::sys::sync::unsafe_list::{UnsafeList, UnsafeListEntry};
2727
use crate::time::Duration;
2828

2929
/// An queue entry in a `WaitQueue`.
@@ -38,24 +38,41 @@ struct WaitEntry {
3838
/// queue and the data are synchronized, since the type itself is not `Sync`.
3939
///
4040
/// Consumers of this API should use a synchronization primitive for shared
41-
/// access, such as `SpinMutex`.
42-
#[derive(Default)]
41+
/// access. `WaitVariable::new` is the only constructor and provides that
42+
/// with `SpinMutex`.
4343
pub struct WaitVariable<T> {
4444
queue: WaitQueue,
4545
lock: T,
4646
}
4747

4848
impl<T> WaitVariable<T> {
49-
pub const fn new(var: T) -> Self {
50-
WaitVariable { queue: WaitQueue::new(), lock: var }
51-
}
52-
5349
pub fn lock_var(&self) -> &T {
5450
&self.lock
5551
}
5652

57-
pub fn lock_var_mut(&mut self) -> &mut T {
58-
&mut self.lock
53+
pub fn lock_var_mut(self: Pin<&mut Self>) -> &mut T {
54+
// SAFETY: `lock` is not structurally pinned: a pinned `WaitVariable`
55+
// makes no promise that `T` is pinned.
56+
unsafe { &mut self.get_unchecked_mut().lock }
57+
}
58+
59+
fn queue(self: Pin<&mut Self>) -> Pin<&mut WaitQueue> {
60+
// SAFETY: `queue` is structurally pinned: a pinned `WaitVariable`
61+
// pins it, and it is never moved out of it.
62+
unsafe { self.map_unchecked_mut(|this| &mut this.queue) }
63+
}
64+
65+
/// Creates a mutex-protected `WaitVariable` on the heap, with its queue's
66+
/// list initialized. Initialization makes the list self-referential and
67+
/// happens before pinning: only the `Box` pointer is moved into the
68+
/// `Pin`, the heap allocation itself never moves.
69+
pub fn new(value: T) -> Pin<Box<SpinMutex<WaitVariable<T>>>> {
70+
// SAFETY: `init` is called below, before the queue is otherwise used
71+
// or dropped.
72+
let queue = unsafe { WaitQueue::new() };
73+
let result = Box::new(SpinMutex::new(WaitVariable { queue, lock: value }));
74+
result.lock().queue.inner.init();
75+
Box::into_pin(result)
5976
}
6077
}
6178

@@ -68,7 +85,7 @@ pub enum NotifiedTcs {
6885
/// An RAII guard that will notify a set of target threads as well as unlock
6986
/// a mutex on drop.
7087
pub struct WaitGuard<'a, T: 'a> {
71-
mutex_guard: Option<SpinMutexGuard<'a, WaitVariable<T>>>,
88+
mutex_guard: Option<Pin<SpinMutexGuard<'a, WaitVariable<T>>>>,
7289
notified_tcs: NotifiedTcs,
7390
}
7491

@@ -79,21 +96,36 @@ pub struct WaitGuard<'a, T: 'a> {
7996
/// safe because the waiting thread will not return from that stack frame until
8097
/// after it is notified. The notifying thread ensures to clean up any
8198
/// references to the list entries before sending the wakeup event.
99+
// The safety requirements of `UnsafeList` are upheld as follows:
100+
//
101+
// * All list operations are performed while holding the lock of the
102+
// `SpinMutex` around the `WaitVariable` containing the list.
103+
// * A waiting thread pushes a stack-allocated entry and does not invalidate
104+
// it while it is in the list: it only accesses the entry through the
105+
// reference `push` returned, reading `wake` under the `WaitEntry`'s own
106+
// `SpinMutex`.
107+
// * `push` -> `pop`: a notifying thread pops the entry and sets `wake` under
108+
// the `WaitEntry`'s `SpinMutex`; when that mutex is released, the thread
109+
// will no longer access the entry (guaranteed by the mutex guard). The
110+
// waiting thread only returns from the stack frame containing the entry
111+
// once it observes `wake == true` under that same mutex, so the entry is
112+
// only deallocated after the notifying thread's last access to it.
113+
// * `push` -> `remove`: on a timeout, `wait_timeout` re-acquires the queue
114+
// lock and checks `wake`: the entry is still in the list if and only if
115+
// `wake` is not set, because notifying threads always `pop` an entry
116+
// before setting its `wake`. Only if the entry is still in the list is it
117+
// removed.
118+
// * Besides as described, no other exclusive references to the entry are
119+
// taken.
82120
pub struct WaitQueue {
83121
// We use an inner Mutex here to protect the data in the face of spurious
84122
// wakeups.
85123
inner: UnsafeList<SpinMutex<WaitEntry>>,
86124
}
87125
unsafe impl Send for WaitQueue {}
88126

89-
impl Default for WaitQueue {
90-
fn default() -> Self {
91-
Self::new()
92-
}
93-
}
94-
95127
impl<'a, T> Deref for WaitGuard<'a, T> {
96-
type Target = SpinMutexGuard<'a, WaitVariable<T>>;
128+
type Target = Pin<SpinMutexGuard<'a, WaitVariable<T>>>;
97129

98130
fn deref(&self) -> &Self::Target {
99131
self.mutex_guard.as_ref().unwrap()
@@ -118,23 +150,42 @@ impl<'a, T> Drop for WaitGuard<'a, T> {
118150
}
119151

120152
impl WaitQueue {
121-
pub const fn new() -> Self {
122-
WaitQueue { inner: UnsafeList::new() }
153+
/// Creates a new queue.
154+
///
155+
/// # Safety
156+
///
157+
/// The caller must initialize the queue's list (`UnsafeList::init`)
158+
/// before any other use of the queue, including dropping it.
159+
/// `WaitVariable::new`, the sole constructor of the containing
160+
/// structure, does this.
161+
pub const unsafe fn new() -> Self {
162+
// SAFETY: the caller upholds `UnsafeList::new`'s contract (see this
163+
// function's safety requirements).
164+
WaitQueue { inner: unsafe { UnsafeList::new() } }
165+
}
166+
167+
fn inner(self: Pin<&mut Self>) -> Pin<&mut UnsafeList<SpinMutex<WaitEntry>>> {
168+
// SAFETY: `inner` is structurally pinned: a pinned `WaitQueue` pins
169+
// it, and it is never moved out of it.
170+
unsafe { self.map_unchecked_mut(|this| &mut this.inner) }
123171
}
124172

125173
/// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
126174
/// until a wakeup event.
127175
///
128176
/// This function does not return until this thread has been awoken. When `before_wait` panics,
129177
/// this function will abort.
130-
pub fn wait<T, F: FnOnce()>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>, before_wait: F) {
178+
pub fn wait<T, F: FnOnce()>(
179+
mut guard: Pin<SpinMutexGuard<'_, WaitVariable<T>>>,
180+
before_wait: F,
181+
) {
131182
// very unsafe: check requirements of UnsafeList::push
132183
unsafe {
133184
let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry {
134185
tcs: thread::current(),
135186
wake: false,
136187
}));
137-
let entry = guard.queue.inner.push(&mut entry);
188+
let entry = guard.as_mut().queue().inner().push(&mut entry);
138189
drop(guard);
139190
if let Err(_e) = panic::catch_unwind(AssertUnwindSafe(|| before_wait())) {
140191
rtabort!("Panic before wait on wakeup event")
@@ -155,7 +206,7 @@ impl WaitQueue {
155206
/// If not, it will remove the calling thread from the wait queue.
156207
/// When `before_wait` panics, this function will abort.
157208
pub fn wait_timeout<T, F: FnOnce()>(
158-
lock: &SpinMutex<WaitVariable<T>>,
209+
lock: Pin<&SpinMutex<WaitVariable<T>>>,
159210
timeout: Duration,
160211
before_wait: F,
161212
) -> bool {
@@ -165,19 +216,19 @@ impl WaitQueue {
165216
tcs: thread::current(),
166217
wake: false,
167218
}));
168-
let entry_lock = lock.lock().queue.inner.push(&mut entry);
219+
let entry_lock = lock.lock_pinned().as_mut().queue().inner().push(&mut entry);
169220
if let Err(_e) = panic::catch_unwind(AssertUnwindSafe(|| before_wait())) {
170221
rtabort!("Panic before wait on wakeup event or timeout")
171222
}
172223
usercalls::wait_timeout(EV_UNPARK, timeout, || entry_lock.lock().wake);
173224
// acquire the wait queue's lock first to avoid deadlock
174225
// and ensure no other function can simultaneously access the list
175226
// (e.g., `notify_one` or `notify_all`)
176-
let mut guard = lock.lock();
227+
let mut guard = lock.lock_pinned();
177228
let success = entry_lock.lock().wake;
178229
if !success {
179230
// nobody is waking us up, so remove our entry from the wait queue.
180-
guard.queue.inner.remove(&mut entry);
231+
guard.as_mut().queue().inner().remove(&mut entry);
181232
}
182233
success
183234
}
@@ -189,14 +240,14 @@ impl WaitQueue {
189240
/// If a waiter is found, a `WaitGuard` is returned which will notify the
190241
/// waiter when it is dropped.
191242
pub fn notify_one<T>(
192-
mut guard: SpinMutexGuard<'_, WaitVariable<T>>,
193-
) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> {
243+
mut guard: Pin<SpinMutexGuard<'_, WaitVariable<T>>>,
244+
) -> Result<WaitGuard<'_, T>, Pin<SpinMutexGuard<'_, WaitVariable<T>>>> {
194245
// SAFETY: lifetime of the pop() return value is limited to the map
195246
// closure (The closure return value is 'static). The underlying
196247
// stack frame won't be freed until after the lock on the queue is released
197248
// (i.e., `guard` is dropped).
198249
unsafe {
199-
let tcs = guard.queue.inner.pop().map(|entry| -> Tcs {
250+
let tcs = guard.as_mut().queue().inner().pop().map(|entry| -> Tcs {
200251
let mut entry_guard = entry.lock();
201252
entry_guard.wake = true;
202253
entry_guard.tcs
@@ -216,14 +267,14 @@ impl WaitQueue {
216267
/// If at least one waiter is found, a `WaitGuard` is returned which will
217268
/// notify all waiters when it is dropped.
218269
pub fn notify_all<T>(
219-
mut guard: SpinMutexGuard<'_, WaitVariable<T>>,
220-
) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> {
270+
mut guard: Pin<SpinMutexGuard<'_, WaitVariable<T>>>,
271+
) -> Result<WaitGuard<'_, T>, Pin<SpinMutexGuard<'_, WaitVariable<T>>>> {
221272
// SAFETY: lifetime of the pop() return values are limited to the
222273
// while loop body. The underlying stack frames won't be freed until
223274
// after the lock on the queue is released (i.e., `guard` is dropped).
224275
unsafe {
225276
let mut count = 0;
226-
while let Some(entry) = guard.queue.inner.pop() {
277+
while let Some(entry) = guard.as_mut().queue().inner().pop() {
227278
count += 1;
228279
let mut entry_guard = entry.lock();
229280
entry_guard.wake = true;

0 commit comments

Comments
 (0)