about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/sys/pal/unix/net.rs29
-rw-r--r--library/std/src/sys/personality/gcc.rs321
2 files changed, 199 insertions, 151 deletions
diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs
index bedb06043a7..eafde51c608 100644
--- a/library/std/src/sys/pal/unix/net.rs
+++ b/library/std/src/sys/pal/unix/net.rs
@@ -214,16 +214,25 @@ impl Socket {
                 }
                 0 => {}
                 _ => {
-                    // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
-                    // for POLLHUP rather than read readiness
-                    if pollfd.revents & libc::POLLHUP != 0 {
-                        let e = self.take_error()?.unwrap_or_else(|| {
-                            io::const_io_error!(
-                                io::ErrorKind::Uncategorized,
-                                "no error set after POLLHUP",
-                            )
-                        });
-                        return Err(e);
+                    if cfg!(target_os = "vxworks") {
+                        // VxWorks poll does not return  POLLHUP or POLLERR in revents. Check if the
+                        // connnection actually succeeded and return ok only when the socket is
+                        // ready and no errors were found.
+                        if let Some(e) = self.take_error()? {
+                            return Err(e);
+                        }
+                    } else {
+                        // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
+                        // for POLLHUP or POLLERR rather than read readiness
+                        if pollfd.revents & (libc::POLLHUP | libc::POLLERR) != 0 {
+                            let e = self.take_error()?.unwrap_or_else(|| {
+                                io::const_io_error!(
+                                    io::ErrorKind::Uncategorized,
+                                    "no error set after POLLHUP",
+                                )
+                            });
+                            return Err(e);
+                        }
                     }
 
                     return Ok(());
diff --git a/library/std/src/sys/personality/gcc.rs b/library/std/src/sys/personality/gcc.rs
index 0dc53550ca9..1fb85a10179 100644
--- a/library/std/src/sys/personality/gcc.rs
+++ b/library/std/src/sys/personality/gcc.rs
@@ -35,6 +35,7 @@
 //!
 //! Once stack has been unwound down to the handler frame level, unwinding stops
 //! and the last personality routine transfers control to the catch block.
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 use super::dwarf::eh::{self, EHAction, EHContext};
 use crate::ffi::c_int;
@@ -92,107 +93,116 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1
 // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
 
 cfg_if::cfg_if! {
-    if #[cfg(all(not(all(target_vendor = "apple", not(target_os = "watchos"))), target_arch = "arm", not(target_os = "netbsd")))] {
-        // ARM EHABI personality routine.
-        // https://web.archive.org/web/20190728160938/https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
-        //
-        // Apple 32-bit ARM (but not watchOS) uses the default routine instead
-        // since it uses SjLj unwinding.
+    if #[cfg(all(
+            target_arch = "arm",
+            not(all(target_vendor = "apple", not(target_os = "watchos"))),
+            not(target_os = "netbsd"),
+        ))] {
+        /// personality fn called by [ARM EHABI][armeabi-eh]
+        ///
+        /// Apple 32-bit ARM (but not watchOS) uses the default routine instead
+        /// since it uses "setjmp-longjmp" unwinding.
+        ///
+        /// [armeabi-eh]: https://web.archive.org/web/20190728160938/https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
         #[lang = "eh_personality"]
         unsafe extern "C" fn rust_eh_personality(
             state: uw::_Unwind_State,
             exception_object: *mut uw::_Unwind_Exception,
             context: *mut uw::_Unwind_Context,
         ) -> uw::_Unwind_Reason_Code {
-            let state = state as c_int;
-            let action = state & uw::_US_ACTION_MASK as c_int;
-            let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int {
-                // Backtraces on ARM will call the personality routine with
-                // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
-                // we want to continue unwinding the stack, otherwise all our backtraces
-                // would end at __rust_try
-                if state & uw::_US_FORCE_UNWIND as c_int != 0 {
+            unsafe {
+                let state = state as c_int;
+                let action = state & uw::_US_ACTION_MASK as c_int;
+                let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int {
+                    // Backtraces on ARM will call the personality routine with
+                    // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
+                    // we want to continue unwinding the stack, otherwise all our backtraces
+                    // would end at __rust_try
+                    if state & uw::_US_FORCE_UNWIND as c_int != 0 {
+                        return continue_unwind(exception_object, context);
+                    }
+                    true
+                } else if action == uw::_US_UNWIND_FRAME_STARTING as c_int {
+                    false
+                } else if action == uw::_US_UNWIND_FRAME_RESUME as c_int {
                     return continue_unwind(exception_object, context);
-                }
-                true
-            } else if action == uw::_US_UNWIND_FRAME_STARTING as c_int {
-                false
-            } else if action == uw::_US_UNWIND_FRAME_RESUME as c_int {
-                return continue_unwind(exception_object, context);
-            } else {
-                return uw::_URC_FAILURE;
-            };
+                } else {
+                    return uw::_URC_FAILURE;
+                };
 
-            // The DWARF unwinder assumes that _Unwind_Context holds things like the function
-            // and LSDA pointers, however ARM EHABI places them into the exception object.
-            // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
-            // take only the context pointer, GCC personality routines stash a pointer to
-            // exception_object in the context, using location reserved for ARM's
-            // "scratch register" (r12).
-            uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr);
-            // ...A more principled approach would be to provide the full definition of ARM's
-            // _Unwind_Context in our libunwind bindings and fetch the required data from there
-            // directly, bypassing DWARF compatibility functions.
+                // The DWARF unwinder assumes that _Unwind_Context holds things like the function
+                // and LSDA pointers, however ARM EHABI places them into the exception object.
+                // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
+                // take only the context pointer, GCC personality routines stash a pointer to
+                // exception_object in the context, using location reserved for ARM's
+                // "scratch register" (r12).
+                uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr);
+                // ...A more principled approach would be to provide the full definition of ARM's
+                // _Unwind_Context in our libunwind bindings and fetch the required data from there
+                // directly, bypassing DWARF compatibility functions.
 
-            let eh_action = match find_eh_action(context) {
-                Ok(action) => action,
-                Err(_) => return uw::_URC_FAILURE,
-            };
-            if search_phase {
-                match eh_action {
-                    EHAction::None | EHAction::Cleanup(_) => {
-                        return continue_unwind(exception_object, context);
-                    }
-                    EHAction::Catch(_) | EHAction::Filter(_) => {
-                        // EHABI requires the personality routine to update the
-                        // SP value in the barrier cache of the exception object.
-                        (*exception_object).private[5] =
-                            uw::_Unwind_GetGR(context, uw::UNWIND_SP_REG);
-                        return uw::_URC_HANDLER_FOUND;
+                let eh_action = match find_eh_action(context) {
+                    Ok(action) => action,
+                    Err(_) => return uw::_URC_FAILURE,
+                };
+                if search_phase {
+                    match eh_action {
+                        EHAction::None | EHAction::Cleanup(_) => {
+                            return continue_unwind(exception_object, context);
+                        }
+                        EHAction::Catch(_) | EHAction::Filter(_) => {
+                            // EHABI requires the personality routine to update the
+                            // SP value in the barrier cache of the exception object.
+                            (*exception_object).private[5] =
+                                uw::_Unwind_GetGR(context, uw::UNWIND_SP_REG);
+                            return uw::_URC_HANDLER_FOUND;
+                        }
+                        EHAction::Terminate => return uw::_URC_FAILURE,
                     }
-                    EHAction::Terminate => return uw::_URC_FAILURE,
-                }
-            } else {
-                match eh_action {
-                    EHAction::None => return continue_unwind(exception_object, context),
-                    EHAction::Filter(_) if state & uw::_US_FORCE_UNWIND as c_int != 0 => return continue_unwind(exception_object, context),
-                    EHAction::Cleanup(lpad) | EHAction::Catch(lpad) | EHAction::Filter(lpad) => {
-                        uw::_Unwind_SetGR(
-                            context,
-                            UNWIND_DATA_REG.0,
-                            exception_object as uw::_Unwind_Ptr,
-                        );
-                        uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, core::ptr::null());
-                        uw::_Unwind_SetIP(context, lpad);
-                        return uw::_URC_INSTALL_CONTEXT;
+                } else {
+                    match eh_action {
+                        EHAction::None => return continue_unwind(exception_object, context),
+                        EHAction::Filter(_) if state & uw::_US_FORCE_UNWIND as c_int != 0 => return continue_unwind(exception_object, context),
+                        EHAction::Cleanup(lpad) | EHAction::Catch(lpad) | EHAction::Filter(lpad) => {
+                            uw::_Unwind_SetGR(
+                                context,
+                                UNWIND_DATA_REG.0,
+                                exception_object as uw::_Unwind_Ptr,
+                            );
+                            uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, core::ptr::null());
+                            uw::_Unwind_SetIP(context, lpad);
+                            return uw::_URC_INSTALL_CONTEXT;
+                        }
+                        EHAction::Terminate => return uw::_URC_FAILURE,
                     }
-                    EHAction::Terminate => return uw::_URC_FAILURE,
                 }
-            }
 
-            // On ARM EHABI the personality routine is responsible for actually
-            // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
-            unsafe fn continue_unwind(
-                exception_object: *mut uw::_Unwind_Exception,
-                context: *mut uw::_Unwind_Context,
-            ) -> uw::_Unwind_Reason_Code {
-                if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON {
-                    uw::_URC_CONTINUE_UNWIND
-                } else {
-                    uw::_URC_FAILURE
-                }
-            }
-            // defined in libgcc
-            extern "C" {
-                fn __gnu_unwind_frame(
+                // On ARM EHABI the personality routine is responsible for actually
+                // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
+                unsafe fn continue_unwind(
                     exception_object: *mut uw::_Unwind_Exception,
                     context: *mut uw::_Unwind_Context,
-                ) -> uw::_Unwind_Reason_Code;
+                ) -> uw::_Unwind_Reason_Code {
+                    unsafe {
+                        if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON {
+                            uw::_URC_CONTINUE_UNWIND
+                        } else {
+                            uw::_URC_FAILURE
+                        }
+                    }
+                }
+                // defined in libgcc
+                extern "C" {
+                    fn __gnu_unwind_frame(
+                        exception_object: *mut uw::_Unwind_Exception,
+                        context: *mut uw::_Unwind_Context,
+                    ) -> uw::_Unwind_Reason_Code;
+                }
             }
         }
     } else {
-        // Default personality routine, which is used directly on most targets
-        // and indirectly on Windows x86_64 via SEH.
+        /// Default personality routine, which is used directly on most targets
+        /// and indirectly on Windows x86_64 and AArch64 via SEH.
         unsafe extern "C" fn rust_eh_personality_impl(
             version: c_int,
             actions: uw::_Unwind_Action,
@@ -200,43 +210,49 @@ cfg_if::cfg_if! {
             exception_object: *mut uw::_Unwind_Exception,
             context: *mut uw::_Unwind_Context,
         ) -> uw::_Unwind_Reason_Code {
-            if version != 1 {
-                return uw::_URC_FATAL_PHASE1_ERROR;
-            }
-            let eh_action = match find_eh_action(context) {
-                Ok(action) => action,
-                Err(_) => return uw::_URC_FATAL_PHASE1_ERROR,
-            };
-            if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
-                match eh_action {
-                    EHAction::None | EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
-                    EHAction::Catch(_) | EHAction::Filter(_) => uw::_URC_HANDLER_FOUND,
-                    EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR,
+            unsafe {
+                if version != 1 {
+                    return uw::_URC_FATAL_PHASE1_ERROR;
                 }
-            } else {
-                match eh_action {
-                    EHAction::None => uw::_URC_CONTINUE_UNWIND,
-                    // Forced unwinding hits a terminate action.
-                    EHAction::Filter(_) if actions as i32 & uw::_UA_FORCE_UNWIND as i32 != 0 => uw::_URC_CONTINUE_UNWIND,
-                    EHAction::Cleanup(lpad) | EHAction::Catch(lpad) | EHAction::Filter(lpad) => {
-                        uw::_Unwind_SetGR(
-                            context,
-                            UNWIND_DATA_REG.0,
-                            exception_object.cast(),
-                        );
-                        uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, core::ptr::null());
-                        uw::_Unwind_SetIP(context, lpad);
-                        uw::_URC_INSTALL_CONTEXT
+                let eh_action = match find_eh_action(context) {
+                    Ok(action) => action,
+                    Err(_) => return uw::_URC_FATAL_PHASE1_ERROR,
+                };
+                if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
+                    match eh_action {
+                        EHAction::None | EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
+                        EHAction::Catch(_) | EHAction::Filter(_) => uw::_URC_HANDLER_FOUND,
+                        EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR,
+                    }
+                } else {
+                    match eh_action {
+                        EHAction::None => uw::_URC_CONTINUE_UNWIND,
+                        // Forced unwinding hits a terminate action.
+                        EHAction::Filter(_) if actions as i32 & uw::_UA_FORCE_UNWIND as i32 != 0 => uw::_URC_CONTINUE_UNWIND,
+                        EHAction::Cleanup(lpad) | EHAction::Catch(lpad) | EHAction::Filter(lpad) => {
+                            uw::_Unwind_SetGR(
+                                context,
+                                UNWIND_DATA_REG.0,
+                                exception_object.cast(),
+                            );
+                            uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, core::ptr::null());
+                            uw::_Unwind_SetIP(context, lpad);
+                            uw::_URC_INSTALL_CONTEXT
+                        }
+                        EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR,
                     }
-                    EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR,
                 }
             }
         }
 
         cfg_if::cfg_if! {
             if #[cfg(all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"))] {
-                // On x86_64 MinGW targets, the unwinding mechanism is SEH however the unwind
-                // handler data (aka LSDA) uses GCC-compatible encoding.
+                /// personality fn called by [Windows Structured Exception Handling][windows-eh]
+                ///
+                /// On x86_64 and AArch64 MinGW targets, the unwinding mechanism is SEH,
+                /// however the unwind handler data (aka LSDA) uses GCC-compatible encoding
+                ///
+                /// [windows-eh]: https://learn.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-170
                 #[lang = "eh_personality"]
                 #[allow(nonstandard_style)]
                 unsafe extern "C" fn rust_eh_personality(
@@ -245,16 +261,33 @@ cfg_if::cfg_if! {
                     contextRecord: *mut uw::CONTEXT,
                     dispatcherContext: *mut uw::DISPATCHER_CONTEXT,
                 ) -> uw::EXCEPTION_DISPOSITION {
-                    uw::_GCC_specific_handler(
-                        exceptionRecord,
-                        establisherFrame,
-                        contextRecord,
-                        dispatcherContext,
-                        rust_eh_personality_impl,
-                    )
+                    // SAFETY: the cfg is still target_os = "windows" and target_env = "gnu",
+                    // which means that this is the correct function to call, passing our impl fn
+                    // as the callback which gets actually used
+                    unsafe {
+                        uw::_GCC_specific_handler(
+                            exceptionRecord,
+                            establisherFrame,
+                            contextRecord,
+                            dispatcherContext,
+                            rust_eh_personality_impl,
+                        )
+                    }
                 }
             } else {
-                // The personality routine for most of our targets.
+                /// personality fn called by [Itanium C++ ABI Exception Handling][itanium-eh]
+                ///
+                /// The personality routine for most non-Windows targets. This will be called by
+                /// the unwinding library:
+                /// - "In the search phase, the framework repeatedly calls the personality routine,
+                ///   with the _UA_SEARCH_PHASE flag as described below, first for the current PC
+                ///   and register state, and then unwinding a frame to a new PC at each step..."
+                /// - "If the search phase reports success, the framework restarts in the cleanup
+                ///    phase. Again, it repeatedly calls the personality routine, with the
+                ///   _UA_CLEANUP_PHASE flag as described below, first for the current PC and
+                ///   register state, and then unwinding a frame to a new PC at each step..."i
+                ///
+                /// [itanium-eh]: https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
                 #[lang = "eh_personality"]
                 unsafe extern "C" fn rust_eh_personality(
                     version: c_int,
@@ -263,13 +296,17 @@ cfg_if::cfg_if! {
                     exception_object: *mut uw::_Unwind_Exception,
                     context: *mut uw::_Unwind_Context,
                 ) -> uw::_Unwind_Reason_Code {
-                    rust_eh_personality_impl(
-                        version,
-                        actions,
-                        exception_class,
-                        exception_object,
-                        context,
-                    )
+                    // SAFETY: the platform support must modify the cfg for the inner fn
+                    // if it needs something different than what is currently invoked.
+                    unsafe {
+                        rust_eh_personality_impl(
+                            version,
+                            actions,
+                            exception_class,
+                            exception_object,
+                            context,
+                        )
+                    }
                 }
             }
         }
@@ -277,18 +314,20 @@ cfg_if::cfg_if! {
 }
 
 unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> Result<EHAction, ()> {
-    let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
-    let mut ip_before_instr: c_int = 0;
-    let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
-    let eh_context = EHContext {
-        // The return address points 1 byte past the call instruction,
-        // which could be in the next IP range in LSDA range table.
-        //
-        // `ip = -1` has special meaning, so use wrapping sub to allow for that
-        ip: if ip_before_instr != 0 { ip } else { ip.wrapping_sub(1) },
-        func_start: uw::_Unwind_GetRegionStart(context),
-        get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
-        get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
-    };
-    eh::find_eh_action(lsda, &eh_context)
+    unsafe {
+        let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
+        let mut ip_before_instr: c_int = 0;
+        let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
+        let eh_context = EHContext {
+            // The return address points 1 byte past the call instruction,
+            // which could be in the next IP range in LSDA range table.
+            //
+            // `ip = -1` has special meaning, so use wrapping sub to allow for that
+            ip: if ip_before_instr != 0 { ip } else { ip.wrapping_sub(1) },
+            func_start: uw::_Unwind_GetRegionStart(context),
+            get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
+            get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
+        };
+        eh::find_eh_action(lsda, &eh_context)
+    }
 }