+++ /dev/null
-// Copyright 2013 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 Rust stack unwinding
-//!
-//! For background on exception handling and stack unwinding please see
-//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
-//! documents linked from it.
-//! These are also good reads:
-//! http://theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/
-//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/
-//! http://www.airs.com/blog/index.php?s=exception+frames
-//!
-//! ## A brief summary
-//!
-//! Exception handling happens in two phases: a search phase and a cleanup phase.
-//!
-//! In both phases the unwinder walks stack frames from top to bottom using
-//! information from the stack frame unwind sections of the current process's
-//! modules ("module" here refers to an OS module, i.e. an executable or a
-//! dynamic library).
-//!
-//! For each stack frame, it invokes the associated "personality routine", whose
-//! address is also stored in the unwind info section.
-//!
-//! In the search phase, the job of a personality routine is to examine exception
-//! object being thrown, and to decide whether it should be caught at that stack
-//! frame. Once the handler frame has been identified, cleanup phase begins.
-//!
-//! In the cleanup phase, personality routines invoke cleanup code associated
-//! with their stack frames (i.e. destructors). Once stack has been unwound down
-//! to the handler frame level, unwinding stops and the last personality routine
-//! transfers control to its catch block.
-//!
-//! ## Frame unwind info registration
-//!
-//! Each module has its own frame unwind info section (usually ".eh_frame"), and
-//! unwinder needs to know about all of them in order for unwinding to be able to
-//! cross module boundaries.
-//!
-//! On some platforms, like Linux, this is achieved by dynamically enumerating
-//! currently loaded modules via the dl_iterate_phdr() API and finding all
-//! .eh_frame sections.
-//!
-//! Others, like Windows, require modules to actively register their unwind info
-//! sections by calling __register_frame_info() API at startup. In the latter
-//! case it is essential that there is only one copy of the unwinder runtime in
-//! the process. This is usually achieved by linking to the dynamic version of
-//! the unwind runtime.
-//!
-//! Currently Rust uses unwind runtime provided by libgcc.
-
-use prelude::v1::*;
-
-use any::Any;
-use boxed;
-use cell::Cell;
-use cmp;
-use panicking;
-use fmt;
-use intrinsics;
-use libc::c_void;
-use mem;
-use sync::atomic::{self, Ordering};
-use sys_common::mutex::{Mutex, MUTEX_INIT};
-
-use rt::libunwind as uw;
-
-struct Exception {
- uwe: uw::_Unwind_Exception,
- cause: Option<Box<Any + Send + 'static>>,
-}
-
-pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: u32);
-
-// Variables used for invoking callbacks when a thread starts to unwind.
-//
-// For more information, see below.
-const MAX_CALLBACKS: usize = 16;
-static CALLBACKS: [atomic::AtomicUsize; MAX_CALLBACKS] =
- [atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT];
-static CALLBACK_CNT: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
-
-thread_local! { static PANICKING: Cell<bool> = Cell::new(false) }
-
-/// Invoke a closure, capturing the cause of panic if one occurs.
-///
-/// This function will return `Ok(())` if the closure did not panic, and will
-/// return `Err(cause)` if the closure panics. The `cause` returned is the
-/// object with which panic was originally invoked.
-///
-/// This function also is unsafe for a variety of reasons:
-///
-/// * This is not safe to call in a nested fashion. The unwinding
-/// interface for Rust is designed to have at most one try/catch block per
-/// thread, not multiple. No runtime checking is currently performed to uphold
-/// this invariant, so this function is not safe. A nested try/catch block
-/// may result in corruption of the outer try/catch block's state, especially
-/// if this is used within a thread itself.
-///
-/// * It is not sound to trigger unwinding while already unwinding. Rust threads
-/// have runtime checks in place to ensure this invariant, but it is not
-/// guaranteed that a rust thread is in place when invoking this function.
-/// Unwinding twice can lead to resource leaks where some destructors are not
-/// run.
-pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
- let mut f = Some(f);
-
- let prev = PANICKING.with(|s| s.get());
- PANICKING.with(|s| s.set(false));
- let ep = rust_try(try_fn::<F>, &mut f as *mut _ as *mut c_void);
- PANICKING.with(|s| s.set(prev));
- return if ep.is_null() {
- Ok(())
- } else {
- let my_ep = ep as *mut Exception;
- rtdebug!("caught {}", (*my_ep).uwe.exception_class);
- let cause = (*my_ep).cause.take();
- uw::_Unwind_DeleteException(ep);
- Err(cause.unwrap())
- };
-
- extern fn try_fn<F: FnOnce()>(opt_closure: *mut c_void) {
- let opt_closure = opt_closure as *mut Option<F>;
- unsafe { (*opt_closure).take().unwrap()(); }
- }
-
- #[link(name = "rustrt_native", kind = "static")]
- #[cfg(not(test))]
- extern {}
-
- extern {
- // Rust's try-catch
- // When f(...) returns normally, the return value is null.
- // When f(...) throws, the return value is a pointer to the caught
- // exception object.
- fn rust_try(f: extern fn(*mut c_void),
- data: *mut c_void) -> *mut uw::_Unwind_Exception;
- }
-}
-
-/// Determines whether the current thread is unwinding because of panic.
-pub fn panicking() -> bool {
- PANICKING.with(|s| s.get())
-}
-
-// An uninlined, unmangled function upon which to slap yer breakpoints
-#[inline(never)]
-#[no_mangle]
-#[allow(private_no_mangle_fns)]
-fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
- rtdebug!("begin_unwind()");
-
- unsafe {
- let exception: Box<_> = box Exception {
- uwe: uw::_Unwind_Exception {
- exception_class: rust_exception_class(),
- exception_cleanup: exception_cleanup,
- private: [0; uw::unwinder_private_data_size],
- },
- cause: Some(cause),
- };
- let exception_param = boxed::into_raw(exception) as *mut uw::_Unwind_Exception;
- let error = uw::_Unwind_RaiseException(exception_param);
- rtabort!("Could not unwind stack, error = {}", error as isize)
- }
-
- extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
- exception: *mut uw::_Unwind_Exception) {
- rtdebug!("exception_cleanup()");
- unsafe {
- let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
- }
- }
-}
-
-// Rust's exception class identifier. This is used by personality routines to
-// determine whether the exception was thrown by their own runtime.
-fn rust_exception_class() -> uw::_Unwind_Exception_Class {
- // M O Z \0 R U S T -- vendor, language
- 0x4d4f5a_00_52555354
-}
-
-// We could implement our personality routine in pure Rust, however exception
-// info decoding is tedious. More importantly, personality routines have to
-// handle various platform quirks, which are not fun to maintain. For this
-// reason, we attempt to reuse personality routine of the C language:
-// __gcc_personality_v0.
-//
-// Since C does not support exception catching, __gcc_personality_v0 simply
-// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
-// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
-//
-// This is pretty close to Rust's exception handling approach, except that Rust
-// does have a single "catch-all" handler at the bottom of each thread's stack.
-// So we have two versions of the personality routine:
-// - rust_eh_personality, used by all cleanup landing pads, which never catches,
-// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
-// - rust_eh_personality_catch, used only by rust_try(), which always catches.
-//
-// Note, however, that for implementation simplicity, rust_eh_personality_catch
-// lacks code to install a landing pad, so in order to obtain exception object
-// pointer (which it needs to return upstream), rust_try() employs another trick:
-// it calls into the nested rust_try_inner(), whose landing pad does not resume
-// unwinds. Instead, it extracts the exception pointer and performs a "normal"
-// return.
-//
-// See also: rt/rust_try.ll
-
-#[cfg(all(not(target_arch = "arm"),
- not(all(windows, target_arch = "x86_64")),
- not(test)))]
-#[doc(hidden)]
-pub mod eabi {
- use rt::libunwind as uw;
- use libc::c_int;
-
- extern "C" {
- fn __gcc_personality_v0(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
-
- #[lang = "eh_personality"]
- #[no_mangle] // referenced from rust_try.ll
- #[allow(private_no_mangle_fns)]
- extern fn rust_eh_personality(
- version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- unsafe {
- __gcc_personality_v0(version, actions, exception_class, ue_header,
- context)
- }
- }
-
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality_catch(
- _version: c_int,
- actions: uw::_Unwind_Action,
- _exception_class: uw::_Unwind_Exception_Class,
- _ue_header: *mut uw::_Unwind_Exception,
- _context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
-
- if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
- uw::_URC_HANDLER_FOUND // catch!
- }
- else { // cleanup phase
- uw::_URC_INSTALL_CONTEXT
- }
- }
-}
-
-// iOS on armv7 is using SjLj exceptions and therefore requires to use
-// a specialized personality routine: __gcc_personality_sj0
-
-#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
-#[doc(hidden)]
-pub mod eabi {
- use rt::libunwind as uw;
- use libc::c_int;
-
- extern "C" {
- fn __gcc_personality_sj0(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
-
- #[lang = "eh_personality"]
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality(
- version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- unsafe {
- __gcc_personality_sj0(version, actions, exception_class, ue_header,
- context)
- }
- }
-
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality_catch(
- _version: c_int,
- actions: uw::_Unwind_Action,
- _exception_class: uw::_Unwind_Exception_Class,
- _ue_header: *mut uw::_Unwind_Exception,
- _context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
- uw::_URC_HANDLER_FOUND // catch!
- }
- else { // cleanup phase
- unsafe {
- __gcc_personality_sj0(_version, actions, _exception_class, _ue_header,
- _context)
- }
- }
- }
-}
-
-
-// ARM EHABI uses a slightly different personality routine signature,
-// but otherwise works the same.
-#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
-#[doc(hidden)]
-pub mod eabi {
- use rt::libunwind as uw;
- use libc::c_int;
-
- extern "C" {
- fn __gcc_personality_v0(state: uw::_Unwind_State,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
-
- #[lang = "eh_personality"]
- #[no_mangle] // referenced from rust_try.ll
- #[allow(private_no_mangle_fns)]
- extern "C" fn rust_eh_personality(
- state: uw::_Unwind_State,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- unsafe {
- __gcc_personality_v0(state, ue_header, context)
- }
- }
-
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality_catch(
- state: uw::_Unwind_State,
- _ue_header: *mut uw::_Unwind_Exception,
- _context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- if (state as c_int & uw::_US_ACTION_MASK as c_int)
- == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase
- uw::_URC_HANDLER_FOUND // catch!
- }
- else { // cleanup phase
- uw::_URC_INSTALL_CONTEXT
- }
- }
-}
-
-// Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx)
-//
-// This looks a bit convoluted because rather than implementing a native SEH handler,
-// GCC reuses the same personality routine as for the other architectures by wrapping it
-// with an "API translator" layer (_GCC_specific_handler).
-
-#[cfg(all(windows, target_arch = "x86_64", not(test)))]
-#[doc(hidden)]
-#[allow(non_camel_case_types, non_snake_case)]
-pub mod eabi {
- pub use self::EXCEPTION_DISPOSITION::*;
- use rt::libunwind as uw;
- use libc::{c_void, c_int};
-
- #[repr(C)]
- pub struct EXCEPTION_RECORD;
- #[repr(C)]
- pub struct CONTEXT;
- #[repr(C)]
- pub struct DISPATCHER_CONTEXT;
-
- #[repr(C)]
- #[derive(Copy, Clone)]
- pub enum EXCEPTION_DISPOSITION {
- ExceptionContinueExecution,
- ExceptionContinueSearch,
- ExceptionNestedException,
- ExceptionCollidedUnwind
- }
-
- type _Unwind_Personality_Fn =
- extern "C" fn(
- version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code;
-
- extern "C" {
- fn __gcc_personality_seh0(
- exceptionRecord: *mut EXCEPTION_RECORD,
- establisherFrame: *mut c_void,
- contextRecord: *mut CONTEXT,
- dispatcherContext: *mut DISPATCHER_CONTEXT
- ) -> EXCEPTION_DISPOSITION;
-
- fn _GCC_specific_handler(
- exceptionRecord: *mut EXCEPTION_RECORD,
- establisherFrame: *mut c_void,
- contextRecord: *mut CONTEXT,
- dispatcherContext: *mut DISPATCHER_CONTEXT,
- personality: _Unwind_Personality_Fn
- ) -> EXCEPTION_DISPOSITION;
- }
-
- #[lang = "eh_personality"]
- #[no_mangle] // referenced from rust_try.ll
- #[allow(private_no_mangle_fns)]
- extern "C" fn rust_eh_personality(
- exceptionRecord: *mut EXCEPTION_RECORD,
- establisherFrame: *mut c_void,
- contextRecord: *mut CONTEXT,
- dispatcherContext: *mut DISPATCHER_CONTEXT
- ) -> EXCEPTION_DISPOSITION
- {
- unsafe {
- __gcc_personality_seh0(exceptionRecord, establisherFrame,
- contextRecord, dispatcherContext)
- }
- }
-
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality_catch(
- exceptionRecord: *mut EXCEPTION_RECORD,
- establisherFrame: *mut c_void,
- contextRecord: *mut CONTEXT,
- dispatcherContext: *mut DISPATCHER_CONTEXT
- ) -> EXCEPTION_DISPOSITION
- {
- extern "C" fn inner(
- _version: c_int,
- actions: uw::_Unwind_Action,
- _exception_class: uw::_Unwind_Exception_Class,
- _ue_header: *mut uw::_Unwind_Exception,
- _context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
- uw::_URC_HANDLER_FOUND // catch!
- }
- else { // cleanup phase
- uw::_URC_INSTALL_CONTEXT
- }
- }
-
- unsafe {
- _GCC_specific_handler(exceptionRecord, establisherFrame,
- contextRecord, dispatcherContext,
- inner)
- }
- }
-}
-
-#[cfg(not(test))]
-/// Entry point of panic from the libcore crate.
-#[lang = "panic_fmt"]
-pub extern fn rust_begin_unwind(msg: fmt::Arguments,
- file: &'static str, line: u32) -> ! {
- begin_unwind_fmt(msg, &(file, line))
-}
-
-/// The entry point for unwinding 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.
-#[inline(never)] #[cold]
-pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
- use fmt::Write;
-
- // 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_unwind
- // below).
-
- let mut s = String::new();
- let _ = s.write_fmt(msg);
- begin_unwind_inner(Box::new(s), file_line)
-}
-
-/// This is the entry point of unwinding for panic!() and assert!().
-#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
-pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, 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.
-
- // see below for why we do the `Any` coercion here.
- begin_unwind_inner(Box::new(msg), file_line)
-}
-
-/// The core of the unwinding.
-///
-/// This is non-generic to avoid instantiation bloat in other crates
-/// (which makes compilation of small crates noticeably slower). (Note:
-/// we need the `Any` object anyway, we're not just creating it to
-/// avoid being generic.)
-///
-/// Doing this split took the LLVM IR line counts of `fn main() { panic!()
-/// }` from ~1900/3700 (-O/no opts) to 180/590.
-#[inline(never)] #[cold] // this is the slow path, please never inline this
-fn begin_unwind_inner(msg: Box<Any + Send>,
- file_line: &(&'static str, u32)) -> ! {
- // Make sure the default failure handler is registered before we look at the
- // callbacks. We also use a raw sys-based mutex here instead of a
- // `std::sync` one as accessing TLS can cause weird recursive problems (and
- // we don't need poison checking).
- unsafe {
- static LOCK: Mutex = MUTEX_INIT;
- static mut INIT: bool = false;
- LOCK.lock();
- if !INIT {
- register(panicking::on_panic);
- INIT = true;
- }
- LOCK.unlock();
- }
-
- // First, invoke call the user-defined callbacks triggered on thread panic.
- //
- // By the time that we see a callback has been registered (by reading
- // MAX_CALLBACKS), the actual callback itself may have not been stored yet,
- // so we just chalk it up to a race condition and move on to the next
- // callback. Additionally, CALLBACK_CNT may briefly be higher than
- // MAX_CALLBACKS, so we're sure to clamp it as necessary.
- let callbacks = {
- let amt = CALLBACK_CNT.load(Ordering::SeqCst);
- &CALLBACKS[..cmp::min(amt, MAX_CALLBACKS)]
- };
- for cb in callbacks {
- match cb.load(Ordering::SeqCst) {
- 0 => {}
- n => {
- let f: Callback = unsafe { mem::transmute(n) };
- let (file, line) = *file_line;
- f(&*msg, file, line);
- }
- }
- };
-
- // Now that we've run all the necessary unwind callbacks, we actually
- // perform the unwinding.
- if panicking() {
- // 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.
- rterrln!("thread panicked while panicking. aborting.");
- unsafe { intrinsics::abort() }
- }
- PANICKING.with(|s| s.set(true));
- rust_panic(msg);
-}
-
-/// Register a callback to be invoked when a thread unwinds.
-///
-/// This is an unsafe and experimental API which allows for an arbitrary
-/// callback to be invoked when a thread panics. This callback is invoked on both
-/// the initial unwinding and a double unwinding if one occurs. Additionally,
-/// the local `Thread` will be in place for the duration of the callback, and
-/// the callback must ensure that it remains in place once the callback returns.
-///
-/// Only a limited number of callbacks can be registered, and this function
-/// returns whether the callback was successfully registered or not. It is not
-/// currently possible to unregister a callback once it has been registered.
-pub unsafe fn register(f: Callback) -> bool {
- match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) {
- // The invocation code has knowledge of this window where the count has
- // been incremented, but the callback has not been stored. We're
- // guaranteed that the slot we're storing into is 0.
- n if n < MAX_CALLBACKS => {
- let prev = CALLBACKS[n].swap(mem::transmute(f), Ordering::SeqCst);
- rtassert!(prev == 0);
- true
- }
- // If we accidentally bumped the count too high, pull it back.
- _ => {
- CALLBACK_CNT.store(MAX_CALLBACKS, Ordering::SeqCst);
- false
- }
- }
-}
--- /dev/null
+// Copyright 2015 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.
+
+use prelude::v1::*;
+
+use any::Any;
+use boxed;
+use libc::c_void;
+use rt::libunwind as uw;
+
+struct Exception {
+ uwe: uw::_Unwind_Exception,
+ cause: Option<Box<Any + Send + 'static>>,
+}
+
+pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
+ let exception: Box<_> = box Exception {
+ uwe: uw::_Unwind_Exception {
+ exception_class: rust_exception_class(),
+ exception_cleanup: exception_cleanup,
+ private: [0; uw::unwinder_private_data_size],
+ },
+ cause: Some(data),
+ };
+ let exception_param = boxed::into_raw(exception) as *mut uw::_Unwind_Exception;
+ let error = uw::_Unwind_RaiseException(exception_param);
+ rtabort!("Could not unwind stack, error = {}", error as isize);
+
+ extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
+ exception: *mut uw::_Unwind_Exception) {
+ rtdebug!("exception_cleanup()");
+ unsafe {
+ let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
+ }
+ }
+}
+
+pub unsafe fn cleanup(ptr: *mut c_void) -> Box<Any + Send + 'static> {
+ let my_ep = ptr as *mut Exception;
+ rtdebug!("caught {}", (*my_ep).uwe.exception_class);
+ let cause = (*my_ep).cause.take();
+ uw::_Unwind_DeleteException(ptr as *mut _);
+ cause.unwrap()
+}
+
+// Rust's exception class identifier. This is used by personality routines to
+// determine whether the exception was thrown by their own runtime.
+fn rust_exception_class() -> uw::_Unwind_Exception_Class {
+ // M O Z \0 R U S T -- vendor, language
+ 0x4d4f5a_00_52555354
+}
+
+// We could implement our personality routine in pure Rust, however exception
+// info decoding is tedious. More importantly, personality routines have to
+// handle various platform quirks, which are not fun to maintain. For this
+// reason, we attempt to reuse personality routine of the C language:
+// __gcc_personality_v0.
+//
+// Since C does not support exception catching, __gcc_personality_v0 simply
+// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
+// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
+//
+// This is pretty close to Rust's exception handling approach, except that Rust
+// does have a single "catch-all" handler at the bottom of each thread's stack.
+// So we have two versions of the personality routine:
+// - rust_eh_personality, used by all cleanup landing pads, which never catches,
+// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
+// - rust_eh_personality_catch, used only by rust_try(), which always catches.
+//
+// Note, however, that for implementation simplicity, rust_eh_personality_catch
+// lacks code to install a landing pad, so in order to obtain exception object
+// pointer (which it needs to return upstream), rust_try() employs another trick:
+// it calls into the nested rust_try_inner(), whose landing pad does not resume
+// unwinds. Instead, it extracts the exception pointer and performs a "normal"
+// return.
+//
+// See also: rt/rust_try.ll
+
+#[cfg(all(not(target_arch = "arm"),
+ not(all(windows, target_arch = "x86_64")),
+ not(test)))]
+pub mod eabi {
+ use rt::libunwind as uw;
+ use libc::c_int;
+
+ extern "C" {
+ fn __gcc_personality_v0(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code;
+ }
+
+ #[lang="eh_personality"]
+ #[no_mangle] // referenced from rust_try.ll
+ #[allow(private_no_mangle_fns)]
+ extern fn rust_eh_personality(
+ version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ unsafe {
+ __gcc_personality_v0(version, actions, exception_class, ue_header,
+ context)
+ }
+ }
+
+ #[no_mangle] // referenced from rust_try.ll
+ pub extern "C" fn rust_eh_personality_catch(
+ _version: c_int,
+ actions: uw::_Unwind_Action,
+ _exception_class: uw::_Unwind_Exception_Class,
+ _ue_header: *mut uw::_Unwind_Exception,
+ _context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+
+ if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+ uw::_URC_HANDLER_FOUND // catch!
+ }
+ else { // cleanup phase
+ uw::_URC_INSTALL_CONTEXT
+ }
+ }
+}
+
+// iOS on armv7 is using SjLj exceptions and therefore requires to use
+// a specialized personality routine: __gcc_personality_sj0
+
+#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
+pub mod eabi {
+ use rt::libunwind as uw;
+ use libc::c_int;
+
+ extern "C" {
+ fn __gcc_personality_sj0(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code;
+ }
+
+ #[lang="eh_personality"]
+ #[no_mangle] // referenced from rust_try.ll
+ pub extern "C" fn rust_eh_personality(
+ version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ unsafe {
+ __gcc_personality_sj0(version, actions, exception_class, ue_header,
+ context)
+ }
+ }
+
+ #[no_mangle] // referenced from rust_try.ll
+ pub extern "C" fn rust_eh_personality_catch(
+ _version: c_int,
+ actions: uw::_Unwind_Action,
+ _exception_class: uw::_Unwind_Exception_Class,
+ _ue_header: *mut uw::_Unwind_Exception,
+ _context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+ uw::_URC_HANDLER_FOUND // catch!
+ }
+ else { // cleanup phase
+ unsafe {
+ __gcc_personality_sj0(_version, actions, _exception_class, _ue_header,
+ _context)
+ }
+ }
+ }
+}
+
+
+// ARM EHABI uses a slightly different personality routine signature,
+// but otherwise works the same.
+#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
+pub mod eabi {
+ use rt::libunwind as uw;
+ use libc::c_int;
+
+ extern "C" {
+ fn __gcc_personality_v0(state: uw::_Unwind_State,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code;
+ }
+
+ #[lang="eh_personality"]
+ #[no_mangle] // referenced from rust_try.ll
+ #[allow(private_no_mangle_fns)]
+ extern "C" fn rust_eh_personality(
+ state: uw::_Unwind_State,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ unsafe {
+ __gcc_personality_v0(state, ue_header, context)
+ }
+ }
+
+ #[no_mangle] // referenced from rust_try.ll
+ pub extern "C" fn rust_eh_personality_catch(
+ state: uw::_Unwind_State,
+ _ue_header: *mut uw::_Unwind_Exception,
+ _context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ if (state as c_int & uw::_US_ACTION_MASK as c_int)
+ == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase
+ uw::_URC_HANDLER_FOUND // catch!
+ }
+ else { // cleanup phase
+ uw::_URC_INSTALL_CONTEXT
+ }
+ }
+}
+
+// Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx)
+//
+// This looks a bit convoluted because rather than implementing a native SEH
+// handler, GCC reuses the same personality routine as for the other
+// architectures by wrapping it with an "API translator" layer
+// (_GCC_specific_handler).
+
+#[cfg(all(windows, target_arch = "x86_64", not(test)))]
+#[doc(hidden)]
+#[allow(non_camel_case_types, non_snake_case)]
+pub mod eabi {
+ pub use self::EXCEPTION_DISPOSITION::*;
+ use rt::libunwind as uw;
+ use libc::{c_void, c_int};
+
+ #[repr(C)]
+ pub struct EXCEPTION_RECORD;
+ #[repr(C)]
+ pub struct CONTEXT;
+ #[repr(C)]
+ pub struct DISPATCHER_CONTEXT;
+
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub enum EXCEPTION_DISPOSITION {
+ ExceptionContinueExecution,
+ ExceptionContinueSearch,
+ ExceptionNestedException,
+ ExceptionCollidedUnwind
+ }
+
+ type _Unwind_Personality_Fn =
+ extern "C" fn(
+ version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code;
+
+ extern "C" {
+ fn __gcc_personality_seh0(
+ exceptionRecord: *mut EXCEPTION_RECORD,
+ establisherFrame: *mut c_void,
+ contextRecord: *mut CONTEXT,
+ dispatcherContext: *mut DISPATCHER_CONTEXT
+ ) -> EXCEPTION_DISPOSITION;
+
+ fn _GCC_specific_handler(
+ exceptionRecord: *mut EXCEPTION_RECORD,
+ establisherFrame: *mut c_void,
+ contextRecord: *mut CONTEXT,
+ dispatcherContext: *mut DISPATCHER_CONTEXT,
+ personality: _Unwind_Personality_Fn
+ ) -> EXCEPTION_DISPOSITION;
+ }
+
+ #[lang="eh_personality"]
+ #[no_mangle] // referenced from rust_try.ll
+ #[allow(private_no_mangle_fns)]
+ extern "C" fn rust_eh_personality(
+ exceptionRecord: *mut EXCEPTION_RECORD,
+ establisherFrame: *mut c_void,
+ contextRecord: *mut CONTEXT,
+ dispatcherContext: *mut DISPATCHER_CONTEXT
+ ) -> EXCEPTION_DISPOSITION
+ {
+ unsafe {
+ __gcc_personality_seh0(exceptionRecord, establisherFrame,
+ contextRecord, dispatcherContext)
+ }
+ }
+
+ #[no_mangle] // referenced from rust_try.ll
+ pub extern "C" fn rust_eh_personality_catch(
+ exceptionRecord: *mut EXCEPTION_RECORD,
+ establisherFrame: *mut c_void,
+ contextRecord: *mut CONTEXT,
+ dispatcherContext: *mut DISPATCHER_CONTEXT
+ ) -> EXCEPTION_DISPOSITION
+ {
+ extern "C" fn inner(
+ _version: c_int,
+ actions: uw::_Unwind_Action,
+ _exception_class: uw::_Unwind_Exception_Class,
+ _ue_header: *mut uw::_Unwind_Exception,
+ _context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+ uw::_URC_HANDLER_FOUND // catch!
+ }
+ else { // cleanup phase
+ uw::_URC_INSTALL_CONTEXT
+ }
+ }
+
+ unsafe {
+ _GCC_specific_handler(exceptionRecord, establisherFrame,
+ contextRecord, dispatcherContext,
+ inner)
+ }
+ }
+}
+
--- /dev/null
+// Copyright 2013 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 Rust stack unwinding
+//!
+//! For background on exception handling and stack unwinding please see
+//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
+//! documents linked from it.
+//! These are also good reads:
+//! http://theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/
+//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/
+//! http://www.airs.com/blog/index.php?s=exception+frames
+//!
+//! ## A brief summary
+//!
+//! Exception handling happens in two phases: a search phase and a cleanup phase.
+//!
+//! In both phases the unwinder walks stack frames from top to bottom using
+//! information from the stack frame unwind sections of the current process's
+//! modules ("module" here refers to an OS module, i.e. an executable or a
+//! dynamic library).
+//!
+//! For each stack frame, it invokes the associated "personality routine", whose
+//! address is also stored in the unwind info section.
+//!
+//! In the search phase, the job of a personality routine is to examine exception
+//! object being thrown, and to decide whether it should be caught at that stack
+//! frame. Once the handler frame has been identified, cleanup phase begins.
+//!
+//! In the cleanup phase, personality routines invoke cleanup code associated
+//! with their stack frames (i.e. destructors). Once stack has been unwound down
+//! to the handler frame level, unwinding stops and the last personality routine
+//! transfers control to its catch block.
+//!
+//! ## Frame unwind info registration
+//!
+//! Each module has its own frame unwind info section (usually ".eh_frame"), and
+//! unwinder needs to know about all of them in order for unwinding to be able to
+//! cross module boundaries.
+//!
+//! On some platforms, like Linux, this is achieved by dynamically enumerating
+//! currently loaded modules via the dl_iterate_phdr() API and finding all
+//! .eh_frame sections.
+//!
+//! Others, like Windows, require modules to actively register their unwind info
+//! sections by calling __register_frame_info() API at startup. In the latter
+//! case it is essential that there is only one copy of the unwinder runtime in
+//! the process. This is usually achieved by linking to the dynamic version of
+//! the unwind runtime.
+//!
+//! Currently Rust uses unwind runtime provided by libgcc.
+
+#![allow(dead_code)]
+#![allow(unused_imports)]
+
+use prelude::v1::*;
+
+use any::Any;
+use boxed;
+use cell::Cell;
+use cmp;
+use panicking;
+use fmt;
+use intrinsics;
+use libc::c_void;
+use mem;
+use sync::atomic::{self, Ordering};
+use sys_common::mutex::{Mutex, MUTEX_INIT};
+
+// The actual unwinding implementation is cfg'd here, and we've got two current
+// implementations. One goes through SEH on Windows and the other goes through
+// libgcc via the libunwind-like API.
+#[cfg(target_env = "msvc")] #[path = "seh.rs"] #[doc(hidden)]
+pub mod imp;
+#[cfg(not(target_env = "msvc"))] #[path = "gcc.rs"] #[doc(hidden)]
+pub mod imp;
+
+pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: u32);
+
+// Variables used for invoking callbacks when a thread starts to unwind.
+//
+// For more information, see below.
+const MAX_CALLBACKS: usize = 16;
+static CALLBACKS: [atomic::AtomicUsize; MAX_CALLBACKS] =
+ [atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
+ atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
+ atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
+ atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
+ atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
+ atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
+ atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
+ atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT];
+static CALLBACK_CNT: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
+
+thread_local! { static PANICKING: Cell<bool> = Cell::new(false) }
+
+#[link(name = "rustrt_native", kind = "static")]
+#[cfg(not(test))]
+extern {}
+
+/// Invoke a closure, capturing the cause of panic if one occurs.
+///
+/// This function will return `Ok(())` if the closure did not panic, and will
+/// return `Err(cause)` if the closure panics. The `cause` returned is the
+/// object with which panic was originally invoked.
+///
+/// This function also is unsafe for a variety of reasons:
+///
+/// * This is not safe to call in a nested fashion. The unwinding
+/// interface for Rust is designed to have at most one try/catch block per
+/// thread, not multiple. No runtime checking is currently performed to uphold
+/// this invariant, so this function is not safe. A nested try/catch block
+/// may result in corruption of the outer try/catch block's state, especially
+/// if this is used within a thread itself.
+///
+/// * It is not sound to trigger unwinding while already unwinding. Rust threads
+/// have runtime checks in place to ensure this invariant, but it is not
+/// guaranteed that a rust thread is in place when invoking this function.
+/// Unwinding twice can lead to resource leaks where some destructors are not
+/// run.
+pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
+ let mut f = Some(f);
+
+ let prev = PANICKING.with(|s| s.get());
+ PANICKING.with(|s| s.set(false));
+ let ep = rust_try(try_fn::<F>, &mut f as *mut _ as *mut c_void);
+ PANICKING.with(|s| s.set(prev));
+ return if ep.is_null() {
+ Ok(())
+ } else {
+ Err(imp::cleanup(ep))
+ };
+
+ extern fn try_fn<F: FnOnce()>(opt_closure: *mut c_void) {
+ let opt_closure = opt_closure as *mut Option<F>;
+ unsafe { (*opt_closure).take().unwrap()(); }
+ }
+
+ extern {
+ // Rust's try-catch
+ // When f(...) returns normally, the return value is null.
+ // When f(...) throws, the return value is a pointer to the caught
+ // exception object.
+ fn rust_try(f: extern fn(*mut c_void),
+ data: *mut c_void) -> *mut c_void;
+ }
+}
+
+/// Determines whether the current thread is unwinding because of panic.
+pub fn panicking() -> bool {
+ PANICKING.with(|s| s.get())
+}
+
+// An uninlined, unmangled function upon which to slap yer breakpoints
+#[inline(never)]
+#[no_mangle]
+#[allow(private_no_mangle_fns)]
+fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
+ rtdebug!("begin_unwind()");
+ unsafe {
+ imp::panic(cause)
+ }
+}
+
+#[cfg(not(test))]
+/// Entry point of panic from the libcore crate.
+#[lang = "panic_fmt"]
+pub extern fn rust_begin_unwind(msg: fmt::Arguments,
+ file: &'static str, line: u32) -> ! {
+ begin_unwind_fmt(msg, &(file, line))
+}
+
+/// The entry point for unwinding 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.
+#[inline(never)] #[cold]
+pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
+ use fmt::Write;
+
+ // 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_unwind
+ // below).
+
+ let mut s = String::new();
+ let _ = s.write_fmt(msg);
+ begin_unwind_inner(Box::new(s), file_line)
+}
+
+/// This is the entry point of unwinding for panic!() and assert!().
+#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
+pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, 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.
+
+ // see below for why we do the `Any` coercion here.
+ begin_unwind_inner(Box::new(msg), file_line)
+}
+
+/// The core of the unwinding.
+///
+/// This is non-generic to avoid instantiation bloat in other crates
+/// (which makes compilation of small crates noticeably slower). (Note:
+/// we need the `Any` object anyway, we're not just creating it to
+/// avoid being generic.)
+///
+/// Doing this split took the LLVM IR line counts of `fn main() { panic!()
+/// }` from ~1900/3700 (-O/no opts) to 180/590.
+#[inline(never)] #[cold] // this is the slow path, please never inline this
+fn begin_unwind_inner(msg: Box<Any + Send>,
+ file_line: &(&'static str, u32)) -> ! {
+ // Make sure the default failure handler is registered before we look at the
+ // callbacks. We also use a raw sys-based mutex here instead of a
+ // `std::sync` one as accessing TLS can cause weird recursive problems (and
+ // we don't need poison checking).
+ unsafe {
+ static LOCK: Mutex = MUTEX_INIT;
+ static mut INIT: bool = false;
+ LOCK.lock();
+ if !INIT {
+ register(panicking::on_panic);
+ INIT = true;
+ }
+ LOCK.unlock();
+ }
+
+ // First, invoke call the user-defined callbacks triggered on thread panic.
+ //
+ // By the time that we see a callback has been registered (by reading
+ // MAX_CALLBACKS), the actual callback itself may have not been stored yet,
+ // so we just chalk it up to a race condition and move on to the next
+ // callback. Additionally, CALLBACK_CNT may briefly be higher than
+ // MAX_CALLBACKS, so we're sure to clamp it as necessary.
+ let callbacks = {
+ let amt = CALLBACK_CNT.load(Ordering::SeqCst);
+ &CALLBACKS[..cmp::min(amt, MAX_CALLBACKS)]
+ };
+ for cb in callbacks {
+ match cb.load(Ordering::SeqCst) {
+ 0 => {}
+ n => {
+ let f: Callback = unsafe { mem::transmute(n) };
+ let (file, line) = *file_line;
+ f(&*msg, file, line);
+ }
+ }
+ };
+
+ // Now that we've run all the necessary unwind callbacks, we actually
+ // perform the unwinding.
+ if panicking() {
+ // 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.
+ rterrln!("thread panicked while panicking. aborting.");
+ unsafe { intrinsics::abort() }
+ }
+ PANICKING.with(|s| s.set(true));
+ rust_panic(msg);
+}
+
+/// Register a callback to be invoked when a thread unwinds.
+///
+/// This is an unsafe and experimental API which allows for an arbitrary
+/// callback to be invoked when a thread panics. This callback is invoked on both
+/// the initial unwinding and a double unwinding if one occurs. Additionally,
+/// the local `Thread` will be in place for the duration of the callback, and
+/// the callback must ensure that it remains in place once the callback returns.
+///
+/// Only a limited number of callbacks can be registered, and this function
+/// returns whether the callback was successfully registered or not. It is not
+/// currently possible to unregister a callback once it has been registered.
+pub unsafe fn register(f: Callback) -> bool {
+ match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) {
+ // The invocation code has knowledge of this window where the count has
+ // been incremented, but the callback has not been stored. We're
+ // guaranteed that the slot we're storing into is 0.
+ n if n < MAX_CALLBACKS => {
+ let prev = CALLBACKS[n].swap(mem::transmute(f), Ordering::SeqCst);
+ rtassert!(prev == 0);
+ true
+ }
+ // If we accidentally bumped the count too high, pull it back.
+ _ => {
+ CALLBACK_CNT.store(MAX_CALLBACKS, Ordering::SeqCst);
+ false
+ }
+ }
+}
--- /dev/null
+// Copyright 2015 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.
+
+use prelude::v1::*;
+
+use any::Any;
+use intrinsics;
+use libc::c_void;
+
+pub unsafe fn panic(_data: Box<Any + Send + 'static>) -> ! {
+ intrinsics::abort();
+}
+
+pub unsafe fn cleanup(_ptr: *mut c_void) -> Box<Any + Send + 'static> {
+ intrinsics::abort();
+}
+
+#[lang = "eh_personality"]
+#[no_mangle]
+pub extern fn rust_eh_personality() {}
+
+#[no_mangle]
+pub extern fn rust_eh_personality_catch() {}