Parece que a função __cxa_throw em KSCrashMonitor_CPPException.c não está sendo chamada quando uma exceção C++ é lançada em uma estrutura incorporada, por exemplo, CrashLib no aplicativo Crash-Tester.
Não consegui encontrar uma solução para isso. Para mim, parece que qualquer biblioteca incorporada sempre usará __cxa_throw da libc++, e não a implementação no KSCrash.
Além disso: Quando uma exceção C++ não tratada é lançada em uma estrutura incorporada, o KSCrash falhará durante o relatório, pois stackCursor->advanceCursor será igual a NULL em KSCrashReport.c:writeBacktrace().
Editar: Adicionadas informações KSCrash travando durante o relatório.
Alguma sorte com isso? Estou tentando integrar o KSCrash no meu aplicativo, mas travado por causa da estrutura incorporada.
Por favor, deixe-me saber se você tem alguma solução para isso.
Sem sorte, e não acredito que seja possível, pelo menos não em nosso caso de uso. Este é o meu entendimento da situação:
A maneira como o KSCrash registra o rastreamento de pilha é criando sua própria implementação de __cxa_throw, que permite o acesso à pilha antes de ser desenrolada pela libc++. Isso funciona desde que o KSCrash esteja vinculado estaticamente ao código C++, pois o vinculador encontrará e usará __cxa_throw no formato KSCrash em vez da implementação em libc++. Mas no caso de um framework embutido que se vincula a libc++, a implementação __cxa_throw do libc++ será usada, pois o framework não conhece o código no KSCrash. Talvez haja uma solução alternativa se você tiver controle sobre a estrutura incorporada, mas isso não funcionará em nosso caso de uso.
Por favor, deixe-me saber se você descobrir uma solução.
Eu tenho controle sobre a estrutura incorporada. Mas não tenho certeza de como corrigi-lo.
Eu também tentei o PLCrashReporter, mesmo problema com ele.
Isso significa que o KSCrash deve idealmente ser construído como uma biblioteca estática e vinculado ao aplicativo, para pelo menos capturar exceções C++ lançadas no código do aplicativo?
Mas isso ainda deixaria quaisquer exceções lançadas em qualquer biblioteca dinâmica não capturada pelo KSCrash se eu entender seu relatório de bug corretamente @pdrtrifork ? Se controlarmos as bibliotecas dinâmicas incorporadas, poderíamos vincular uma biblioteca estática a cada uma delas com apenas esse stub __cxa_throw, que apenas adiaria para um manipulador KSCrash compartilhado?
Hah, então ao investigar isso acabei aqui http://stackoverflow.com/questions/36846628/conditionally-overriding-cxa-throw , que foi aberto pelo nosso próprio @kstenerud 😄
De qualquer forma, o PR #219 deve pelo menos evitar falhas durante o relatório de falhas.
@kstenerud Acho que esse problema deve ser renomeado para algo como _"Rastreamentos de pilha ausentes para exceções C++ lançadas de imagens não vinculadas estaticamente ao KSCrash"_. Até onde eu sei, a substituição __cxa_throw
só funciona na mesma imagem que o KSCrash, então:
O último afetaria clientes como sentry-swift
, https://docs.sentry.io/clients/cocoa/ , que incorpora o KSCrash como um framework.
Após uma investigação mais aprofundada, parece que meu comentário anterior estava incorreto:
Acho que esse problema deve ser renomeado para algo como _"Ausência de rastreamentos de pilha para exceções C++ lançadas de imagens não vinculadas estaticamente ao KSCrash"_.
No caso do KSCrash ser vinculado ao aplicativo principal como uma biblioteca estática:
MyApplication
( main.o
, libKSCrash.a
)libDynamicLibrary.dylib
( lib.o
)/usr/lib/libc++abi.dylib
Quaisquer exceções lançadas de MyApplication
entrarão no libKSCrash.a::__cxa_throw
. Além disso, como libKSCrash.a
declara __cxa_throw
como weak
, vincular MyApplication
não falha se main.o
tiver seu próprio __cxa_throw
substituir. Até agora tudo bem. No entanto, como este relatório de bug observou, quaisquer exceções lançadas de libDynamicLibrary.dylib
não acionarão libKSCrash.a::__cxa_throw
e terminarão em /usr/lib/libc++abi.dylib::__cxa_throw
.
No caso do KSCrash ser vinculado ao aplicativo principal como uma biblioteca dinâmica:
MyApplication
( main.o
)libKSCrash.dylib
/usr/lib/libc++abi.dylib
libDynamicLibrary.dylib
( lib.o
)/usr/lib/libc++abi.dylib
Quaisquer exceções lançadas de MyApplication
entrarão em libKSCrash.dylib::__cxa_throw
, mas somente se:
__cxa_throw
é exportado de libKSCrash.dylib
__cxa_throw
não está marcado como weak
Se __cxa_throw
estiver marcado como weak
( 0000000000002e90 (__TEXT,__text) weak external ___cxa_throw
), então ao vincular libKSCrash.dylib
o vinculador parece olhar para /usr/lib/libc++abi.dylib
, encontre um valor não -weak __cxa_throw
e concluir que libKSCrash.dylib::__cxa_throw
deve ser ignorado. Durante a pesquisa de símbolo de tempo de execução no tempo de lançamento de MyApplication
, libKSCrash.dylib::__cxa_throw
é então ignorado.
Isso me leva a acreditar que o atributo weak
deve ser adicionado condicionalmente apenas ao construir o KSCrash como uma biblioteca estática.
Como no primeiro caso de uso, quaisquer exceções lançadas de libDynamicLibrary.dylib
não acionarão libKSCrash.dylib::__cxa_throw
e terminarão em /usr/lib/libc++abi.dylib::__cxa_throw
.
Esse problema pode ser corrigido com alguns patches de tempo de execução de baixo nível de imagens carregadas com referências indefinidas a __cxa_throw
. Usando o aplicativo de teste mencionado no artigo, verifiquei que a técnica também funciona para __cxa_throw
.
Estou tentando verificar a falha em uma estrutura no meu aplicativo. Quando tento obter o log de falhas, vejo que o rastreamento de pilha não está mostrando a falha real, em vez disso, o KSCrash está falhando.
Esta é a mesma questão?
Tópico 0 travado:
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 (abortar + 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 Serviços Gráficos 0x0000000183f03f84 0x183ef9000 + 44932 (GSEventRunModal + 100)
12 UIKit 0x000000018b61e880 0x18b5ab000 + 473216 (UIApplicationMain + 208)
@torarnv Oi, você poderia compartilhar sua demonstração bem-sucedida de mach-o-hook conosco? Eu encontrei EXC_BAD_ACCESS quando tento 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[])
{
<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();
}
}
tente isso... boa sorte
Eu encontro uma falha com o KSCrash ,
como resolver isso?
Criamos um gancho dinâmico de implementação de PR mencionado acima por @huakucha : #375
Comentários muito úteis
Após uma investigação mais aprofundada, parece que meu comentário anterior estava incorreto:
No caso do KSCrash ser vinculado ao aplicativo principal como uma biblioteca estática:
MyApplication
(main.o
,libKSCrash.a
)libDynamicLibrary.dylib
(lib.o
)/usr/lib/libc++abi.dylib
Quaisquer exceções lançadas de
MyApplication
entrarão nolibKSCrash.a::__cxa_throw
. Além disso, comolibKSCrash.a
declara__cxa_throw
comoweak
, vincularMyApplication
não falha semain.o
tiver seu próprio__cxa_throw
substituir. Até agora tudo bem. No entanto, como este relatório de bug observou, quaisquer exceções lançadas delibDynamicLibrary.dylib
não acionarãolibKSCrash.a::__cxa_throw
e terminarão em/usr/lib/libc++abi.dylib::__cxa_throw
.No caso do KSCrash ser vinculado ao aplicativo principal como uma biblioteca dinâmica:
MyApplication
(main.o
)libKSCrash.dylib
/usr/lib/libc++abi.dylib
libDynamicLibrary.dylib
(lib.o
)/usr/lib/libc++abi.dylib
Quaisquer exceções lançadas de
MyApplication
entrarão emlibKSCrash.dylib::__cxa_throw
, mas somente se:__cxa_throw
é exportado delibKSCrash.dylib
__cxa_throw
não está marcado comoweak
Se
__cxa_throw
estiver marcado comoweak
(0000000000002e90 (__TEXT,__text) weak external ___cxa_throw
), então ao vincularlibKSCrash.dylib
o vinculador parece olhar para/usr/lib/libc++abi.dylib
, encontre um valor não -weak__cxa_throw
e concluir quelibKSCrash.dylib::__cxa_throw
deve ser ignorado. Durante a pesquisa de símbolo de tempo de execução no tempo de lançamento deMyApplication
,libKSCrash.dylib::__cxa_throw
é então ignorado.Isso me leva a acreditar que o atributo
weak
deve ser adicionado condicionalmente apenas ao construir o KSCrash como uma biblioteca estática.Como no primeiro caso de uso, quaisquer exceções lançadas de
libDynamicLibrary.dylib
não acionarãolibKSCrash.dylib::__cxa_throw
e terminarão em/usr/lib/libc++abi.dylib::__cxa_throw
.Esse problema pode ser corrigido com alguns patches de tempo de execução de baixo nível de imagens carregadas com referências indefinidas a
__cxa_throw
. Usando o aplicativo de teste mencionado no artigo, verifiquei que a técnica também funciona para__cxa_throw
.