From 6620e2b219e29ee36cc29991293def2579278eae Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 5 Oct 2024 11:07:01 +0200 Subject: [PATCH 1/9] std: detect stack overflows in TLS destructors on UNIX Fixes #111272. With #127912 merged, we now have all the infrastructure in place to support stack overflow detection in TLS destructors. This was not possible before because the signal stack was freed in the thread main function, thus a SIGSEGV afterwards would immediately crash. And on platforms without native TLS, the guard page address was stored in an allocation freed in a TLS destructor, so would not be available. #127912 introduced the `local_pointer` macro which allows storing a pointer-sized TLS variable without allocation and the `thread_cleanup` runtime function which is called after all other code managed by the Rust runtime. This PR simply moves the signal stack cleanup to the end of `thread_cleanup` and uses `local_pointer` to store every necessary variable. And so, everything run under the Rust runtime is now properly protected against stack overflows. --- library/std/src/rt.rs | 1 + library/std/src/sys/pal/hermit/mod.rs | 2 + library/std/src/sys/pal/sgx/mod.rs | 2 + library/std/src/sys/pal/solid/mod.rs | 2 + library/std/src/sys/pal/teeos/mod.rs | 2 + library/std/src/sys/pal/uefi/mod.rs | 2 + library/std/src/sys/pal/unix/mod.rs | 10 +- .../std/src/sys/pal/unix/stack_overflow.rs | 246 ++++++++---------- library/std/src/sys/pal/unix/thread.rs | 7 +- library/std/src/sys/pal/unsupported/common.rs | 2 + library/std/src/sys/pal/windows/mod.rs | 2 + library/std/src/sys/pal/zkvm/mod.rs | 2 + tests/ui/runtime/out-of-stack.rs | 85 ++++-- 13 files changed, 192 insertions(+), 173 deletions(-) diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 384369b0012b5..50dd2cd6ba7c4 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -117,6 +117,7 @@ pub(crate) fn thread_cleanup() { // print a nice message. panic::catch_unwind(|| { crate::thread::drop_current(); + crate::sys::thread_cleanup(); }) .unwrap_or_else(handle_rt_panic); } diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index d833c9d632c6d..163ff85786682 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -69,6 +69,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { } } +pub fn thread_cleanup() {} + // SAFETY: must be called only once during runtime cleanup. // NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() {} diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index ce8a2fed4bc6b..d0d928936abd2 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -37,6 +37,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { } } +pub fn thread_cleanup() {} + // SAFETY: must be called only once during runtime cleanup. // NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() {} diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index d41042be51844..70099cfaa862e 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -38,6 +38,8 @@ pub mod time; // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} +pub fn thread_cleanup() {} + // SAFETY: must be called only once during runtime cleanup. pub unsafe fn cleanup() {} diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index a9900f55b1926..a4ccc3f236a82 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -45,6 +45,8 @@ pub fn abort_internal() -> ! { // so this should never be called. pub fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {} +pub fn thread_cleanup() {} + // SAFETY: must be called only once during runtime cleanup. // this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() { diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 111bed7a7eb64..66939d1046247 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -76,6 +76,8 @@ pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { } } +pub fn thread_cleanup() {} + /// # SAFETY /// this is not guaranteed to run, for example when the program aborts. /// - must be called only once during runtime cleanup. diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 3cc1cae8d000e..0894e8370edf4 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -55,7 +55,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // behavior. reset_sigpipe(sigpipe); - stack_overflow::init(); + stack_overflow::protect(true); args::init(argc, argv); // Normally, `thread::spawn` will call `Thread::set_name` but since this thread @@ -229,12 +229,14 @@ pub(crate) fn on_broken_pipe_flag_used() -> bool { ON_BROKEN_PIPE_FLAG_USED.load(crate::sync::atomic::Ordering::Relaxed) } -// SAFETY: must be called only once during runtime cleanup. -// NOTE: this is not guaranteed to run, for example when the program aborts. -pub unsafe fn cleanup() { +pub fn thread_cleanup() { stack_overflow::cleanup(); } +// SAFETY: must be called only once during runtime cleanup. +// NOTE: this is not guaranteed to run, for example when the program aborts. +pub unsafe fn cleanup() {} + #[allow(unused_imports)] pub use libc::signal; diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index db5c6bd3a1c32..4c9fffaff0d74 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -1,29 +1,6 @@ #![cfg_attr(test, allow(dead_code))] -pub use self::imp::{cleanup, init}; -use self::imp::{drop_handler, make_handler}; - -pub struct Handler { - data: *mut libc::c_void, -} - -impl Handler { - pub unsafe fn new() -> Handler { - make_handler(false) - } - - fn null() -> Handler { - Handler { data: crate::ptr::null_mut() } - } -} - -impl Drop for Handler { - fn drop(&mut self) { - unsafe { - drop_handler(self.data); - } - } -} +pub use self::imp::{cleanup, protect}; #[cfg(any( target_os = "linux", @@ -45,12 +22,11 @@ mod imp { #[cfg(all(target_os = "linux", target_env = "gnu"))] use libc::{mmap64, mprotect, munmap}; - use super::Handler; - use crate::cell::Cell; use crate::ops::Range; use crate::sync::OnceLock; - use crate::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering}; + use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use crate::sys::pal::unix::os; + use crate::sys::thread_local::{guard, local_pointer}; use crate::{io, mem, ptr, thread}; // We use a TLS variable to store the address of the guard page. While TLS @@ -58,9 +34,11 @@ mod imp { // since we make sure to write to the variable before the signal stack is // installed, thereby ensuring that the variable is always allocated when // the signal handler is called. - thread_local! { - // FIXME: use `Range` once that implements `Copy`. - static GUARD: Cell<(usize, usize)> = const { Cell::new((0, 0)) }; + local_pointer! { + static GUARD_START; + static GUARD_END; + + static SIGALTSTACK; } // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages @@ -93,7 +71,9 @@ mod imp { info: *mut libc::siginfo_t, _data: *mut libc::c_void, ) { - let (start, end) = GUARD.get(); + let start = GUARD_START.get().addr(); + let end = GUARD_END.get().addr(); + // SAFETY: this pointer is provided by the system and will always point to a valid `siginfo_t`. let addr = unsafe { (*info).si_addr().addr() }; @@ -119,51 +99,72 @@ mod imp { } static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); - static MAIN_ALTSTACK: AtomicPtr = AtomicPtr::new(ptr::null_mut()); static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false); + /// Set up stack overflow protection for the current thread + /// /// # Safety - /// Must be called only once + /// May only be called once per thread. #[forbid(unsafe_op_in_unsafe_fn)] - pub unsafe fn init() { - PAGE_SIZE.store(os::page_size(), Ordering::Relaxed); - - // Always write to GUARD to ensure the TLS variable is allocated. - let guard = unsafe { install_main_guard().unwrap_or(0..0) }; - GUARD.set((guard.start, guard.end)); - - // SAFETY: assuming all platforms define struct sigaction as "zero-initializable" - let mut action: sigaction = unsafe { mem::zeroed() }; - for &signal in &[SIGSEGV, SIGBUS] { - // SAFETY: just fetches the current signal handler into action - unsafe { sigaction(signal, ptr::null_mut(), &mut action) }; - // Configure our signal handler if one is not already set. - if action.sa_sigaction == SIG_DFL { - if !NEED_ALTSTACK.load(Ordering::Relaxed) { - // haven't set up our sigaltstack yet - NEED_ALTSTACK.store(true, Ordering::Release); - let handler = unsafe { make_handler(true) }; - MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed); - mem::forget(handler); + pub unsafe fn protect(main_thread: bool) { + if main_thread { + PAGE_SIZE.store(os::page_size(), Ordering::Relaxed); + // Use acquire ordering to observe the page size store above, + // which is propagated by a release store to NEED_ALTSTACK. + } else if !NEED_ALTSTACK.load(Ordering::Acquire) { + return; + } + + let guard = if main_thread { + unsafe { install_main_guard().unwrap_or(0..0) } + } else { + unsafe { current_guard().unwrap_or(0..0) } + }; + + // Always store the guard range to ensure the TLS variables are allocated. + GUARD_START.set(ptr::without_provenance_mut(guard.start)); + GUARD_END.set(ptr::without_provenance_mut(guard.end)); + + if main_thread { + // SAFETY: assuming all platforms define struct sigaction as "zero-initializable" + let mut action: sigaction = unsafe { mem::zeroed() }; + for &signal in &[SIGSEGV, SIGBUS] { + // SAFETY: just fetches the current signal handler into action + unsafe { sigaction(signal, ptr::null_mut(), &mut action) }; + // Configure our signal handler if one is not already set. + if action.sa_sigaction == SIG_DFL { + if !NEED_ALTSTACK.load(Ordering::Relaxed) { + // Set up the signal stack and tell other threads to set + // up their own. This uses a release store to propagate + // the store to PAGE_SIZE above. + NEED_ALTSTACK.store(true, Ordering::Release); + unsafe { setup_sigaltstack() }; + } + + action.sa_flags = SA_SIGINFO | SA_ONSTACK; + action.sa_sigaction = signal_handler as sighandler_t; + // SAFETY: only overriding signals if the default is set + unsafe { sigaction(signal, &action, ptr::null_mut()) }; } - action.sa_flags = SA_SIGINFO | SA_ONSTACK; - action.sa_sigaction = signal_handler as sighandler_t; - // SAFETY: only overriding signals if the default is set - unsafe { sigaction(signal, &action, ptr::null_mut()) }; } + } else { + unsafe { setup_sigaltstack() }; } } /// # Safety - /// Must be called only once + /// Mutates the alternate signal stack #[forbid(unsafe_op_in_unsafe_fn)] - pub unsafe fn cleanup() { - // FIXME: I probably cause more bugs than I'm worth! - // see https://github.com/rust-lang/rust/issues/111272 - unsafe { drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed)) }; - } + unsafe fn setup_sigaltstack() { + // SAFETY: assuming stack_t is zero-initializable + let mut stack = unsafe { mem::zeroed() }; + // SAFETY: reads current stack_t into stack + unsafe { sigaltstack(ptr::null(), &mut stack) }; + // Do not overwrite the stack if one is already set. + if stack.ss_flags & SS_DISABLE == 0 { + return; + } - unsafe fn get_stack() -> libc::stack_t { // OpenBSD requires this flag for stack mapping // otherwise the said mapping will fail as a no-op on most systems // and has a different meaning on FreeBSD @@ -185,82 +186,60 @@ mod imp { let sigstack_size = sigstack_size(); let page_size = PAGE_SIZE.load(Ordering::Relaxed); - let stackp = mmap64( - ptr::null_mut(), - sigstack_size + page_size, - PROT_READ | PROT_WRITE, - flags, - -1, - 0, - ); - if stackp == MAP_FAILED { + let allocation = unsafe { + mmap64(ptr::null_mut(), sigstack_size + page_size, PROT_READ | PROT_WRITE, flags, -1, 0) + }; + if allocation == MAP_FAILED { panic!("failed to allocate an alternative stack: {}", io::Error::last_os_error()); } - let guard_result = libc::mprotect(stackp, page_size, PROT_NONE); + + let guard_result = unsafe { libc::mprotect(allocation, page_size, PROT_NONE) }; if guard_result != 0 { panic!("failed to set up alternative stack guard page: {}", io::Error::last_os_error()); } - let stackp = stackp.add(page_size); - libc::stack_t { ss_sp: stackp, ss_flags: 0, ss_size: sigstack_size } + let stack = libc::stack_t { + // Reserve a guard page at the bottom of the allocation. + ss_sp: unsafe { allocation.add(page_size) }, + ss_flags: 0, + ss_size: sigstack_size, + }; + // SAFETY: We warned our caller this would happen! + unsafe { + sigaltstack(&stack, ptr::null_mut()); + } + + // Ensure that `rt::thread_cleanup` gets called, which will in turn call + // cleanup, where this signal stack will be freed. + guard::enable(); + SIGALTSTACK.set(allocation.cast()); } - /// # Safety - /// Mutates the alternate signal stack - #[forbid(unsafe_op_in_unsafe_fn)] - pub unsafe fn make_handler(main_thread: bool) -> Handler { - if !NEED_ALTSTACK.load(Ordering::Acquire) { - return Handler::null(); + pub fn cleanup() { + let allocation = SIGALTSTACK.get(); + if allocation.is_null() { + return; } - if !main_thread { - // Always write to GUARD to ensure the TLS variable is allocated. - let guard = unsafe { current_guard() }.unwrap_or(0..0); - GUARD.set((guard.start, guard.end)); - } + SIGALTSTACK.set(ptr::null_mut()); - // SAFETY: assuming stack_t is zero-initializable - let mut stack = unsafe { mem::zeroed() }; - // SAFETY: reads current stack_t into stack - unsafe { sigaltstack(ptr::null(), &mut stack) }; - // Configure alternate signal stack, if one is not already set. - if stack.ss_flags & SS_DISABLE != 0 { - // SAFETY: We warned our caller this would happen! - unsafe { - stack = get_stack(); - sigaltstack(&stack, ptr::null_mut()); - } - Handler { data: stack.ss_sp as *mut libc::c_void } - } else { - Handler::null() - } - } + let sigstack_size = sigstack_size(); + let page_size = PAGE_SIZE.load(Ordering::Relaxed); - /// # Safety - /// Must be called - /// - only with our handler or nullptr - /// - only when done with our altstack - /// This disables the alternate signal stack! - #[forbid(unsafe_op_in_unsafe_fn)] - pub unsafe fn drop_handler(data: *mut libc::c_void) { - if !data.is_null() { - let sigstack_size = sigstack_size(); - let page_size = PAGE_SIZE.load(Ordering::Relaxed); - let disabling_stack = libc::stack_t { - ss_sp: ptr::null_mut(), - ss_flags: SS_DISABLE, - // Workaround for bug in macOS implementation of sigaltstack - // UNIX2003 which returns ENOMEM when disabling a stack while - // passing ss_size smaller than MINSIGSTKSZ. According to POSIX - // both ss_sp and ss_size should be ignored in this case. - ss_size: sigstack_size, - }; - // SAFETY: we warned the caller this disables the alternate signal stack! - unsafe { sigaltstack(&disabling_stack, ptr::null_mut()) }; - // SAFETY: We know from `get_stackp` that the alternate stack we installed is part of - // a mapping that started one page earlier, so walk back a page and unmap from there. - unsafe { munmap(data.sub(page_size), sigstack_size + page_size) }; - } + let disabling_stack = libc::stack_t { + ss_sp: ptr::null_mut(), + ss_flags: SS_DISABLE, + // Workaround for bug in macOS implementation of sigaltstack + // UNIX2003 which returns ENOMEM when disabling a stack while + // passing ss_size smaller than MINSIGSTKSZ. According to POSIX + // both ss_sp and ss_size should be ignored in this case. + ss_size: sigstack_size, + }; + unsafe { sigaltstack(&disabling_stack, ptr::null_mut()) }; + + // SAFETY: we created this mapping in `setup_sigaltstack` above with + // this exact size. + unsafe { munmap(allocation.cast(), sigstack_size + page_size) }; } /// Modern kernels on modern hardware can have dynamic signal stack sizes. @@ -577,13 +556,6 @@ mod imp { target_os = "illumos", )))] mod imp { - pub unsafe fn init() {} - - pub unsafe fn cleanup() {} - - pub unsafe fn make_handler(_main_thread: bool) -> super::Handler { - super::Handler::null() - } - - pub unsafe fn drop_handler(_data: *mut libc::c_void) {} + pub unsafe fn protect(_main_thread: bool) {} + pub fn cleanup() {} } diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index f657f82e6e368..1f7d2f1ac94ad 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -99,10 +99,9 @@ impl Thread { extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { unsafe { - // Next, set up our stack overflow handler which may get triggered if we run - // out of stack. - let _handler = stack_overflow::Handler::new(); - // Finally, let's run some code. + // Protect this thread against stack overflows + stack_overflow::protect(false); + // and run its main function. Box::from_raw(main as *mut Box)(); } ptr::null_mut() diff --git a/library/std/src/sys/pal/unsupported/common.rs b/library/std/src/sys/pal/unsupported/common.rs index 34a766683830d..ec046e226659a 100644 --- a/library/std/src/sys/pal/unsupported/common.rs +++ b/library/std/src/sys/pal/unsupported/common.rs @@ -4,6 +4,8 @@ use crate::io as std_io; // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} +pub fn thread_cleanup() {} + // SAFETY: must be called only once during runtime cleanup. // NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() {} diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 4282dbb54934f..c58f3e868773a 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -60,6 +60,8 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) { } } +pub fn thread_cleanup() {} + // SAFETY: must be called only once during runtime cleanup. // NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() { diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index 6ea057720296d..618fb2e3a4120 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -37,6 +37,8 @@ use crate::io as std_io; // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} +pub fn thread_cleanup() {} + // SAFETY: must be called only once during runtime cleanup. // NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() {} diff --git a/tests/ui/runtime/out-of-stack.rs b/tests/ui/runtime/out-of-stack.rs index c5300635ad924..05f2aa44fb709 100644 --- a/tests/ui/runtime/out-of-stack.rs +++ b/tests/ui/runtime/out-of-stack.rs @@ -21,6 +21,7 @@ use std::env; use std::hint::black_box; use std::process::Command; use std::thread; +use std::cell::Cell; fn silent_recurse() { let buf = [0u8; 1000]; @@ -34,13 +35,34 @@ fn loud_recurse() { black_box(()); // don't optimize this into a tail call. please. } +fn in_tls_destructor(f: impl FnOnce() + 'static) { + struct RunOnDrop(Cell>>); + impl Drop for RunOnDrop { + fn drop(&mut self) { + self.0.take().unwrap()() + } + } + + thread_local! { + static RUN: RunOnDrop = RunOnDrop(Cell::new(None)); + } + + RUN.with(|run| run.0.set(Some(Box::new(f)))); +} + #[cfg(unix)] fn check_status(status: std::process::ExitStatus) { use std::os::unix::process::ExitStatusExt; assert!(!status.success()); + #[cfg(not(target_vendor = "apple"))] assert_eq!(status.signal(), Some(libc::SIGABRT)); + + // Apple's libc has a bug where calling abort in a TLS destructor on a thread + // other than the main thread results in a SIGTRAP instead of a SIGABRT. + #[cfg(target_vendor = "apple")] + assert!(matches!(status.signal(), Some(libc::SIGABRT | libc::SIGTRAP))); } #[cfg(not(unix))] @@ -49,40 +71,47 @@ fn check_status(status: std::process::ExitStatus) assert!(!status.success()); } - fn main() { let args: Vec = env::args().collect(); - if args.len() > 1 && args[1] == "silent" { - silent_recurse(); - } else if args.len() > 1 && args[1] == "loud" { - loud_recurse(); - } else if args.len() > 1 && args[1] == "silent-thread" { - thread::spawn(silent_recurse).join(); - } else if args.len() > 1 && args[1] == "loud-thread" { - thread::spawn(loud_recurse).join(); - } else { - let mut modes = vec![ - "silent-thread", - "loud-thread", - ]; - - // On linux it looks like the main thread can sometimes grow its stack - // basically without bounds, so we only test the child thread cases - // there. - if !cfg!(target_os = "linux") { - modes.push("silent"); - modes.push("loud"); + match args.get(1).map(String::as_str) { + Some("silent") => silent_recurse(), + Some("loud") => loud_recurse(), + Some("silent-thread") => thread::spawn(silent_recurse).join().unwrap(), + Some("loud-thread") => thread::spawn(loud_recurse).join().unwrap(), + Some("silent-tls") => in_tls_destructor(silent_recurse), + Some("loud-tls") => in_tls_destructor(loud_recurse), + Some("silent-thread-tls") => { + thread::spawn(|| in_tls_destructor(silent_recurse)).join().unwrap(); } - for mode in modes { - println!("testing: {}", mode); + Some("loud-thread-tls") => { + thread::spawn(|| in_tls_destructor(loud_recurse)).join().unwrap(); + } + _ => { + let mut modes = vec![ + "silent-thread", + "loud-thread", + "silent-thread-tls", + "loud-thread-tls", + ]; + + // On linux it looks like the main thread can sometimes grow its stack + // basically without bounds, so we only test the child thread cases + // there. + if !cfg!(target_os = "linux") { + modes.extend(["silent", "loud", "silent-tls", "loud-tls"]); + } + + for mode in modes { + println!("testing: {}", mode); - let silent = Command::new(&args[0]).arg(mode).output().unwrap(); + let silent = Command::new(&args[0]).arg(mode).output().unwrap(); - check_status(silent.status); + let error = String::from_utf8_lossy(&silent.stderr); + assert!(error.contains("has overflowed its stack"), + "missing overflow message: {}", error); - let error = String::from_utf8_lossy(&silent.stderr); - assert!(error.contains("has overflowed its stack"), - "missing overflow message: {}", error); + check_status(silent.status); + } } } } From fdb636e88b48ef8b3166d71ddca7332b625334c5 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 20 Jan 2025 13:07:27 -0600 Subject: [PATCH 2/9] Add tests for windows-gnu split-debuginfo options --- .../windows_gnu_split_debuginfo_off.rs | 29 +++++++++++++++++++ ...u_split_debuginfo_packed.aarch64_gl.stderr | 4 +++ ...s_gnu_split_debuginfo_packed.i686_g.stderr | 4 +++ ..._gnu_split_debuginfo_packed.i686_gl.stderr | 4 +++ ...u_split_debuginfo_packed.i686_uwp_g.stderr | 4 +++ .../windows_gnu_split_debuginfo_packed.rs | 29 +++++++++++++++++++ ...gnu_split_debuginfo_packed.x86_64_g.stderr | 4 +++ ...nu_split_debuginfo_packed.x86_64_gl.stderr | 4 +++ ...split_debuginfo_packed.x86_64_uwp_g.stderr | 4 +++ ...split_debuginfo_unpacked.aarch64_gl.stderr | 4 +++ ...gnu_split_debuginfo_unpacked.i686_g.stderr | 4 +++ ...nu_split_debuginfo_unpacked.i686_gl.stderr | 4 +++ ...split_debuginfo_unpacked.i686_uwp_g.stderr | 4 +++ .../windows_gnu_split_debuginfo_unpacked.rs | 29 +++++++++++++++++++ ...u_split_debuginfo_unpacked.x86_64_g.stderr | 4 +++ ..._split_debuginfo_unpacked.x86_64_gl.stderr | 4 +++ ...lit_debuginfo_unpacked.x86_64_uwp_g.stderr | 4 +++ 17 files changed, 143 insertions(+) create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.aarch64_gl.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_g.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_gl.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_uwp_g.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_g.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_gl.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_uwp_g.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.aarch64_gl.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_g.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_gl.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_uwp_g.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_g.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_gl.stderr create mode 100644 tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_uwp_g.stderr diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs b/tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs new file mode 100644 index 0000000000000..3a8d9c998cf74 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs @@ -0,0 +1,29 @@ +//@ revisions: aarch64_gl i686_g i686_gl i686_uwp_g x86_64_g x86_64_gl x86_64_uwp_g +//@ compile-flags: --crate-type cdylib -Csplit-debuginfo=off +//@ check-pass + +//@[aarch64_gl] compile-flags: --target aarch64-pc-windows-gnullvm +//@[aarch64_gl] needs-llvm-components: aarch64 + +//@[i686_g] compile-flags: --target i686-pc-windows-gnu +//@[i686_g] needs-llvm-components: x86 + +//@[i686_gl] compile-flags: --target i686-pc-windows-gnullvm +//@[i686_gl] needs-llvm-components: x86 + +//@[i686_uwp_g] compile-flags: --target i686-uwp-windows-gnu +//@[i686_uwp_g] needs-llvm-components: x86 + +//@[x86_64_g] compile-flags: --target x86_64-pc-windows-gnu +//@[x86_64_g] needs-llvm-components: x86 + +//@[x86_64_gl] compile-flags: --target x86_64-pc-windows-gnullvm +//@[x86_64_gl] needs-llvm-components: x86 + +//@[x86_64_uwp_g] compile-flags: --target x86_64-uwp-windows-gnu +//@[x86_64_uwp_g] needs-llvm-components: x86 + +#![feature(no_core)] + +#![no_core] +#![no_std] diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.aarch64_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.aarch64_gl.stderr new file mode 100644 index 0000000000000..f3465e64976ea --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.aarch64_gl.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_g.stderr new file mode 100644 index 0000000000000..f3465e64976ea --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_gl.stderr new file mode 100644 index 0000000000000..f3465e64976ea --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_gl.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_uwp_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_uwp_g.stderr new file mode 100644 index 0000000000000..f3465e64976ea --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_uwp_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs new file mode 100644 index 0000000000000..896bbac7d8e1e --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs @@ -0,0 +1,29 @@ +//@ revisions: aarch64_gl i686_g i686_gl i686_uwp_g x86_64_g x86_64_gl x86_64_uwp_g +//@ compile-flags: --crate-type cdylib -Csplit-debuginfo=packed +//@ error-pattern: error: `-Csplit-debuginfo=packed` is unstable on this platform + +//@[aarch64_gl] compile-flags: --target aarch64-pc-windows-gnullvm +//@[aarch64_gl] needs-llvm-components: aarch64 + +//@[i686_g] compile-flags: --target i686-pc-windows-gnu +//@[i686_g] needs-llvm-components: x86 + +//@[i686_gl] compile-flags: --target i686-pc-windows-gnullvm +//@[i686_gl] needs-llvm-components: x86 + +//@[i686_uwp_g] compile-flags: --target i686-uwp-windows-gnu +//@[i686_uwp_g] needs-llvm-components: x86 + +//@[x86_64_g] compile-flags: --target x86_64-pc-windows-gnu +//@[x86_64_g] needs-llvm-components: x86 + +//@[x86_64_gl] compile-flags: --target x86_64-pc-windows-gnullvm +//@[x86_64_gl] needs-llvm-components: x86 + +//@[x86_64_uwp_g] compile-flags: --target x86_64-uwp-windows-gnu +//@[x86_64_uwp_g] needs-llvm-components: x86 + +#![feature(no_core)] + +#![no_core] +#![no_std] diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_g.stderr new file mode 100644 index 0000000000000..f3465e64976ea --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_gl.stderr new file mode 100644 index 0000000000000..f3465e64976ea --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_gl.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_uwp_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_uwp_g.stderr new file mode 100644 index 0000000000000..f3465e64976ea --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_uwp_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.aarch64_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.aarch64_gl.stderr new file mode 100644 index 0000000000000..0964e21b13bc1 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.aarch64_gl.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_g.stderr new file mode 100644 index 0000000000000..0964e21b13bc1 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_gl.stderr new file mode 100644 index 0000000000000..0964e21b13bc1 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_gl.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_uwp_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_uwp_g.stderr new file mode 100644 index 0000000000000..0964e21b13bc1 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_uwp_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs new file mode 100644 index 0000000000000..54a88c9121734 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs @@ -0,0 +1,29 @@ +//@ revisions: aarch64_gl i686_g i686_gl i686_uwp_g x86_64_g x86_64_gl x86_64_uwp_g +//@ compile-flags: --crate-type cdylib -Csplit-debuginfo=unpacked +//@ error-pattern: error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +//@[aarch64_gl] compile-flags: --target aarch64-pc-windows-gnullvm +//@[aarch64_gl] needs-llvm-components: aarch64 + +//@[i686_g] compile-flags: --target i686-pc-windows-gnu +//@[i686_g] needs-llvm-components: x86 + +//@[i686_gl] compile-flags: --target i686-pc-windows-gnullvm +//@[i686_gl] needs-llvm-components: x86 + +//@[i686_uwp_g] compile-flags: --target i686-uwp-windows-gnu +//@[i686_uwp_g] needs-llvm-components: x86 + +//@[x86_64_g] compile-flags: --target x86_64-pc-windows-gnu +//@[x86_64_g] needs-llvm-components: x86 + +//@[x86_64_gl] compile-flags: --target x86_64-pc-windows-gnullvm +//@[x86_64_gl] needs-llvm-components: x86 + +//@[x86_64_uwp_g] compile-flags: --target x86_64-uwp-windows-gnu +//@[x86_64_uwp_g] needs-llvm-components: x86 + +#![feature(no_core)] + +#![no_core] +#![no_std] diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_g.stderr new file mode 100644 index 0000000000000..0964e21b13bc1 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_gl.stderr new file mode 100644 index 0000000000000..0964e21b13bc1 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_gl.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_uwp_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_uwp_g.stderr new file mode 100644 index 0000000000000..0964e21b13bc1 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_uwp_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + From 0b24fc99368ebfe9fa58e9b70785dc30ad2049bc Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 20 Jan 2025 14:02:35 -0600 Subject: [PATCH 3/9] Set `DebuginfoKind::Dwarf` for `*-windows-gnu` and `*-windows-gnullvm` These targets have always generated DWARF debuginfo and not CodeView/PDB debuginfo like the MSVC Windows targets. Correct their target definitions to reflect this. The newly added tests for the various combinations of `*-windows-gnu*` targets and `-Csplit-debuginfo` show that this does not change any stable behavior. --- compiler/rustc_target/src/spec/base/windows_gnu.rs | 2 +- compiler/rustc_target/src/spec/base/windows_gnullvm.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs index e975102e2389a..d8b6ae8cf324e 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnu.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs @@ -97,9 +97,9 @@ pub(crate) fn opts() -> TargetOptions { emit_debug_gdb_scripts: false, requires_uwtable: true, eh_frame_header: false, + debuginfo_kind: DebuginfoKind::Dwarf, // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to // output DWO, despite using DWARF, doesn't use ELF.. - debuginfo_kind: DebuginfoKind::Pdb, supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..Default::default() } diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs index 4f370ec8bd032..86e52117dbf75 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs @@ -44,9 +44,9 @@ pub(crate) fn opts() -> TargetOptions { has_thread_local: true, crt_static_allows_dylibs: true, crt_static_respected: true, + debuginfo_kind: DebuginfoKind::Dwarf, // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to // output DWO, despite using DWARF, doesn't use ELF.. - debuginfo_kind: DebuginfoKind::Pdb, supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..Default::default() } From eb3b3fe01c5331967ad8d24584c00d0fb9161121 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 22 Jan 2025 14:42:33 +0100 Subject: [PATCH 4/9] ci: use 8 core arm runner for dist-aarch64-linux --- src/ci/github-actions/jobs.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index c5b33a45db790..b86727c2bf607 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -50,6 +50,8 @@ runners: - &job-aarch64-linux os: ubuntu-22.04-arm + - &job-aarch64-linux-8c + os: ubuntu-22.04-arm64-8core-32gb envs: env-x86_64-apple-tests: &env-x86_64-apple-tests SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact @@ -142,7 +144,7 @@ auto: - name: dist-aarch64-linux env: CODEGEN_BACKENDS: llvm,cranelift - <<: *job-aarch64-linux + <<: *job-aarch64-linux-8c - name: dist-android <<: *job-linux-4c From f0dfda124d436f01c57f70f26efc22d35ef3a9fa Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 22 Jan 2025 16:50:15 +0300 Subject: [PATCH 5/9] fix outdated file path ref in llvm This was added years ago and is outdated today. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/llvm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index cf55fff4078ac..3cf25373b8963 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1338,7 +1338,7 @@ impl Step for CrtBeginEnd { .file(crtbegin_src) .file(crtend_src); - // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt + // Those flags are defined in src/llvm-project/compiler-rt/lib/builtins/CMakeLists.txt // Currently only consumer of those objects is musl, which use .init_array/.fini_array // instead of .ctors/.dtors cfg.flag("-std=c11") From bae2a2f3b56b4540bf21e2aab888a945f38e1fe3 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 22 Jan 2025 18:36:33 +0300 Subject: [PATCH 6/9] Remove erroneous `unsafe` in `BTreeSet::upper_bound_mut` --- library/alloc/src/collections/btree/set.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 9660023d6945e..041f80c1f2c52 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1442,20 +1442,20 @@ impl BTreeSet { /// /// let mut set = BTreeSet::from([1, 2, 3, 4]); /// - /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Included(&3)) }; + /// let mut cursor = set.upper_bound_mut(Bound::Included(&3)); /// assert_eq!(cursor.peek_prev(), Some(&3)); /// assert_eq!(cursor.peek_next(), Some(&4)); /// - /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Excluded(&3)) }; + /// let mut cursor = set.upper_bound_mut(Bound::Excluded(&3)); /// assert_eq!(cursor.peek_prev(), Some(&2)); /// assert_eq!(cursor.peek_next(), Some(&3)); /// - /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Unbounded) }; + /// let mut cursor = set.upper_bound_mut(Bound::Unbounded); /// assert_eq!(cursor.peek_prev(), Some(&4)); /// assert_eq!(cursor.peek_next(), None); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub unsafe fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> + pub fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> where T: Borrow + Ord, Q: Ord, From 53578bdd194d41ac24fd4a5474601e3af2cb029d Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 22 Jan 2025 16:46:40 +0100 Subject: [PATCH 7/9] remove implied end of slice --- compiler/rustc_parse_format/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 9eb335cb34cc2..9a3e79c16b4df 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -545,7 +545,7 @@ impl<'a> Parser<'a> { } } } - &self.input[start..self.input.len()] + &self.input[start..] } /// Parses an `Argument` structure, or what's contained within braces inside the format string. From 72fa87445670046d64222980ec9988bf6975fc56 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 25 Dec 2024 03:10:54 +0000 Subject: [PATCH 8/9] Don't ICE in coerce when autoderef fails to structurally normalize non-WF type in new solver --- compiler/rustc_hir_typeck/src/coercion.rs | 14 +++++-- .../next-solver/non-wf-in-coerce-pointers.rs | 17 ++++++++ .../non-wf-in-coerce-pointers.stderr | 39 +++++++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs create mode 100644 tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6945dbc321697..720f51c0be6f7 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -461,9 +461,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // to the target type), since that should be the least // confusing. let Some(InferOk { value: ty, mut obligations }) = found else { - let err = first_error.expect("coerce_borrowed_pointer had no error"); - debug!("coerce_borrowed_pointer: failed with err = {:?}", err); - return Err(err); + if let Some(first_error) = first_error { + debug!("coerce_borrowed_pointer: failed with err = {:?}", first_error); + return Err(first_error); + } else { + // This may happen in the new trait solver since autoderef requires + // the pointee to be structurally normalizable, or else it'll just bail. + // So when we have a type like `&`, then we get no + // autoderef steps (even though there should be at least one). That means + // we get no type mismatches, since the loop above just exits early. + return Err(TypeError::Mismatch); + } }; if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 { diff --git a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs new file mode 100644 index 0000000000000..d05def2cb757d --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Znext-solver + +trait Wf { + type Assoc; +} + +struct S { + f: &'static <() as Wf>::Assoc, + //~^ ERROR the trait bound `(): Wf` is not satisfied +} + +fn main() { + let x: S = todo!(); + let y: &() = x.f; + //~^ ERROR mismatched types + //~| ERROR the trait bound `(): Wf` is not satisfied +} diff --git a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr new file mode 100644 index 0000000000000..32a7766a638da --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr @@ -0,0 +1,39 @@ +error[E0277]: the trait bound `(): Wf` is not satisfied + --> $DIR/non-wf-in-coerce-pointers.rs:8:17 + | +LL | f: &'static <() as Wf>::Assoc, + | ^^^^^^^^^^^^^^^^^ the trait `Wf` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/non-wf-in-coerce-pointers.rs:3:1 + | +LL | trait Wf { + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/non-wf-in-coerce-pointers.rs:14:18 + | +LL | let y: &() = x.f; + | --- ^^^ types differ + | | + | expected due to this + | + = note: expected reference `&()` + found reference `&'static <() as Wf>::Assoc` + +error[E0277]: the trait bound `(): Wf` is not satisfied + --> $DIR/non-wf-in-coerce-pointers.rs:14:18 + | +LL | let y: &() = x.f; + | ^^^ the trait `Wf` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/non-wf-in-coerce-pointers.rs:3:1 + | +LL | trait Wf { + | ^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. From 0149c0fdd8ca67ab0e6c1bca0fac0ad6eaa8c002 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Wed, 22 Jan 2025 20:01:17 +0000 Subject: [PATCH 9/9] rustdoc-json-types: Finalize dyn compatibility renaming --- src/rustdoc-json-types/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 5a99977ded5eb..916f0ab3cc85b 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -1099,8 +1099,7 @@ pub struct Trait { pub is_auto: bool, /// Whether the trait is marked as `unsafe`. pub is_unsafe: bool, - // FIXME(dyn_compat_renaming): Update the URL once the Reference is updated and hits stable. - /// Whether the trait is [dyn compatible](https://doc.rust-lang.org/reference/items/traits.html#object-safety)[^1]. + /// Whether the trait is [dyn compatible](https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility)[^1]. /// /// [^1]: Formerly known as "object safe". pub is_dyn_compatible: bool,