Browse Source

Merge pull request #65 from FenrirWolf/fix-panics

Update to new panic ABI
pull/10/head
FenrirWolf 7 years ago committed by GitHub
parent
commit
664fc3ab93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      ctr-std/src/lib.rs
  2. 326
      ctr-std/src/panicking.rs
  3. 4
      ctr-std/src/sys/unix/stdio.rs

2
ctr-std/src/lib.rs

@ -289,6 +289,7 @@
#![feature(on_unimplemented)] #![feature(on_unimplemented)]
#![feature(oom)] #![feature(oom)]
#![feature(optin_builtin_traits)] #![feature(optin_builtin_traits)]
#![feature(panic_internals)]
#![feature(panic_unwind)] #![feature(panic_unwind)]
#![feature(peek)] #![feature(peek)]
#![feature(placement_in_syntax)] #![feature(placement_in_syntax)]
@ -305,6 +306,7 @@
#![feature(slice_internals)] #![feature(slice_internals)]
#![feature(slice_patterns)] #![feature(slice_patterns)]
#![feature(staged_api)] #![feature(staged_api)]
#![feature(std_internals)]
#![feature(stdsimd)] #![feature(stdsimd)]
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
#![feature(str_char)] #![feature(str_char)]

326
ctr-std/src/panicking.rs

@ -17,18 +17,19 @@
//! * Executing a panic up to doing the actual implementation //! * Executing a panic up to doing the actual implementation
//! * Shims around "try" //! * Shims around "try"
#![allow(unused_imports)] use core::panic::BoxMeUp;
use io::prelude::*; use io::prelude::*;
use any::Any; use any::Any;
use cell::RefCell; use cell::RefCell;
use core::panic::{PanicInfo, Location};
use fmt; use fmt;
use intrinsics; use intrinsics;
use mem; use mem;
use ptr; use ptr;
use raw; use raw;
use sys::stdio::Stderr; use sys::stdio::{Stderr, stderr_prints_nothing};
use sys_common::rwlock::RWLock; use sys_common::rwlock::RWLock;
use sys_common::thread_info; use sys_common::thread_info;
use sys_common::util; use sys_common::util;
@ -57,7 +58,7 @@ extern {
data_ptr: *mut usize, data_ptr: *mut usize,
vtable_ptr: *mut usize) -> u32; vtable_ptr: *mut usize) -> u32;
#[unwind(allowed)] #[unwind(allowed)]
fn __rust_start_panic(data: usize, vtable: usize) -> u32; fn __rust_start_panic(payload: usize) -> u32;
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -160,182 +161,6 @@ pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
} }
} }
/// A struct providing information about a panic.
///
/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
/// function.
///
/// [`set_hook`]: ../../std/panic/fn.set_hook.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
/// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
/// }));
///
/// panic!("Normal panic");
/// ```
#[stable(feature = "panic_hooks", since = "1.10.0")]
#[derive(Debug)]
pub struct PanicInfo<'a> {
payload: &'a (Any + Send),
location: Location<'a>,
}
impl<'a> PanicInfo<'a> {
/// Returns the payload associated with the panic.
///
/// This will commonly, but not always, be a `&'static str` or [`String`].
///
/// [`String`]: ../../std/string/struct.String.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
/// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
/// }));
///
/// panic!("Normal panic");
/// ```
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn payload(&self) -> &(Any + Send) {
self.payload
}
/// Returns information about the location from which the panic originated,
/// if available.
///
/// This method will currently always return [`Some`], but this may change
/// in future versions.
///
/// [`Some`]: ../../std/option/enum.Option.html#variant.Some
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(location) = panic_info.location() {
/// println!("panic occurred in file '{}' at line {}", location.file(),
/// location.line());
/// } else {
/// println!("panic occurred but can't get location information...");
/// }
/// }));
///
/// panic!("Normal panic");
/// ```
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn location(&self) -> Option<&Location> {
Some(&self.location)
}
}
/// A struct containing information about the location of a panic.
///
/// This structure is created by the [`location`] method of [`PanicInfo`].
///
/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location
/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(location) = panic_info.location() {
/// println!("panic occurred in file '{}' at line {}", location.file(), location.line());
/// } else {
/// println!("panic occurred but can't get location information...");
/// }
/// }));
///
/// panic!("Normal panic");
/// ```
#[derive(Debug)]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub struct Location<'a> {
file: &'a str,
line: u32,
col: u32,
}
impl<'a> Location<'a> {
/// Returns the name of the source file from which the panic originated.
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(location) = panic_info.location() {
/// println!("panic occurred in file '{}'", location.file());
/// } else {
/// println!("panic occurred but can't get location information...");
/// }
/// }));
///
/// panic!("Normal panic");
/// ```
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn file(&self) -> &str {
self.file
}
/// Returns the line number from which the panic originated.
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(location) = panic_info.location() {
/// println!("panic occurred at line {}", location.line());
/// } else {
/// println!("panic occurred but can't get location information...");
/// }
/// }));
///
/// panic!("Normal panic");
/// ```
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn line(&self) -> u32 {
self.line
}
/// Returns the column from which the panic originated.
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(location) = panic_info.location() {
/// println!("panic occurred at column {}", location.column());
/// } else {
/// println!("panic occurred but can't get location information...");
/// }
/// }));
///
/// panic!("Normal panic");
/// ```
#[stable(feature = "panic_col", since = "1.25")]
pub fn column(&self) -> u32 {
self.col
}
}
fn default_hook(info: &PanicInfo) { fn default_hook(info: &PanicInfo) {
#[cfg(feature = "backtrace")] #[cfg(feature = "backtrace")]
use sys_common::backtrace; use sys_common::backtrace;
@ -353,18 +178,16 @@ fn default_hook(info: &PanicInfo) {
} }
}; };
let file = info.location.file; let location = info.location().unwrap(); // The current implementation always returns Some
let line = info.location.line;
let col = info.location.col;
let msg = match info.payload.downcast_ref::<&'static str>() { let msg = match info.payload().downcast_ref::<&'static str>() {
Some(s) => *s, Some(s) => *s,
None => match info.payload.downcast_ref::<String>() { None => match info.payload().downcast_ref::<String>() {
Some(s) => &s[..], Some(s) => &s[..],
None => "Box<Any>", None => "Box<Any>",
} }
}; };
let mut err = Stderr::new().ok();
let thread = thread_info::current_thread(); let thread = thread_info::current_thread();
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>"); let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
@ -372,8 +195,8 @@ fn default_hook(info: &PanicInfo) {
use libctru::{errorInit, errorText, errorDisp, errorConf, ERROR_TEXT_WORD_WRAP, use libctru::{errorInit, errorText, errorDisp, errorConf, ERROR_TEXT_WORD_WRAP,
CFG_LANGUAGE_EN, consoleDebugInit, debugDevice_SVC}; CFG_LANGUAGE_EN, consoleDebugInit, debugDevice_SVC};
let error_text = format!("thread '{}' panicked at '{}', {}:{}:{}", let error_text = format!("thread '{}' panicked at '{}', {}", name, msg, location);
name, msg, file, line, col);
unsafe { unsafe {
// Prepare error message for display // Prepare error message for display
let mut error_conf: errorConf = mem::uninitialized(); let mut error_conf: errorConf = mem::uninitialized();
@ -393,7 +216,6 @@ fn default_hook(info: &PanicInfo) {
consoleDebugInit(debugDevice_SVC); consoleDebugInit(debugDevice_SVC);
} }
let mut err = Stderr::new().ok();
let write = |err: &mut ::io::Write| { let write = |err: &mut ::io::Write| {
let _ = write!(err, "{}", error_text); let _ = write!(err, "{}", error_text);
@ -423,10 +245,9 @@ fn default_hook(info: &PanicInfo) {
(None, Some(ref mut err)) => { write(err) } (None, Some(ref mut err)) => { write(err) }
_ => {} _ => {}
} }
// TODO: If we ever implement backtrace functionality, determine the best way to
// incorporate it with the error applet
} }
#[cfg(not(test))] #[cfg(not(test))]
#[doc(hidden)] #[doc(hidden)]
#[unstable(feature = "update_panic_count", issue = "0")] #[unstable(feature = "update_panic_count", issue = "0")]
@ -544,9 +365,38 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments,
// panic + OOM properly anyway (see comment in begin_panic // panic + OOM properly anyway (see comment in begin_panic
// below). // below).
rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col);
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 {
let inner = self.inner;
self.string.get_or_insert_with(|| {
let mut s = String::new(); let mut s = String::new();
let _ = s.write_fmt(*msg); drop(s.write_fmt(*inner));
begin_panic(s, file_line_col) s
})
}
}
unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
fn box_me_up(&mut self) -> *mut (Any + Send) {
let contents = mem::replace(self.fill(), String::new());
Box::into_raw(Box::new(contents))
}
fn get(&mut self) -> &(Any + Send) {
self.fill()
}
}
} }
/// This is the entry point of panicking for panic!() and assert!(). /// This is the entry point of panicking for panic!() and assert!().
@ -562,18 +412,43 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3
// be performed in the parent of this thread instead of the thread that's // be performed in the parent of this thread instead of the thread that's
// panicking. // panicking.
rust_panic_with_hook(Box::new(msg), file_line_col) 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 (Any + Send) {
let data = match self.inner.take() {
Some(a) => Box::new(a) as Box<Any + Send>,
None => Box::new(()),
};
Box::into_raw(data)
}
fn get(&mut self) -> &(Any + Send) {
match self.inner {
Some(ref a) => a,
None => &(),
}
}
}
} }
/// Executes the primary logic for a panic, including checking for recursive /// Central point for dispatching panics.
/// panics and panic hooks.
/// ///
/// This is the entry point or panics from libcore, formatted panics, and /// Executes the primary logic for a panic, including checking for recursive
/// `Box<Any>` panics. Here we'll verify that we're not panicking recursively, /// panics, panic hooks, and finally dispatching to the panic runtime to either
/// run panic hooks, and then delegate to the actual implementation of panics. /// abort or unwind.
#[inline(never)] fn rust_panic_with_hook(payload: &mut BoxMeUp,
#[cold] message: Option<&fmt::Arguments>,
fn rust_panic_with_hook(msg: Box<Any + Send>,
file_line_col: &(&'static str, u32, u32)) -> ! { file_line_col: &(&'static str, u32, u32)) -> ! {
let (file, line, col) = *file_line_col; let (file, line, col) = *file_line_col;
@ -591,18 +466,24 @@ fn rust_panic_with_hook(msg: Box<Any + Send>,
} }
unsafe { unsafe {
let info = PanicInfo { let mut info = PanicInfo::internal_constructor(
payload: &*msg, message,
location: Location { Location::internal_constructor(file, line, col),
file, );
line,
col,
},
};
HOOK_LOCK.read(); HOOK_LOCK.read();
match HOOK { match HOOK {
Hook::Default => default_hook(&info), // Some platforms know that printing to stderr won't ever actually
Hook::Custom(ptr) => (*ptr)(&info), // 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(); HOOK_LOCK.read_unlock();
} }
@ -617,22 +498,35 @@ fn rust_panic_with_hook(msg: Box<Any + Send>,
unsafe { intrinsics::abort() } unsafe { intrinsics::abort() }
} }
rust_panic(msg) rust_panic(payload)
} }
/// Shim around rust_panic. Called by resume_unwind. /// Shim around rust_panic. Called by resume_unwind.
pub fn update_count_then_panic(msg: Box<Any + Send>) -> ! { pub fn update_count_then_panic(msg: Box<Any + Send>) -> ! {
update_panic_count(1); update_panic_count(1);
rust_panic(msg)
struct RewrapBox(Box<Any + Send>);
unsafe impl BoxMeUp for RewrapBox {
fn box_me_up(&mut self) -> *mut (Any + Send) {
Box::into_raw(mem::replace(&mut self.0, Box::new(())))
}
fn get(&mut self) -> &(Any + Send) {
&*self.0
}
}
rust_panic(&mut RewrapBox(msg))
} }
/// A private no-mangle function on which to slap yer breakpoints. /// A private no-mangle function on which to slap yer breakpoints.
#[no_mangle] #[no_mangle]
#[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints #[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints
pub fn rust_panic(msg: Box<Any + Send>) -> ! { pub fn rust_panic(mut msg: &mut BoxMeUp) -> ! {
let code = unsafe { let code = unsafe {
let obj = mem::transmute::<_, raw::TraitObject>(msg); let obj = &mut msg as *mut &mut BoxMeUp;
__rust_start_panic(obj.data as usize, obj.vtable as usize) __rust_start_panic(obj as usize)
}; };
rtabort!("failed to initiate panic, error {}", code) rtabort!("failed to initiate panic, error {}", code)
} }

4
ctr-std/src/sys/unix/stdio.rs

@ -75,3 +75,7 @@ pub fn is_ebadf(err: &io::Error) -> bool {
} }
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
pub fn stderr_prints_nothing() -> bool {
false
}

Loading…
Cancel
Save