diff --git a/Cargo.lock b/Cargo.lock index 2b7fbf1b647..e892d87245c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2492,6 +2492,7 @@ dependencies = [ name = "panic_abort" version = "0.0.0" dependencies = [ + "alloc", "cfg-if 0.1.10", "compiler_builtins", "core", diff --git a/library/panic_abort/Cargo.toml b/library/panic_abort/Cargo.toml index caa89aa30d0..bdab664cd64 100644 --- a/library/panic_abort/Cargo.toml +++ b/library/panic_abort/Cargo.toml @@ -13,6 +13,7 @@ bench = false doc = false [dependencies] +alloc = { path = "../alloc" } cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } core = { path = "../core" } libc = { version = "0.2", default-features = false } diff --git a/library/panic_abort/src/android.rs b/library/panic_abort/src/android.rs new file mode 100644 index 00000000000..34d77502eab --- /dev/null +++ b/library/panic_abort/src/android.rs @@ -0,0 +1,49 @@ +use alloc::string::String; +use core::mem::transmute; +use core::panic::BoxMeUp; +use core::ptr::copy_nonoverlapping; + +const ANDROID_SET_ABORT_MESSAGE: &[u8] = b"android_set_abort_message\0"; +type SetAbortMessageType = unsafe extern "C" fn(*const libc::c_char) -> (); + +// Forward the abort message to libc's android_set_abort_message. We try our best to populate the +// message but as this function may already be called as part of a failed allocation, it may not be +// possible to do so. +// +// Some methods of core are on purpose avoided (such as try_reserve) as these rely on the correct +// resolution of rust_eh_personality which is loosely defined in panic_abort. +// +// Weakly resolve the symbol for android_set_abort_message. This function is only available +// for API >= 21. +pub(crate) unsafe fn android_set_abort_message(payload: *mut &mut dyn BoxMeUp) { + let func_addr = + libc::dlsym(libc::RTLD_DEFAULT, ANDROID_SET_ABORT_MESSAGE.as_ptr() as *const libc::c_char) + as usize; + if func_addr == 0 { + return; + } + + let payload = (*payload).get(); + let msg = match payload.downcast_ref::<&'static str>() { + Some(msg) => msg.as_bytes(), + None => match payload.downcast_ref::() { + Some(msg) => msg.as_bytes(), + None => &[], + }, + }; + if msg.is_empty() { + return; + } + + // Allocate a new buffer to append the null byte. + let size = msg.len() + 1usize; + let buf = libc::malloc(size) as *mut libc::c_char; + if buf.is_null() { + return; // allocation failure + } + copy_nonoverlapping(msg.as_ptr(), buf as *mut u8, msg.len()); + buf.offset(msg.len() as isize).write(0); + + let func = transmute::(func_addr); + func(buf); +} diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index eb2277d8baa..5dcd1e6af36 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -19,6 +19,9 @@ #![feature(rustc_attrs)] #![feature(asm)] +#[cfg(target_os = "android")] +mod android; + use core::any::Any; use core::panic::BoxMeUp; @@ -31,6 +34,10 @@ pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Sen // "Leak" the payload and shim to the relevant abort on the platform in question. #[rustc_std_internal_symbol] pub unsafe extern "C" fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 { + // Android has the ability to attach a message as part of the abort. + #[cfg(target_os = "android")] + android::android_set_abort_message(_payload); + abort(); cfg_if::cfg_if! {