aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/panicking.rs
diff options
context:
space:
mode:
authorVivian Lim <[email protected]>2021-02-06 22:11:59 -0800
committerVivian Lim <[email protected]>2021-02-06 22:11:59 -0800
commit64423f0e34cc4a7d78c15b345b3b8f58243d8286 (patch)
treecc20e2e7f0fc35abf470e20e61d3d48f0d954f3b /ctr-std/src/panicking.rs
parentSupport libctru 2.0 (diff)
downloadarchived-ctru-rs-64423f0e34cc4a7d78c15b345b3b8f58243d8286.tar.xz
archived-ctru-rs-64423f0e34cc4a7d78c15b345b3b8f58243d8286.zip
Delete ctr-std to use my fork of the rust repo instead
Diffstat (limited to 'ctr-std/src/panicking.rs')
-rw-r--r--ctr-std/src/panicking.rs550
1 files changed, 0 insertions, 550 deletions
diff --git a/ctr-std/src/panicking.rs b/ctr-std/src/panicking.rs
deleted file mode 100644
index c612604..0000000
--- a/ctr-std/src/panicking.rs
+++ /dev/null
@@ -1,550 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Implementation of various bits and pieces of the `panic!` macro and
-//! associated runtime pieces.
-//!
-//! Specifically, this module contains the implementation of:
-//!
-//! * Panic hooks
-//! * Executing a panic up to doing the actual implementation
-//! * Shims around "try"
-
-use core::panic::BoxMeUp;
-
-use io::prelude::*;
-
-use any::Any;
-use cell::RefCell;
-use core::panic::{PanicInfo, Location};
-use fmt;
-use intrinsics;
-use mem;
-use ptr;
-use raw;
-use sys::stdio::{Stderr, stderr_prints_nothing};
-use sys_common::rwlock::RWLock;
-use sys_common::thread_info;
-use sys_common::util;
-use thread;
-
-thread_local! {
- pub static LOCAL_STDERR: RefCell<Option<Box<dyn Write + Send>>> = {
- RefCell::new(None)
- }
-}
-
-// Binary interface to the panic runtime that the standard library depends on.
-//
-// The standard library is tagged with `#![needs_panic_runtime]` (introduced in
-// RFC 1513) to indicate that it requires some other crate tagged with
-// `#![panic_runtime]` to exist somewhere. Each panic runtime is intended to
-// implement these symbols (with the same signatures) so we can get matched up
-// to them.
-//
-// One day this may look a little less ad-hoc with the compiler helping out to
-// hook up these functions, but it is not this day!
-#[allow(improper_ctypes)]
-extern {
- fn __rust_maybe_catch_panic(f: fn(*mut u8),
- data: *mut u8,
- data_ptr: *mut usize,
- vtable_ptr: *mut usize) -> u32;
- #[unwind(allowed)]
- fn __rust_start_panic(payload: usize) -> u32;
-}
-
-#[derive(Copy, Clone)]
-enum Hook {
- Default,
- Custom(*mut (dyn Fn(&PanicInfo) + 'static + Sync + Send)),
-}
-
-static HOOK_LOCK: RWLock = RWLock::new();
-static mut HOOK: Hook = Hook::Default;
-
-/// Registers a custom panic hook, replacing any that was previously registered.
-///
-/// The panic hook is invoked when a thread panics, but before the panic runtime
-/// is invoked. As such, the hook will run with both the aborting and unwinding
-/// runtimes. The default hook prints a message to standard error and generates
-/// a backtrace if requested, but this behavior can be customized with the
-/// `set_hook` and [`take_hook`] functions.
-///
-/// [`take_hook`]: ./fn.take_hook.html
-///
-/// The hook is provided with a `PanicInfo` struct which contains information
-/// about the origin of the panic, including the payload passed to `panic!` and
-/// the source code location from which the panic originated.
-///
-/// The panic hook is a global resource.
-///
-/// # Panics
-///
-/// Panics if called from a panicking thread.
-///
-/// # Examples
-///
-/// The following will print "Custom panic hook":
-///
-/// ```should_panic
-/// use std::panic;
-///
-/// panic::set_hook(Box::new(|_| {
-/// println!("Custom panic hook");
-/// }));
-///
-/// panic!("Normal panic");
-/// ```
-#[stable(feature = "panic_hooks", since = "1.10.0")]
-pub fn set_hook(hook: Box<dyn Fn(&PanicInfo) + 'static + Sync + Send>) {
- if thread::panicking() {
- panic!("cannot modify the panic hook from a panicking thread");
- }
-
- unsafe {
- HOOK_LOCK.write();
- let old_hook = HOOK;
- HOOK = Hook::Custom(Box::into_raw(hook));
- HOOK_LOCK.write_unlock();
-
- if let Hook::Custom(ptr) = old_hook {
- Box::from_raw(ptr);
- }
- }
-}
-
-/// Unregisters the current panic hook, returning it.
-///
-/// *See also the function [`set_hook`].*
-///
-/// [`set_hook`]: ./fn.set_hook.html
-///
-/// If no custom hook is registered, the default hook will be returned.
-///
-/// # Panics
-///
-/// Panics if called from a panicking thread.
-///
-/// # Examples
-///
-/// The following will print "Normal panic":
-///
-/// ```should_panic
-/// use std::panic;
-///
-/// panic::set_hook(Box::new(|_| {
-/// println!("Custom panic hook");
-/// }));
-///
-/// let _ = panic::take_hook();
-///
-/// panic!("Normal panic");
-/// ```
-#[stable(feature = "panic_hooks", since = "1.10.0")]
-pub fn take_hook() -> Box<dyn Fn(&PanicInfo) + 'static + Sync + Send> {
- if thread::panicking() {
- panic!("cannot modify the panic hook from a panicking thread");
- }
-
- unsafe {
- HOOK_LOCK.write();
- let hook = HOOK;
- HOOK = Hook::Default;
- HOOK_LOCK.write_unlock();
-
- match hook {
- Hook::Default => Box::new(default_hook),
- Hook::Custom(ptr) => Box::from_raw(ptr),
- }
- }
-}
-
-fn default_hook(info: &PanicInfo) {
- #[cfg(feature = "backtrace")]
- use sys_common::backtrace;
-
- // If this is a double panic, make sure that we print a backtrace
- // for this panic. Otherwise only print it if logging is enabled.
- #[cfg(feature = "backtrace")]
- let log_backtrace = {
- let panics = update_panic_count(0);
-
- if panics >= 2 {
- Some(backtrace::PrintFormat::Full)
- } else {
- backtrace::log_enabled()
- }
- };
-
- let location = info.location().unwrap(); // The current implementation always returns Some
-
- let msg = match info.payload().downcast_ref::<&'static str>() {
- Some(s) => *s,
- None => match info.payload().downcast_ref::<String>() {
- Some(s) => &s[..],
- None => "Box<Any>",
- }
- };
- let mut err = Stderr::new().ok();
- let thread = thread_info::current_thread();
- let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
-
- // 3DS-specific code begins here to display panics via the Error applet
- use libctru::{errorInit, errorText, errorDisp, errorConf, ERROR_TEXT_WORD_WRAP,
- CFG_LANGUAGE_EN, consoleDebugInit, debugDevice_SVC};
-
- let error_text = format!("thread '{}' panicked at '{}', {}", name, msg, location);
-
- unsafe {
- // Prepare error message for display
- let mut error_conf: errorConf = mem::uninitialized();
- errorInit(&mut error_conf,
- ERROR_TEXT_WORD_WRAP,
- CFG_LANGUAGE_EN);
- errorText(&mut error_conf, error_text.as_ptr() as *const ::libc::c_char);
-
- // Display the error
- errorDisp(&mut error_conf);
- }
-
- // Let's also write to stderr using the debug console. The output will be
- // visible in Citra if a custom logging filter such as `Debug.Emulated:Debug`
- // is enabled in the logging section of `~/.config/citra-emu/sdl2-config.ini`
- unsafe {
- consoleDebugInit(debugDevice_SVC);
- }
-
- let write = |err: &mut dyn (::io::Write)| {
- let _ = write!(err, "{}", error_text);
-
- #[cfg(feature = "backtrace")]
- {
- use sync::atomic::{AtomicBool, Ordering};
-
- static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
-
- if let Some(format) = log_backtrace {
- let _ = backtrace::print(err, format);
- } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
- let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace.");
- }
- }
- };
-
- let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
- match (prev, err.as_mut()) {
- (Some(mut stderr), _) => {
- write(&mut *stderr);
- let mut s = Some(stderr);
- LOCAL_STDERR.with(|slot| {
- *slot.borrow_mut() = s.take();
- });
- }
- (None, Some(ref mut err)) => { write(err) }
- _ => {}
- }
-}
-
-
-#[cfg(not(test))]
-#[doc(hidden)]
-#[unstable(feature = "update_panic_count", issue = "0")]
-pub fn update_panic_count(amt: isize) -> usize {
- use cell::Cell;
- thread_local! { static PANIC_COUNT: Cell<usize> = Cell::new(0) }
-
- PANIC_COUNT.with(|c| {
- let next = (c.get() as isize + amt) as usize;
- c.set(next);
- return next
- })
-}
-
-#[cfg(test)]
-pub use realstd::rt::update_panic_count;
-
-/// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
-pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
- #[allow(unions_with_drop_fields)]
- union Data<F, R> {
- f: F,
- r: R,
- }
-
- // We do some sketchy operations with ownership here for the sake of
- // performance. We can only pass pointers down to
- // `__rust_maybe_catch_panic` (can't pass objects by value), so we do all
- // the ownership tracking here manually using a union.
- //
- // We go through a transition where:
- //
- // * First, we set the data to be the closure that we're going to call.
- // * When we make the function call, the `do_call` function below, we take
- // ownership of the function pointer. At this point the `Data` union is
- // entirely uninitialized.
- // * If the closure successfully returns, we write the return value into the
- // data's return slot. Note that `ptr::write` is used as it's overwriting
- // uninitialized data.
- // * Finally, when we come back out of the `__rust_maybe_catch_panic` we're
- // in one of two states:
- //
- // 1. The closure didn't panic, in which case the return value was
- // filled in. We move it out of `data` and return it.
- // 2. The closure panicked, in which case the return value wasn't
- // filled in. In this case the entire `data` union is invalid, so
- // there is no need to drop anything.
- //
- // Once we stack all that together we should have the "most efficient'
- // method of calling a catch panic whilst juggling ownership.
- let mut any_data = 0;
- let mut any_vtable = 0;
- let mut data = Data {
- f,
- };
-
- let r = __rust_maybe_catch_panic(do_call::<F, R>,
- &mut data as *mut _ as *mut u8,
- &mut any_data,
- &mut any_vtable);
-
- return if r == 0 {
- debug_assert!(update_panic_count(0) == 0);
- Ok(data.r)
- } else {
- update_panic_count(-1);
- debug_assert!(update_panic_count(0) == 0);
- Err(mem::transmute(raw::TraitObject {
- data: any_data as *mut _,
- vtable: any_vtable as *mut _,
- }))
- };
-
- fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
- unsafe {
- let data = data as *mut Data<F, R>;
- let f = ptr::read(&mut (*data).f);
- ptr::write(&mut (*data).r, f());
- }
- }
-}
-
-/// Determines whether the current thread is unwinding because of panic.
-pub fn panicking() -> bool {
- update_panic_count(0) != 0
-}
-
-/// Entry point of panic from the libcore crate.
-#[cfg(not(test))]
-#[panic_implementation]
-#[unwind(allowed)]
-pub fn rust_begin_panic(info: &PanicInfo) -> ! {
- continue_panic_fmt(&info)
-}
-
-/// The entry point for panicking with a formatted message.
-///
-/// This is designed to reduce the amount of code required at the call
-/// site as much as possible (so that `panic!()` has as low an impact
-/// on (e.g.) the inlining of other functions as possible), by moving
-/// the actual formatting into this shared place.
-#[unstable(feature = "libstd_sys_internals",
- reason = "used by the panic! macro",
- issue = "0")]
-#[inline(never)] #[cold]
-pub fn begin_panic_fmt(msg: &fmt::Arguments,
- file_line_col: &(&'static str, u32, u32)) -> ! {
- let (file, line, col) = *file_line_col;
- let info = PanicInfo::internal_constructor(
- Some(msg),
- Location::internal_constructor(file, line, col),
- );
- continue_panic_fmt(&info)
-}
-
-fn continue_panic_fmt(info: &PanicInfo) -> ! {
- struct PanicPayload<'a> {
- inner: &'a fmt::Arguments<'a>,
- string: Option<String>,
- }
-
- impl<'a> PanicPayload<'a> {
- fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> {
- PanicPayload { inner, string: None }
- }
-
- fn fill(&mut self) -> &mut String {
- use fmt::Write;
-
- let inner = self.inner;
- self.string.get_or_insert_with(|| {
- let mut s = String::new();
- drop(s.write_fmt(*inner));
- s
- })
- }
- }
-
- unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
- fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
- let contents = mem::replace(self.fill(), String::new());
- Box::into_raw(Box::new(contents))
- }
-
- fn get(&mut self) -> &(dyn Any + Send) {
- self.fill()
- }
- }
-
- // We do two allocations here, unfortunately. But (a) they're
- // required with the current scheme, and (b) we don't handle
- // panic + OOM properly anyway (see comment in begin_panic
- // below).
-
- let loc = info.location().unwrap(); // The current implementation always returns Some
- let msg = info.message().unwrap(); // The current implementation always returns Some
- let file_line_col = (loc.file(), loc.line(), loc.column());
- rust_panic_with_hook(
- &mut PanicPayload::new(msg),
- info.message(),
- &file_line_col);
-}
-
-/// This is the entry point of panicking for panic!() and assert!().
-#[unstable(feature = "libstd_sys_internals",
- reason = "used by the panic! macro",
- issue = "0")]
-#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
-pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! {
- // Note that this should be the only allocation performed in this code path.
- // Currently this means that panic!() on OOM will invoke this code path,
- // but then again we're not really ready for panic on OOM anyway. If
- // we do start doing this, then we should propagate this allocation to
- // be performed in the parent of this thread instead of the thread that's
- // panicking.
-
- rust_panic_with_hook(&mut PanicPayload::new(msg), None, file_line_col);
-
- struct PanicPayload<A> {
- inner: Option<A>,
- }
-
- impl<A: Send + 'static> PanicPayload<A> {
- fn new(inner: A) -> PanicPayload<A> {
- PanicPayload { inner: Some(inner) }
- }
- }
-
- unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
- fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
- let data = match self.inner.take() {
- Some(a) => Box::new(a) as Box<dyn Any + Send>,
- None => Box::new(()),
- };
- Box::into_raw(data)
- }
-
- fn get(&mut self) -> &(dyn Any + Send) {
- match self.inner {
- Some(ref a) => a,
- None => &(),
- }
- }
- }
-}
-
-/// Central point for dispatching panics.
-///
-/// Executes the primary logic for a panic, including checking for recursive
-/// panics, panic hooks, and finally dispatching to the panic runtime to either
-/// abort or unwind.
-fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
- message: Option<&fmt::Arguments>,
- file_line_col: &(&str, u32, u32)) -> ! {
- let (file, line, col) = *file_line_col;
-
- let panics = update_panic_count(1);
-
- // If this is the third nested call (e.g. panics == 2, this is 0-indexed),
- // the panic hook probably triggered the last panic, otherwise the
- // double-panic check would have aborted the process. In this case abort the
- // process real quickly as we don't want to try calling it again as it'll
- // probably just panic again.
- if panics > 2 {
- util::dumb_print(format_args!("thread panicked while processing \
- panic. aborting.\n"));
- unsafe { intrinsics::abort() }
- }
-
- unsafe {
- let mut info = PanicInfo::internal_constructor(
- message,
- Location::internal_constructor(file, line, col),
- );
- HOOK_LOCK.read();
- match HOOK {
- // Some platforms know that printing to stderr won't ever actually
- // print anything, and if that's the case we can skip the default
- // hook.
- Hook::Default if stderr_prints_nothing() => {}
- Hook::Default => {
- info.set_payload(payload.get());
- default_hook(&info);
- }
- Hook::Custom(ptr) => {
- info.set_payload(payload.get());
- (*ptr)(&info);
- }
- }
- HOOK_LOCK.read_unlock();
- }
-
- if panics > 1 {
- // If a thread panics while it's already unwinding then we
- // have limited options. Currently our preference is to
- // just abort. In the future we may consider resuming
- // unwinding or otherwise exiting the thread cleanly.
- util::dumb_print(format_args!("thread panicked while panicking. \
- aborting.\n"));
- unsafe { intrinsics::abort() }
- }
-
- rust_panic(payload)
-}
-
-/// Shim around rust_panic. Called by resume_unwind.
-pub fn update_count_then_panic(msg: Box<dyn Any + Send>) -> ! {
- update_panic_count(1);
-
- struct RewrapBox(Box<dyn Any + Send>);
-
- unsafe impl BoxMeUp for RewrapBox {
- fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
- Box::into_raw(mem::replace(&mut self.0, Box::new(())))
- }
-
- fn get(&mut self) -> &(dyn Any + Send) {
- &*self.0
- }
- }
-
- rust_panic(&mut RewrapBox(msg))
-}
-
-/// A private no-mangle function on which to slap yer breakpoints.
-#[no_mangle]
-#[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints
-pub fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! {
- let code = unsafe {
- let obj = &mut msg as *mut &mut dyn BoxMeUp;
- __rust_start_panic(obj as usize)
- };
- rtabort!("failed to initiate panic, error {}", code)
-}