Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7495fdf
rustdoc: add missing CCI union logic
notriddle Sep 5, 2026
be3136b
Add regression test for PathBuf not showing up
notriddle Sep 5, 2026
62adee1
Add regression test for merging search index types
notriddle Sep 5, 2026
82bc685
Fix unsoundness issues in std::sys::pal::sgx::waitqueue::unsafe_list
Aug 6, 2026
994ae4e
Implementing pinning in std::sys::pal::sgx::waitqueue::unsafe_list
Aug 6, 2026
0246333
Move std::sys::pal::sgx::waitqueue::unsafe_list to a platform-agnosti…
Aug 18, 2026
8770fd6
SGX: Abort instead of panic on randomness generation failure
Sep 7, 2026
998113d
SGX: don't abort on randomness failure in usercalls::wait
Sep 7, 2026
724f4af
Sort files for reproducible doc merge
notriddle Sep 8, 2026
d56ed53
Update wasip2/wasip3 libstd crate dependencies
alexcrichton Sep 9, 2026
1e18d10
Gate ELF code in metadata.rs for ELF only.
xingxue-ibm Sep 9, 2026
3a5c7d2
Add comment to downstream-type.js
notriddle Sep 9, 2026
937203f
Add comment to pathbuf.js
notriddle Sep 9, 2026
0a9186a
Add issue link to pathbuf.js
notriddle Sep 9, 2026
fe1c458
doc: replace `exceeding_bitshifts` with `arithmetic_overflow`
chiang03 Sep 9, 2026
6d92da7
Update windows-gnu support docs
mati865 Sep 10, 2026
83e0995
Rollup merge of #161334 - jethrogb:fix-sgx-unsafe-list, r=nia-e
JonathanBrouwer Sep 10, 2026
19f7664
Rollup merge of #162346 - notriddle:rustdoc-merge-type, r=lolbinaryca…
JonathanBrouwer Sep 10, 2026
9de5371
Rollup merge of #162273 - chiang03:main, r=Enselic
JonathanBrouwer Sep 10, 2026
02056c6
Rollup merge of #162539 - alexcrichton:update-wit-bindgen-deps, r=Chr…
JonathanBrouwer Sep 10, 2026
3532a4c
Rollup merge of #162542 - xingxue-ibm:gate-elf-code-for-elf, r=khyperia
JonathanBrouwer Sep 10, 2026
013f1e3
Rollup merge of #162604 - mati865:update-windows-gnu-docs, r=hanna-kr…
JonathanBrouwer Sep 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 11 additions & 17 deletions compiler/rustc_codegen_ssa/src/back/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,10 @@ pub(super) fn search_for_section<'a>(
fn add_gnu_property_note(
file: &mut write::Object<'static>,
architecture: Architecture,
binary_format: BinaryFormat,
endianness: Endianness,
) {
// check bti protection
if binary_format != BinaryFormat::Elf
|| !matches!(architecture, Architecture::X86_64 | Architecture::Aarch64)
{
// Only X86_64 and Aarch64 require a GNU property note.
if !matches!(architecture, Architecture::X86_64 | Architecture::Aarch64) {
return;
}

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

file.set_mangling(original_mangling);
}
let e_flags = elf_e_flags(architecture, sess);
// adapted from LLVM's `MCELFObjectTargetWriter::getOSABI`
let os_abi = elf_os_abi(sess);
let abi_version = 0;
add_gnu_property_note(&mut file, architecture, binary_format, endianness);
file.flags = FileFlags::Elf { os_abi, abi_version, e_flags };
if binary_format == BinaryFormat::Elf {
let e_flags = elf_e_flags(architecture, sess);
// adapted from LLVM's `MCELFObjectTargetWriter::getOSABI`
let os_abi = elf_os_abi(sess);
let abi_version = 0;
add_gnu_property_note(&mut file, architecture, endianness);
file.flags = FileFlags::Elf { os_abi, abi_version, e_flags };
}
Some(file)
}

Expand Down Expand Up @@ -382,7 +381,6 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
}
}
Architecture::PowerPc64 => {
const EF_PPC64_ABI_UNKNOWN: u32 = 0;
const EF_PPC64_ABI_ELF_V1: u32 = 1;
const EF_PPC64_ABI_ELF_V2: u32 = 2;

Expand All @@ -392,11 +390,7 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
// which leads to broken binaries if ELFv1 is used for the object files.
LlvmAbi::ElfV1 => EF_PPC64_ABI_ELF_V1,
LlvmAbi::ElfV2 => EF_PPC64_ABI_ELF_V2,
_ if sess.target.options.binary_format.to_object() == BinaryFormat::Elf => {
bug!("invalid ABI specified for this PPC64 ELF target");
}
// Fall back
_ => EF_PPC64_ABI_UNKNOWN,
_ => bug!("invalid ABI specified for this PPC64 ELF target"),
}
}
Architecture::Sparc32Plus => elf::EF_SPARC_32PLUS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub(crate) fn target() -> Target {
metadata: TargetMetadata {
description: Some("32-bit MinGW (Windows 10+)".into()),
tier: Some(2),
host_tools: Some(true),
host_tools: Some(false),
std: Some(true),
},
pointer_width: 32,
Expand Down
12 changes: 6 additions & 6 deletions library/Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -426,9 +426,9 @@ dependencies = [

[[package]]
name = "wasip2"
version = "1.0.4+wasi-0.2.12"
version = "2.0.0+wasi-0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
checksum = "96744b5e833bfd2d84c6faa7569693ce9e04a47c0a4d5519e6442f18af1a0fed"
dependencies = [
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
Expand All @@ -437,9 +437,9 @@ dependencies = [

[[package]]
name = "wasip3"
version = "0.7.1+wasi-0.3.0"
version = "0.8.0+wasi-0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75e9ed91ee5a995b6fe16c89d4511a8c12eb76967be20b57557618e02e781bcc"
checksum = "42a999271e77c083825863fc85404197523b3f3cebe9b402aece658ebea90065"
dependencies = [
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
Expand All @@ -456,9 +456,9 @@ version = "0.61.100"

[[package]]
name = "wit-bindgen"
version = "0.57.1"
version = "0.61.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
checksum = "e473fd0095479f9689ac7d2a52c427cc96bb2b973ace50238dfcc1ab1cd52d93"
dependencies = [
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
Expand Down
4 changes: 2 additions & 2 deletions library/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ wasip1 = { version = "1.0.0", features = [
], default-features = false }

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

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

Expand Down
15 changes: 13 additions & 2 deletions library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::arch::x86_64::_rdrand64_step;
use crate::cmp;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::random::random;
use crate::time::{Duration, Instant};

pub(crate) mod alloc;
Expand Down Expand Up @@ -167,6 +167,12 @@ pub fn exit(panic: bool) -> ! {
/// Usercall `wait`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn wait(event_mask: u64, mut timeout: u64) -> io::Result<u64> {
fn try_rdrand() -> Option<u64> {
let mut val: u64 = 0;
// SAFETY: the rdrand feature is enabled on SGX targets
if unsafe { _rdrand64_step(&mut val) } == 1 { Some(val) } else { None }
}

if timeout != WAIT_NO && timeout != WAIT_INDEFINITE {
// We don't want people to rely on accuracy of timeouts to make
// security decisions in an SGX enclave. That's why we add a random
Expand All @@ -175,9 +181,14 @@ pub fn wait(event_mask: u64, mut timeout: u64) -> io::Result<u64> {
// to make things work in other cases. Note that in the SGX threat
// model the enclave runner which is serving the wait usercall is not
// trusted to ensure accurate timeouts.
//
// Since the random timeout is only intended as defense-in-depth
// protection at development/testing time, it's ok to continue if
// randomness generation fails.
if let Ok(timeout_signed) = i64::try_from(timeout) {
let tenth = timeout_signed / 10;
let deviation = random::<i64>(..).checked_rem(tenth).unwrap_or(0);
let deviation =
try_rdrand().and_then(|rnd| (rnd as i64).checked_rem(tenth)).unwrap_or(0);
timeout = timeout_signed.saturating_add(deviation) as _;
}
}
Expand Down
117 changes: 84 additions & 33 deletions library/std/src/sys/pal/sgx/waitqueue/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@
mod tests;

mod spin_mutex;
mod unsafe_list;

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

pub use self::spin_mutex::{SpinMutex, SpinMutexGuard, try_lock_or_false};
use self::unsafe_list::{UnsafeList, UnsafeListEntry};
pub use self::spin_mutex::{SpinMutex, SpinMutexGuard};
use super::abi::{thread, usercalls};
use crate::num::NonZero;
use crate::ops::{Deref, DerefMut};
use crate::panic::{self, AssertUnwindSafe};
use crate::pin::Pin;
use crate::sys::sync::unsafe_list::{UnsafeList, UnsafeListEntry};
use crate::time::Duration;

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

impl<T> WaitVariable<T> {
pub const fn new(var: T) -> Self {
WaitVariable { queue: WaitQueue::new(), lock: var }
}

pub fn lock_var(&self) -> &T {
&self.lock
}

pub fn lock_var_mut(&mut self) -> &mut T {
&mut self.lock
pub fn lock_var_mut(self: Pin<&mut Self>) -> &mut T {
// SAFETY: `lock` is not structurally pinned: a pinned `WaitVariable`
// makes no promise that `T` is pinned.
unsafe { &mut self.get_unchecked_mut().lock }
}

fn queue(self: Pin<&mut Self>) -> Pin<&mut WaitQueue> {
// SAFETY: `queue` is structurally pinned: a pinned `WaitVariable`
// pins it, and it is never moved out of it.
unsafe { self.map_unchecked_mut(|this| &mut this.queue) }
}

/// Creates a mutex-protected `WaitVariable` on the heap, with its queue's
/// list initialized. Initialization makes the list self-referential and
/// happens before pinning: only the `Box` pointer is moved into the
/// `Pin`, the heap allocation itself never moves.
pub fn new(value: T) -> Pin<Box<SpinMutex<WaitVariable<T>>>> {
// SAFETY: `init` is called below, before the queue is otherwise used
// or dropped.
let queue = unsafe { WaitQueue::new() };
let result = Box::new(SpinMutex::new(WaitVariable { queue, lock: value }));
result.lock().queue.inner.init();
Box::into_pin(result)
}
}

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

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

impl Default for WaitQueue {
fn default() -> Self {
Self::new()
}
}

impl<'a, T> Deref for WaitGuard<'a, T> {
type Target = SpinMutexGuard<'a, WaitVariable<T>>;
type Target = Pin<SpinMutexGuard<'a, WaitVariable<T>>>;

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

impl WaitQueue {
pub const fn new() -> Self {
WaitQueue { inner: UnsafeList::new() }
/// Creates a new queue.
///
/// # Safety
///
/// The caller must initialize the queue's list (`UnsafeList::init`)
/// before any other use of the queue, including dropping it.
/// `WaitVariable::new`, the sole constructor of the containing
/// structure, does this.
pub const unsafe fn new() -> Self {
// SAFETY: the caller upholds `UnsafeList::new`'s contract (see this
// function's safety requirements).
WaitQueue { inner: unsafe { UnsafeList::new() } }
}

fn inner(self: Pin<&mut Self>) -> Pin<&mut UnsafeList<SpinMutex<WaitEntry>>> {
// SAFETY: `inner` is structurally pinned: a pinned `WaitQueue` pins
// it, and it is never moved out of it.
unsafe { self.map_unchecked_mut(|this| &mut this.inner) }
}

/// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
/// until a wakeup event.
///
/// This function does not return until this thread has been awoken. When `before_wait` panics,
/// this function will abort.
pub fn wait<T, F: FnOnce()>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>, before_wait: F) {
pub fn wait<T, F: FnOnce()>(
mut guard: Pin<SpinMutexGuard<'_, WaitVariable<T>>>,
before_wait: F,
) {
// very unsafe: check requirements of UnsafeList::push
unsafe {
let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry {
tcs: thread::current(),
wake: false,
}));
let entry = guard.queue.inner.push(&mut entry);
let entry = guard.as_mut().queue().inner().push(&mut entry);
drop(guard);
if let Err(_e) = panic::catch_unwind(AssertUnwindSafe(|| before_wait())) {
rtabort!("Panic before wait on wakeup event")
Expand All @@ -155,7 +206,7 @@ impl WaitQueue {
/// If not, it will remove the calling thread from the wait queue.
/// When `before_wait` panics, this function will abort.
pub fn wait_timeout<T, F: FnOnce()>(
lock: &SpinMutex<WaitVariable<T>>,
lock: Pin<&SpinMutex<WaitVariable<T>>>,
timeout: Duration,
before_wait: F,
) -> bool {
Expand All @@ -165,19 +216,19 @@ impl WaitQueue {
tcs: thread::current(),
wake: false,
}));
let entry_lock = lock.lock().queue.inner.push(&mut entry);
let entry_lock = lock.lock_pinned().as_mut().queue().inner().push(&mut entry);
if let Err(_e) = panic::catch_unwind(AssertUnwindSafe(|| before_wait())) {
rtabort!("Panic before wait on wakeup event or timeout")
}
usercalls::wait_timeout(EV_UNPARK, timeout, || entry_lock.lock().wake);
// acquire the wait queue's lock first to avoid deadlock
// and ensure no other function can simultaneously access the list
// (e.g., `notify_one` or `notify_all`)
let mut guard = lock.lock();
let mut guard = lock.lock_pinned();
let success = entry_lock.lock().wake;
if !success {
// nobody is waking us up, so remove our entry from the wait queue.
guard.queue.inner.remove(&mut entry);
guard.as_mut().queue().inner().remove(&mut entry);
}
success
}
Expand All @@ -189,14 +240,14 @@ impl WaitQueue {
/// If a waiter is found, a `WaitGuard` is returned which will notify the
/// waiter when it is dropped.
pub fn notify_one<T>(
mut guard: SpinMutexGuard<'_, WaitVariable<T>>,
) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> {
mut guard: Pin<SpinMutexGuard<'_, WaitVariable<T>>>,
) -> Result<WaitGuard<'_, T>, Pin<SpinMutexGuard<'_, WaitVariable<T>>>> {
// SAFETY: lifetime of the pop() return value is limited to the map
// closure (The closure return value is 'static). The underlying
// stack frame won't be freed until after the lock on the queue is released
// (i.e., `guard` is dropped).
unsafe {
let tcs = guard.queue.inner.pop().map(|entry| -> Tcs {
let tcs = guard.as_mut().queue().inner().pop().map(|entry| -> Tcs {
let mut entry_guard = entry.lock();
entry_guard.wake = true;
entry_guard.tcs
Expand All @@ -216,14 +267,14 @@ impl WaitQueue {
/// If at least one waiter is found, a `WaitGuard` is returned which will
/// notify all waiters when it is dropped.
pub fn notify_all<T>(
mut guard: SpinMutexGuard<'_, WaitVariable<T>>,
) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> {
mut guard: Pin<SpinMutexGuard<'_, WaitVariable<T>>>,
) -> Result<WaitGuard<'_, T>, Pin<SpinMutexGuard<'_, WaitVariable<T>>>> {
// SAFETY: lifetime of the pop() return values are limited to the
// while loop body. The underlying stack frames won't be freed until
// after the lock on the queue is released (i.e., `guard` is dropped).
unsafe {
let mut count = 0;
while let Some(entry) = guard.queue.inner.pop() {
while let Some(entry) = guard.as_mut().queue().inner().pop() {
count += 1;
let mut entry_guard = entry.lock();
entry_guard.wake = true;
Expand Down
Loading
Loading