Issues with crash handling for iOS for Rust 1.22.1
I'm using rustc 1.22.1 (05e2e1c41 2017-11-22) and I'm calling a simple rust function from my iOS app that just panics. The rust function is in a static library and is compiled cargo build (debug with -O0). The architecture is aarch64-apple-ios. Here's the rust code:
extern crate rand;
pub struct MyStruct {
i: i32,
}
impl MyStruct {
pub fn do_stuff(&mut self) -> String {
panic!("that was a fail");
return String::from("asdf");
}
}
#[no_mangle]
pub extern fn panicky_fn() {
let mut m = MyStruct {
i: 0
};
m.do_stuff();
}
When I call it like this, from my root view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
[Fabric with:@[ [Crashlytics class]]]; // start the crash reporter
CFTimeInterval start = CACurrentMediaTime();
srand(time(NULL));
if (rand() % 2 == 0) {
panicky_fn();
}
// more code...
}
Then when the panic occurs, in the left-hand pane of Xcode, it just shows me this generic trace:
#0 0x00000001838e9348 in __pthread_kill ()
#1 0x00000001839fd354 in pthread_kill$VARIANT$mp ()
#2 0x0000000183858fd8 in abort ()
#3 0x00000001832bc068 in abort_message ()
#4 0x00000001832bc16c in default_terminate_handler() ()
#5 0x00000001832d454c in std::__terminate(void (*)()) ()
#6 0x00000001832d45c0 in std::terminate() ()
#7 0x00000001832e476c in objc_terminate ()
#8 0x0000000104651470 in _dispatch_client_callout ()
#9 0x000000010465db74 in _dispatch_block_invoke_direct ()
#10 0x00000001864a5a04 in __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ ()
#11 0x00000001864a56a8 in -[FBSSerialQueue _performNext] ()
#12 0x00000001864a5c44 in -[FBSSerialQueue _performNextFromRunLoopSource] ()
#13 0x0000000183d78358 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()
#14 0x0000000183d782d8 in __CFRunLoopDoSource0 ()
#15 0x0000000183d77b60 in __CFRunLoopDoSources0 ()
#16 0x0000000183d75738 in __CFRunLoopRun ()
#17 0x0000000183c962d8 in CFRunLoopRunSpecific ()
#18 0x0000000185b27f84 in GSEventRunModal ()
#19 0x000000018d243880 in UIApplicationMain ()
#20 0x0000000104219b68 in main at /Users/michael/Snapchat/Dev/Rotationization/Rotationization/main.m:15
#21 0x00000001837ba56c in start ()
And in the crash reporting service, Crashlytics, I just see a stack trace just like it. However, when I wrap the call to the rust function like so:
dispatch_async(dispatch_get_main_queue(), ^{
panicky_fn();
}
Then both the left-hand pane of Xcode as well as the crash reporting service show the correct stack trace. Can anyone help with this? I want to start using Rust in my app, but I don't feel comfortable doing so until I can monitor crashes with it.
Unwinding across an FFI call is undefined behaviour
Jonas Schievink at 2017-12-18 00:25:38
Would it be safe to at least call the C backtrace function at that moment to get a backtrace that I can then use for crash reporting?
Michael Eisel at 2017-12-18 00:54:28
Probably. I think the backtrace crate does this.
Jonas Schievink at 2017-12-18 01:09:28
According to the docs, that library doesn't support iOS.
Michael Eisel at 2017-12-18 01:11:35
Also, according to the docs for
resume_unwind, it can be used to carry a panic across a layer of C, is that referring to if you have rust code -> C code -> rust code, then in that last layer it would use resume_unwind to jump to first layer somehow?The reason I'm so curious is that, without good crash reporting for rust in iOS, I don't see how I can deploy any sort of large-scale app.
Michael Eisel at 2017-12-18 01:18:00
Using
panic = 'abort'seems to give a better stack trace. The stack trace printed bypanicis useless if you can't access console logs, and unwinding destroys most of the useful information.Dusty DeWeese at 2022-04-12 23:23:25
I thought this fixed it, but it wasn't enough. Based on a Stack Overflow thread, I think I've found a solution.
In Rust:
extern "C" { fn platform_panic(); } pub fn main() { std::panic::set_hook(Box::new(|_| unsafe { platform_panic(); })); // stuff that might panic }and in Swift:
@_cdecl("platform_panic") func platform_panic() { DispatchQueue.global(qos: .userInteractive) .sync { fatalError() } }Now, the actual
panic!()line is in the stack trace.Dusty DeWeese at 2022-04-13 02:43:23