It looks like the __cxa_throw function in KSCrashMonitor_CPPException.c is not getting called when a C++ exception is thrown in an embedded framework, e.g. CrashLib in the Crash-Tester app.
I haven't been able to come up with a solution to this. To me it looks like any embedded library will always use __cxa_throw from libc++, and not the implementation in KSCrash.
Additionally: When an unhandled C++ exception is thrown in an embedded framework, KSCrash will crash during reporting, since stackCursor->advanceCursor will equal NULL in KSCrashReport.c:writeBacktrace().
Edit: Added information KSCrash crashing during reporting.
Any luck with this? I'm trying to integrate KSCrash in my app, but stuck because of embedded framework.
Please let me know if you have any work around for this.
No luck, and I don't believe it is possible, at least not in our use case. This is my understanding of the situation:
The way KSCrash records the stack trace is by creating its own implementation of __cxa_throw, which allow access to the stack before it is unwound by libc++. This works as long as KSCrash is statically linked with the C++ code, since the linker will find and use __cxa_throw form KSCrash instead of the implementation in libc++. But in the case of an embedded framework that links to libc++, the __cxa_throw implementation from libc++ will be used, since the framework doesn't know about the code in KSCrash. Maybe there is a work-around if you have control over the embedded framework, but this won't work in our use-case.
Please let me know if you figure out a solution.
I have control over the embedded framework. But not sure how to fix it.
I also tried PLCrashReporter, same problem with it.
Does this mean that KSCrash should ideally be built as a static library and linked into the application, to at least catch C++ exceptions thrown in the application code?
But that would still leave any exceptions thrown in any dynamic library uncaught by KSCrash if I understand your bug report correctly @pdrtrifork ? If we control the embedded dynamic libs, could we link in a static lib to each of them with just that __cxa_throw stub, which would just defer to a shared KSCrash handler?
Hah, so in investigating this I ended up here http://stackoverflow.com/questions/36846628/conditionally-overriding-cxa-throw, which was opened by our very own @kstenerud 馃槃
Anyways, PR #219 should at least prevent crashing during crash reporting.
@kstenerud I think this issue should be renamed to something like _"Missing stack traces for C++ exceptions thrown from images not statically linked with KSCrash"_. As far as I can tell, the __cxa_throw
override only works in the same image as KSCrash, so:
The latter would affect clients such as sentry-swift
, https://docs.sentry.io/clients/cocoa/, which embeds KSCrash as a framework.
After further investigation it seems my previous comment was incorrect:
I think this issue should be renamed to something like _"Missing stack traces for C++ exceptions thrown from images not statically linked with KSCrash"_.
In the case of KSCrash being linked into the main application as a static library:
MyApplication
(main.o
, libKSCrash.a
)libDynamicLibrary.dylib
(lib.o
)/usr/lib/libc++abi.dylib
Any exceptions thrown from MyApplication
will enter the libKSCrash.a::__cxa_throw
. In additions, since libKSCrash.a
declares __cxa_throw
as weak
, linking MyApplication
doesn't fail if main.o
has its own __cxa_throw
override. So far so good. However, as this bug report has observed, any exceptions thrown from libDynamicLibrary.dylib
will not trigger libKSCrash.a::__cxa_throw
, and will end up in /usr/lib/libc++abi.dylib::__cxa_throw
.
In the case of KSCrash being linked into the main application as a dynamic library:
MyApplication
(main.o
)libKSCrash.dylib
/usr/lib/libc++abi.dylib
libDynamicLibrary.dylib
(lib.o
)/usr/lib/libc++abi.dylib
Any exceptions thrown from MyApplication
will enter the libKSCrash.dylib::__cxa_throw
, but only if:
__cxa_throw
is exported from libKSCrash.dylib
__cxa_throw
is not marked as weak
If __cxa_throw
is marked as weak
(0000000000002e90 (__TEXT,__text) weak external ___cxa_throw
), then when linking libKSCrash.dylib
the linker seems to look at /usr/lib/libc++abi.dylib
, find a non-weak __cxa_throw
, and conclude that libKSCrash.dylib::__cxa_throw
should be ignored. During runtime symbol lookup at throw time from MyApplication
, libKSCrash.dylib::__cxa_throw
is then ignored.
This leads me to belive that the weak
attribute should be conditionally added only when building KSCrash as a static library.
Like for the first usecase, any exceptions thrown from libDynamicLibrary.dylib
will not trigger libKSCrash.dylib::__cxa_throw
, and will end up in /usr/lib/libc++abi.dylib::__cxa_throw
.
This issue could potentially be fixed with some low level runtime patching of loaded images with undefined references to __cxa_throw
. Using the test application referenced in the article I've verified that the technique does indeed work for __cxa_throw
as well.
I'm trying to check crash in a framework in my app. When I try to get the crash log I see that stack trace is not showing the actual crash, instead KSCrash is crashing.
Is this the same issue?
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x0000000181cc5348 0x181ca4000 + 136008 (__pthread_kill + 8)
1 libsystem_pthread.dylib 0x0000000181ddd7a4 0x181dd6000 + 30628 ( + 360)
2 libsystem_c.dylib 0x0000000181c34fd8 0x181bd2000 + 405464 (abort + 140)
3 libc++abi.dylib 0x0000000181698068 0x181696000 + 8296 ( + 132)
4 libc++abi.dylib 0x0000000181698210 0x181696000 + 8720 ( + 304)
5 libobjc.A.dylib 0x00000001816c0810 0x1816b8000 + 34832 ( + 124)
6 KSCrash 0x00000001054a0590 0x10549c000 + 17808 (kscm_cppexception_getAPI + 280)
7 libc++abi.dylib 0x00000001816b054c 0x181696000 + 107852 ( + 16)
8 libc++abi.dylib 0x00000001816b0158 0x181696000 + 106840 (__cxa_rethrow + 144)
9 libobjc.A.dylib 0x00000001816c06e8 0x1816b8000 + 34536 (objc_exception_rethrow + 44)
10 CoreFoundation 0x0000000182072344 0x18206a000 + 33604 (CFRunLoopRunSpecific + 544)
11 GraphicsServices 0x0000000183f03f84 0x183ef9000 + 44932 (GSEventRunModal + 100)
12 UIKit 0x000000018b61e880 0x18b5ab000 + 473216 (UIApplicationMain + 208)
@torarnv Hi, could you share your successful mach-o-hook demo with us? I ran into EXC_BAD_ACCESS when I try to mach_hook
__cxa_throw.
void ter_handler(){
printf("custom handler\n");
}
void test(){
throw std::runtime_error("test function");
}
static void (*orig_throw)(void * thrown_exception, std::type_info *tinfo, void (*dest)(void *));
void hooked_throw(void * thrown_exception, std::type_info *tinfo, void (*dest)(void *)){
printf("hooked_throw...\n");
return orig_throw(thrown_exception, tinfo, dest);
}
int main(int argc, char * argv[])
{
@autoreleasepool {
struct rebinding binds[1];
struct rebinding bind1 = {"__cxa_throw", (void *)hooked_throw, (void **)&orig_throw};
binds[0] = bind1;
rebind_symbols(binds, 1);
std::set_terminate(ter_handler);
try {
throw std::runtime_error("test error");
}
catch (...){
printf ("catch exception\n");
}
test();
}
}
try this... good luck
I meet one crash with KSCrash ,
how to resolve it?
We've created a PR implementing dynamic hook mentioned above by @huakucha: #375
Most helpful comment
After further investigation it seems my previous comment was incorrect:
In the case of KSCrash being linked into the main application as a static library:
MyApplication
(main.o
,libKSCrash.a
)libDynamicLibrary.dylib
(lib.o
)/usr/lib/libc++abi.dylib
Any exceptions thrown from
MyApplication
will enter thelibKSCrash.a::__cxa_throw
. In additions, sincelibKSCrash.a
declares__cxa_throw
asweak
, linkingMyApplication
doesn't fail ifmain.o
has its own__cxa_throw
override. So far so good. However, as this bug report has observed, any exceptions thrown fromlibDynamicLibrary.dylib
will not triggerlibKSCrash.a::__cxa_throw
, and will end up in/usr/lib/libc++abi.dylib::__cxa_throw
.In the case of KSCrash being linked into the main application as a dynamic library:
MyApplication
(main.o
)libKSCrash.dylib
/usr/lib/libc++abi.dylib
libDynamicLibrary.dylib
(lib.o
)/usr/lib/libc++abi.dylib
Any exceptions thrown from
MyApplication
will enter thelibKSCrash.dylib::__cxa_throw
, but only if:__cxa_throw
is exported fromlibKSCrash.dylib
__cxa_throw
is not marked asweak
If
__cxa_throw
is marked asweak
(0000000000002e90 (__TEXT,__text) weak external ___cxa_throw
), then when linkinglibKSCrash.dylib
the linker seems to look at/usr/lib/libc++abi.dylib
, find a non-weak__cxa_throw
, and conclude thatlibKSCrash.dylib::__cxa_throw
should be ignored. During runtime symbol lookup at throw time fromMyApplication
,libKSCrash.dylib::__cxa_throw
is then ignored.This leads me to belive that the
weak
attribute should be conditionally added only when building KSCrash as a static library.Like for the first usecase, any exceptions thrown from
libDynamicLibrary.dylib
will not triggerlibKSCrash.dylib::__cxa_throw
, and will end up in/usr/lib/libc++abi.dylib::__cxa_throw
.This issue could potentially be fixed with some low level runtime patching of loaded images with undefined references to
__cxa_throw
. Using the test application referenced in the article I've verified that the technique does indeed work for__cxa_throw
as well.