aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src
diff options
context:
space:
mode:
authorFenrirWolf <[email protected]>2018-04-21 19:03:25 -0600
committerGitHub <[email protected]>2018-04-21 19:03:25 -0600
commit664fc3ab93716e4ae217b8b7c6619d020cf207be (patch)
tree36dbe42f29ffe434dbe6f9b8691eabcaacb32889 /ctr-std/src
parentMerge pull request #64 from FenrirWolf/nightly-update (diff)
parentUpdate to new panic ABI (diff)
downloadctru-rs-664fc3ab93716e4ae217b8b7c6619d020cf207be.tar.xz
ctru-rs-664fc3ab93716e4ae217b8b7c6619d020cf207be.zip
Merge pull request #65 from FenrirWolf/fix-panics
Update to new panic ABI
Diffstat (limited to 'ctr-std/src')
-rw-r--r--ctr-std/src/lib.rs2
-rw-r--r--ctr-std/src/panicking.rs346
-rw-r--r--ctr-std/src/sys/unix/stdio.rs4
3 files changed, 126 insertions, 226 deletions
diff --git a/ctr-std/src/lib.rs b/ctr-std/src/lib.rs
index 146e23c..d5d4f49 100644
--- a/ctr-std/src/lib.rs
+++ b/ctr-std/src/lib.rs
@@ -289,6 +289,7 @@
#![feature(on_unimplemented)]
#![feature(oom)]
#![feature(optin_builtin_traits)]
+#![feature(panic_internals)]
#![feature(panic_unwind)]
#![feature(peek)]
#![feature(placement_in_syntax)]
@@ -305,6 +306,7 @@
#![feature(slice_internals)]
#![feature(slice_patterns)]
#![feature(staged_api)]
+#![feature(std_internals)]
#![feature(stdsimd)]
#![feature(stmt_expr_attributes)]
#![feature(str_char)]
diff --git a/ctr-std/src/panicking.rs b/ctr-std/src/panicking.rs
index cbc375f..ad0a337 100644
--- a/ctr-std/src/panicking.rs
+++ b/ctr-std/src/panicking.rs
@@ -17,18 +17,19 @@
//! * Executing a panic up to doing the actual implementation
//! * Shims around "try"
-#![allow(unused_imports)]
+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;
+use sys::stdio::{Stderr, stderr_prints_nothing};
use sys_common::rwlock::RWLock;
use sys_common::thread_info;
use sys_common::util;
@@ -57,7 +58,7 @@ extern {
data_ptr: *mut usize,
vtable_ptr: *mut usize) -> u32;
#[unwind(allowed)]
- fn __rust_start_panic(data: usize, vtable: usize) -> u32;
+ fn __rust_start_panic(payload: usize) -> u32;
}
#[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) {
#[cfg(feature = "backtrace")]
use sys_common::backtrace;
@@ -353,18 +178,16 @@ fn default_hook(info: &PanicInfo) {
}
};
- let file = info.location.file;
- let line = info.location.line;
- let col = info.location.col;
+ let location = info.location().unwrap(); // The current implementation always returns Some
- let msg = match info.payload.downcast_ref::<&'static str>() {
+ let msg = match info.payload().downcast_ref::<&'static str>() {
Some(s) => *s,
- None => match info.payload.downcast_ref::<String>() {
+ 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>");
@@ -372,8 +195,8 @@ fn default_hook(info: &PanicInfo) {
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, file, line, col);
+ let error_text = format!("thread '{}' panicked at '{}', {}", name, msg, location);
+
unsafe {
// Prepare error message for display
let mut error_conf: errorConf = mem::uninitialized();
@@ -393,7 +216,6 @@ fn default_hook(info: &PanicInfo) {
consoleDebugInit(debugDevice_SVC);
}
- let mut err = Stderr::new().ok();
let write = |err: &mut ::io::Write| {
let _ = write!(err, "{}", error_text);
@@ -413,20 +235,19 @@ fn default_hook(info: &PanicInfo) {
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) }
- _ => {}
+ (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) }
+ _ => {}
}
- // TODO: If we ever implement backtrace functionality, determine the best way to
- // incorporate it with the error applet
}
+
#[cfg(not(test))]
#[doc(hidden)]
#[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
// below).
- let mut s = String::new();
- let _ = s.write_fmt(*msg);
- begin_panic(s, file_line_col)
+ 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();
+ drop(s.write_fmt(*inner));
+ 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!().
@@ -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
// 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
-/// panics and panic hooks.
+/// Central point for dispatching panics.
///
-/// This is the entry point or panics from libcore, formatted panics, and
-/// `Box<Any>` panics. Here we'll verify that we're not panicking recursively,
-/// run panic hooks, and then delegate to the actual implementation of panics.
-#[inline(never)]
-#[cold]
-fn rust_panic_with_hook(msg: Box<Any + Send>,
+/// 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 BoxMeUp,
+ message: Option<&fmt::Arguments>,
file_line_col: &(&'static str, u32, u32)) -> ! {
let (file, line, col) = *file_line_col;
@@ -591,18 +466,24 @@ fn rust_panic_with_hook(msg: Box<Any + Send>,
}
unsafe {
- let info = PanicInfo {
- payload: &*msg,
- location: Location {
- file,
- line,
- col,
- },
- };
+ let mut info = PanicInfo::internal_constructor(
+ message,
+ Location::internal_constructor(file, line, col),
+ );
HOOK_LOCK.read();
match HOOK {
- Hook::Default => default_hook(&info),
- Hook::Custom(ptr) => (*ptr)(&info),
+ // 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();
}
@@ -617,22 +498,35 @@ fn rust_panic_with_hook(msg: Box<Any + Send>,
unsafe { intrinsics::abort() }
}
- rust_panic(msg)
+ rust_panic(payload)
}
/// Shim around rust_panic. Called by resume_unwind.
pub fn update_count_then_panic(msg: Box<Any + Send>) -> ! {
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.
#[no_mangle]
#[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 obj = mem::transmute::<_, raw::TraitObject>(msg);
- __rust_start_panic(obj.data as usize, obj.vtable as usize)
+ let obj = &mut msg as *mut &mut BoxMeUp;
+ __rust_start_panic(obj as usize)
};
rtabort!("failed to initiate panic, error {}", code)
}
diff --git a/ctr-std/src/sys/unix/stdio.rs b/ctr-std/src/sys/unix/stdio.rs
index e9b3d4a..87ba2ae 100644
--- a/ctr-std/src/sys/unix/stdio.rs
+++ b/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 fn stderr_prints_nothing() -> bool {
+ false
+}