When Kotlin throws an exception in my iOS and macO...
# kotlin-native
c
When Kotlin throws an exception in my iOS and macOS app and it is unhandled, the crash report is not super helpful at the moment The stack track is in
Kotlin_ObjCExport_trapOnUndeclaredException
and the “Application Specific Information” which normally contains the exception message (for Swift traps and Objective-C exceptions) just shows
abort() called
Is there a way to put the Kotlin exception message inside of the crash report?
a
We’ve used CrashKiOS for this: https://github.com/touchlab/CrashKiOS I believe it’s also integrated into Kermit?
r
I don't believe there is. If I remember correctly folks at Touchlab actually log the unhandeled exceptions at the Kotlin side in their Kermit library. https://github.com/touchlab/Kermit
c
There is
setUnhandledExceptionHook
(which is what they use), so perhaps I could take the exception and crash myself in a way that reports the exception message correctly I do wonder how “Application Specific Information” is populated, though, and if there is a way to get this functionality into Kotlin itself
Because other information goes in there, like the “dyld4 config” and the current selector being performed by AppKit if present
r
Yeah. Maybe if you convert the exception to an
NSError
and then send it to ObjC/Swift. From there you could basically throw it or something to get the "normal behavior". Not sure if that would actually work but might be worth to try.
c
I could generate an NSException and throw it
👌 1
👀 1
Looks like it is private API, but it is a DATA section of the process that Swift fills out before aborting (
__crash_info
)
I’ll write a Kotlin library to populate that in the hook and actually let Kotlin finish the abort
🙌🏻 2
Wireshark, Firefox, etc all have implementations of it: https://github.com/wireshark/wireshark/blob/master/wsutil/crash_info.c
a
Nice, maybe worth checking with @kpgalligan to see if they’d considered adding that to crashkios and ruled it out for some reason
r
Very interesting! Looks like even more info could be attached (like the app specific backtrace).
k
Interesting. We haven't done that. Obviously I'd be very interested to see what you come up with. On my phone now but will look at source linked when back on the computer
c
Funnily enough, Kotlin tries to do it itself, but it looks like the private API they were using may have broken: https://github.com/JetBrains/kotlin/blob/4c3fb8697b0a2b4bb504557427ec309aedffeaac/kotlin-native/runtime/src/main/cpp/ObjCExceptions.cpp#L100
Actually, they don’t enable that for macOS
k
That exception writing from the kotlin runtime has been there for years. I don’t know if the api is currently broken, but it used to write to your local device (or the buffer it wrote to wrote to your local device). It never surfaced to remote exception loggers (Crashlytics, etc), which was (is) our goal, so we didn’t try too much with it.
I’ve been poking around this since you posted, so I have some more thoughts (and old things coming back from long term memory).
Now, is it possible that I’m just looking in the wrong place? Absolutely. I’m not sure when I’ll get time to finish it, but I’ve been setting up a little C code to write to those fields and see what comes out, but C isn’t exactly my strong suit, and obviously there isn’t a lot of documentation out there, so we’ll see.
From what I can tell, Crashlytics grabs the state of all threads stacktraces at abort time and writes them out, so for our purposes (full stack trace), I don’t think it’ll work.
My approach prior to this thread was appending the stack info before sending the crash. Bugsnag at least lets you inspect and modify crash reports before they’re sent to the server, so the Kotlin unhandled exception callback can write the Kotlin stack, and add it after restart, but there’s a lot left to figure out there, and I’m not sure Crashlytics or others allow the same.
It does technically work, though.
However, looking back on the thread, I don’t think you cared so much about remote tools? On the
__crash_info
, I think the piece, or one of the pieces, that I’m missing is what actually gets put in there, and who is intended to read it? I did go through the wireshark and firefox code, but only lightly. I’m definitely not set up for local native dev like that, so I’ve just been reading source. I think writing to it would be easy enough if I understand what’s happening, although I wouldn’t know what to write. Also, I have that background concern of if this is actually a private api, does that mess with app store submissions? That last one is a bit down the road as far as worries go, but still.
Anyway, that’s where I’m at this morning. I rabbit holed a bit on this yesterday, but there’s a whole bunch of things I really should be focused on this week, so I’m probably not going to make much progress for a bit.
r
Also, I have that background concern of if this is actually a private api, does that mess with app store submissions?
As long as Swift is using the same that shouldn’t be an issue, right? Also if Crashlytics is aware of it then it’s already part of your app.
k
It doesn’t seem like
__crash_info
is a problem, but I’m not sure that it’s considered private either. Poorly documented for sure, but not sure it’s something Apple cares about. but, again, I’m also not sure it’ll do much for the crash reports, at least for stack traces.
👍 1
r
Bugsnag at least lets you inspect and modify crash reports before they’re sent to the server … and I’m not sure Crashlytics or others allow the same.
Yes if automatic collection is disabled you can update the report before it’s send: https://firebase.google.com/docs/reference/swift/firebasecrashlytics/api/reference/Classes/Crashlytics#checkandupdateunsentreports Though there is no field for a stacktrace, but you could add it as logs or as a custom value or something.
c
Yeah, a few things: • I care primarily about local crash reports. I run UI integration tests on GitHub actions and my app crashes in one, but the report in the xcresult was useless, which is why I am looking into this in the first place • As for reporting, I am always just going to use Apple’s crash reporting functionality. On macOS I might have a custom reporting functionality, but it will still use the Apple crash reports that are written to disk. Out of process crash reporting is just more robust • The backtrace functionality does work – NSException actually uses it. I remember reading a lot of “Application Specific Backtrace” sections when I was reading reports at Apple. I plan on populating it with the Kotlin exception’s backtrace • Kotlin’s built in exception reporting is very much a hack. I'll likely write a diff for the Kotlin runtime to use crash_info (as that is where it belongs, in the runtime), but compiling Kotlin sounds like a PITA • Haven't gotten it working locally quite yet, but working on it
k
when I was reading reports at Apple
Apologies in advance for the endless list of questions I might throw at you in the future
As for reporting, I am always just going to use Apple’s crash reporting functionality
We’re primarily focused on 3rd party tools, but that’s mostly because that’s what our clients are using. Certainly interested to see what you figure out.
The backtrace functionality does work – NSException actually uses it. I remember reading a lot of “Application Specific Backtrace” sections
I’d definitely love to see how this works. The apple-side internals are a bit out of my wheelhouse, and I’m not sure the 3rd party tools wouldn’t report this, but would need to try it and see how it goes.
I’ll likely write a diff for the Kotlin runtime to use crash_info (as that is where it belongs, in the runtime), but compiling Kotlin sounds like a PITA
I wouldn’t say compiling Kotlin is the easiest, but it’s not too bad once you get it set up. We’re hacking around compiler changes now. If you have thoughts on what that should look like we might be able to try some things our, or just assist getting local dev working for you if needed.
c
I got it working in pure Kotlin. Originally, I had some C code to generate a
__crash___info
section, but the crash info section seemingly only gets checked for system libraries. I updated the code to find an existing section in a system library and write to that
k
That’s interesting. This is definitely a bit out of my wheelhouse, but I’m surprised you can write that to a system library. I’d definitely like to try this out if you make anything public and/or just post some code. I’d like to see if the crash reporting libraries we’re using pick up that data.
👍 1
c
It is the data section of a system library, which is read write (it writes to it just as the system library itself would) but yes! I am landing it in my codebase first: https://github.com/conradev/Wallet/pull/9/files but I will consider making it into a Kotlin library that people can drop in later – have never made or setup a Kotlin library on Github before
👀 1
Firefox and Chrome both have functionality to read the info out, at least the message part
k
Yeah, I saw that for both. Crashlytics does that too, but again, just the message. Not sure they don’t also get the rest, but the only code that used the defined structure for that data type (that I could find) was pulling the message string. We also use bugsnag and I haven’t started poking around the client code for that. In any case, I’d love to see if anything interesting makes its way out after stuffing data in.
I was curious about the signature. Wasn’t sure if one needed to worry about that. Guess not 🙂
If you want to do a library, we work on that quite a bit, so can chat/answer questions.
There’s not much different, except sometimes publishing.