Es sieht so aus, als ob die __cxa_throw-Funktion in KSCrashMonitor_CPPException.c nicht aufgerufen wird, wenn eine C++-Ausnahme in einem eingebetteten Framework geworfen wird, zB CrashLib in der Crash-Tester-App.
Ich bin nicht in der Lage gewesen, eine Lösung dafür zu finden. Für mich sieht es so aus, als würde jede eingebettete Bibliothek immer __cxa_throw von libc++ verwenden und nicht die Implementierung in KSCrash.
Zusätzlich: Wenn eine unbehandelte C++-Ausnahme in einem eingebetteten Framework ausgelöst wird, stürzt KSCrash während der Berichterstellung ab, da stackCursor->advanceCursor in KSCrashReport.c:writeBacktrace() gleich NULL ist.
Bearbeiten: Information hinzugefügt, dass KSCrash während der Berichterstellung abstürzt.
Glück damit? Ich versuche, KSCrash in meine App zu integrieren, bin aber wegen des eingebetteten Frameworks hängen geblieben.
Bitte lassen Sie mich wissen, ob Sie dafür eine Arbeit haben.
Kein Glück, und ich glaube nicht, dass es möglich ist, zumindest nicht in unserem Anwendungsfall. So verstehe ich die Situation:
Die Art und Weise, wie KSCrash den Stack-Trace aufzeichnet, besteht darin, eine eigene Implementierung von __cxa_throw zu erstellen, die den Zugriff auf den Stack ermöglicht, bevor er von libc++ entladen wird. Dies funktioniert, solange KSCrash statisch mit dem C++-Code gelinkt ist, da der Linker __cxa_throw von KSCrash anstelle der Implementierung in libc++ finden und verwenden wird. Aber im Fall eines eingebetteten Frameworks, das auf libc++ verlinkt, wird die __cxa_throw-Implementierung von libc++ verwendet, da das Framework den Code in KSCrash nicht kennt. Vielleicht gibt es eine Problemumgehung, wenn Sie die Kontrolle über das eingebettete Framework haben, aber das funktioniert in unserem Anwendungsfall nicht.
Bitte lassen Sie mich wissen, wenn Sie eine Lösung finden.
Ich habe die Kontrolle über das eingebettete Framework. Aber nicht sicher, wie man es repariert.
Ich habe auch PLCrashReporter ausprobiert, das gleiche Problem damit.
Bedeutet dies, dass KSCrash idealerweise als statische Bibliothek erstellt und in die Anwendung eingebunden werden sollte, um zumindest im Anwendungscode ausgelöste C++-Ausnahmen abzufangen?
Aber das würde immer noch Ausnahmen hinterlassen, die in einer dynamischen Bibliothek ausgelöst werden, die von KSCrash nicht erfasst wird, wenn ich Ihren Fehlerbericht richtig verstehe @pdrtrifork ? Wenn wir die eingebetteten dynamischen Bibliotheken kontrollieren, könnten wir eine statische Bibliothek mit nur diesem __cxa_throw-Stub zu jeder von ihnen verlinken, was nur zu einem gemeinsam genutzten KSCrash-Handler führen würde?
Hah, also bin ich bei der Untersuchung hier gelandet http://stackoverflow.com/questions/36846628/conditionally-overriding-cxa-throw , das von unserem eigenen @kstenerud 😄 geöffnet wurde
Wie auch immer, PR #219 sollte zumindest Abstürze während der Absturzmeldung verhindern.
@kstenerud Ich denke, dieses Problem sollte umbenannt werden in etwas wie _"Fehlende Stack-Traces für C++-Ausnahmen, die von Bildern ausgelöst werden, die nicht statisch mit KSCrash verknüpft sind"_. Soweit ich das beurteilen kann, funktioniert die Überschreibung __cxa_throw
nur im selben Image wie KSCrash, also:
Letzteres würde Clients wie sentry-swift
, https://docs.sentry.io/clients/cocoa/ betreffen, die KSCrash als Framework einbetten.
Nach weiteren Nachforschungen scheint mein vorheriger Kommentar falsch gewesen zu sein:
Ich denke, dieses Problem sollte umbenannt werden in so etwas wie _"Fehlende Stack-Traces für C++-Ausnahmen, die von Bildern ausgelöst werden, die nicht statisch mit KSCrash verknüpft sind"_.
Falls KSCrash als statische Bibliothek in die Hauptanwendung eingebunden wird:
MyApplication
( main.o
, libKSCrash.a
)libDynamicLibrary.dylib
( lib.o
)/usr/lib/libc++abi.dylib
Alle Ausnahmen, die von MyApplication
ausgelöst werden, werden in libKSCrash.a::__cxa_throw
. Da außerdem libKSCrash.a
__cxa_throw
als weak
$ deklariert, schlägt das Verknüpfen MyApplication
nicht fehl, wenn main.o
ein eigenes __cxa_throw
hat libDynamicLibrary.dylib
ausgelösten Ausnahmen nicht libKSCrash.a::__cxa_throw
aus und landen in /usr/lib/libc++abi.dylib::__cxa_throw
.
Falls KSCrash als dynamische Bibliothek in die Hauptanwendung eingebunden wird:
MyApplication
( main.o
)libKSCrash.dylib
/usr/lib/libc++abi.dylib
libDynamicLibrary.dylib
( lib.o
)/usr/lib/libc++abi.dylib
Alle Ausnahmen, die von MyApplication
ausgelöst werden, werden in libKSCrash.dylib::__cxa_throw
, aber nur, wenn:
__cxa_throw
wird aus libKSCrash.dylib
exportiert__cxa_throw
ist nicht als weak
gekennzeichnetWenn __cxa_throw
als weak
( 0000000000002e90 (__TEXT,__text) weak external ___cxa_throw
) markiert ist, dann scheint der Linker beim Verknüpfen libKSCrash.dylib
nach /usr/lib/libc++abi.dylib
zu suchen und einen Non zu finden -weak __cxa_throw
und schließen daraus, dass libKSCrash.dylib::__cxa_throw
ignoriert werden sollte. Während der Laufzeitsymbolsuche zur Auslösezeit von MyApplication
wird libKSCrash.dylib::__cxa_throw
dann ignoriert.
Dies lässt mich glauben, dass das Attribut weak
nur bedingt hinzugefügt werden sollte, wenn KSCrash als statische Bibliothek erstellt wird.
Wie beim ersten Anwendungsfall lösen alle von libDynamicLibrary.dylib
ausgelösten Ausnahmen nicht libKSCrash.dylib::__cxa_throw
aus und landen in /usr/lib/libc++abi.dylib::__cxa_throw
.
Dieses Problem könnte möglicherweise durch ein Low-Level-Patch zur Laufzeit von geladenen Images mit undefinierten Verweisen auf __cxa_throw
behoben werden. Mit der Testanwendung, auf die im Artikel verwiesen wird, habe ich verifiziert, dass die Technik tatsächlich auch für __cxa_throw
funktioniert.
Ich versuche, den Absturz in einem Framework in meiner App zu überprüfen. Wenn ich versuche, das Absturzprotokoll abzurufen, sehe ich, dass der Stack-Trace nicht den tatsächlichen Absturz anzeigt, stattdessen stürzt KSCrash ab.
Ist das das gleiche Problem?
Thread 0 abgestürzt:
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 (Abbruch + 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 Hallo, könntest du deine erfolgreiche Mach-o-Hook-Demo mit uns teilen? Ich bin auf EXC_BAD_ACCESS gestoßen, als ich versuche, mach_hook
__cxa_throw zu machen.
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[])
{
<strong i="5">@autoreleasepool</strong> {
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();
}
}
versuchen Sie dies ... viel Glück
Ich treffe einen Absturz mit KSCrash,
wie kann man es lösen?
Wir haben eine PR erstellt, die den oben erwähnten dynamischen Hook von @huakucha implementiert : #375
Hilfreichster Kommentar
Nach weiteren Nachforschungen scheint mein vorheriger Kommentar falsch gewesen zu sein:
Falls KSCrash als statische Bibliothek in die Hauptanwendung eingebunden wird:
MyApplication
(main.o
,libKSCrash.a
)libDynamicLibrary.dylib
(lib.o
)/usr/lib/libc++abi.dylib
Alle Ausnahmen, die von
MyApplication
ausgelöst werden, werden inlibKSCrash.a::__cxa_throw
. Da außerdemlibKSCrash.a
__cxa_throw
alsweak
$ deklariert, schlägt das VerknüpfenMyApplication
nicht fehl, wennmain.o
ein eigenes__cxa_throw
hatlibDynamicLibrary.dylib
ausgelösten Ausnahmen nichtlibKSCrash.a::__cxa_throw
aus und landen in/usr/lib/libc++abi.dylib::__cxa_throw
.Falls KSCrash als dynamische Bibliothek in die Hauptanwendung eingebunden wird:
MyApplication
(main.o
)libKSCrash.dylib
/usr/lib/libc++abi.dylib
libDynamicLibrary.dylib
(lib.o
)/usr/lib/libc++abi.dylib
Alle Ausnahmen, die von
MyApplication
ausgelöst werden, werden inlibKSCrash.dylib::__cxa_throw
, aber nur, wenn:__cxa_throw
wird auslibKSCrash.dylib
exportiert__cxa_throw
ist nicht alsweak
gekennzeichnetWenn
__cxa_throw
alsweak
(0000000000002e90 (__TEXT,__text) weak external ___cxa_throw
) markiert ist, dann scheint der Linker beim VerknüpfenlibKSCrash.dylib
nach/usr/lib/libc++abi.dylib
zu suchen und einen Non zu finden -weak__cxa_throw
und schließen daraus, dasslibKSCrash.dylib::__cxa_throw
ignoriert werden sollte. Während der Laufzeitsymbolsuche zur Auslösezeit vonMyApplication
wirdlibKSCrash.dylib::__cxa_throw
dann ignoriert.Dies lässt mich glauben, dass das Attribut
weak
nur bedingt hinzugefügt werden sollte, wenn KSCrash als statische Bibliothek erstellt wird.Wie beim ersten Anwendungsfall lösen alle von
libDynamicLibrary.dylib
ausgelösten Ausnahmen nichtlibKSCrash.dylib::__cxa_throw
aus und landen in/usr/lib/libc++abi.dylib::__cxa_throw
.Dieses Problem könnte möglicherweise durch ein Low-Level-Patch zur Laufzeit von geladenen Images mit undefinierten Verweisen auf
__cxa_throw
behoben werden. Mit der Testanwendung, auf die im Artikel verwiesen wird, habe ich verifiziert, dass die Technik tatsächlich auch für__cxa_throw
funktioniert.