| use alloc::string::String; | |
| use core::mem::transmute; | |
| use core::panic::PanicPayload; | |
| 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 might 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 dyn PanicPayload) { | |
| let func_addr = unsafe { | |
| 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::<String>() { | |
| 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 = unsafe { libc::malloc(size) as *mut libc::c_char }; | |
| if buf.is_null() { | |
| return; // allocation failure | |
| } | |
| unsafe { | |
| copy_nonoverlapping(msg.as_ptr(), buf as *mut u8, msg.len()); | |
| buf.add(msg.len()).write(0); | |
| let func = transmute::<usize, SetAbortMessageType>(func_addr); | |
| func(buf); | |
| } | |
| } |