Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues with crash handling for iOS for Rust 1.22.1 #46796

Open
michaeleiselsc opened this issue Dec 18, 2017 · 7 comments
Open

Issues with crash handling for iOS for Rust 1.22.1 #46796

michaeleiselsc opened this issue Dec 18, 2017 · 7 comments
Labels
A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) C-enhancement Category: An issue proposing an enhancement or a PR with one. O-ios Operating system: iOS T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@michaeleiselsc
Copy link

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.

@jonas-schievink
Copy link
Contributor

Unwinding across an FFI call is undefined behaviour

@michaeleiselsc
Copy link
Author

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?

@jonas-schievink
Copy link
Contributor

Probably. I think the backtrace crate does this.

@michaeleiselsc
Copy link
Author

According to the docs, that library doesn't support iOS.

@michaeleiselsc
Copy link
Author

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.

@frewsxcv frewsxcv added the O-ios Operating system: iOS label Dec 19, 2017
@XAMPPRocky XAMPPRocky added A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 26, 2018
@HackerFoo
Copy link

Using panic = 'abort' seems to give a better stack trace. The stack trace printed by panic is useless if you can't access console logs, and unwinding destroys most of the useful information.

@HackerFoo
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) C-enhancement Category: An issue proposing an enhancement or a PR with one. O-ios Operating system: iOS T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants