Kscrash: Pelacakan tumpukan salah untuk pengecualian C++ dalam kerangka kerja yang disematkan

Dibuat pada 20 Feb 2017  ·  12Komentar  ·  Sumber: kstenerud/KSCrash

Sepertinya fungsi __cxa_throw di KSCrashMonitor_CPPException.c tidak dipanggil ketika pengecualian C++ dilemparkan ke dalam kerangka kerja yang disematkan, misalnya CrashLib di aplikasi Crash-Tester.

Saya belum bisa menemukan solusi untuk ini. Bagi saya sepertinya perpustakaan yang disematkan akan selalu menggunakan __cxa_throw dari libc++, dan bukan implementasi di KSCrash.

Selain itu: Ketika pengecualian C++ yang tidak ditangani dilemparkan ke dalam kerangka kerja yang disematkan, KSCrash akan macet selama pelaporan, karena stackCursor->advanceCursor akan sama dengan NULL di KSCrashReport.c:writeBacktrace().

Sunting: Menambahkan informasi KSCrash mogok selama pelaporan.

Komentar yang paling membantu

Setelah penyelidikan lebih lanjut, sepertinya komentar saya sebelumnya salah:

Saya pikir masalah ini harus diganti namanya menjadi sesuatu seperti _"Jejak tumpukan yang hilang untuk pengecualian C++ yang dilemparkan dari gambar yang tidak ditautkan secara statis dengan KSCrash"_.

Dalam kasus KSCrash ditautkan ke aplikasi utama sebagai perpustakaan statis:

  • MyApplication ( main.o , libKSCrash.a )

    • libDynamicLibrary.dylib ( lib.o )

    • /usr/lib/libc++abi.dylib

Pengecualian apa pun yang dilemparkan dari MyApplication akan masuk ke libKSCrash.a::__cxa_throw . Sebagai tambahan, karena libKSCrash.a mendeklarasikan __cxa_throw sebagai weak , menautkan MyApplication tidak gagal jika main.o memiliki __cxa_throw sendiri libDynamicLibrary.dylib tidak akan memicu libKSCrash.a::__cxa_throw , dan akan berakhir di /usr/lib/libc++abi.dylib::__cxa_throw .

Dalam kasus KSCrash ditautkan ke aplikasi utama sebagai pustaka dinamis:

  • MyApplication ( main.o )

    • libKSCrash.dylib

    • /usr/lib/libc++abi.dylib

    • libDynamicLibrary.dylib ( lib.o )

    • /usr/lib/libc++abi.dylib

Pengecualian apa pun yang dilemparkan dari MyApplication akan masuk ke libKSCrash.dylib::__cxa_throw , tetapi hanya jika:

  1. __cxa_throw diekspor dari libKSCrash.dylib
  2. __cxa_throw tidak ditandai sebagai weak

Jika __cxa_throw ditandai sebagai weak ( 0000000000002e90 (__TEXT,__text) weak external ___cxa_throw ), maka ketika menautkan libKSCrash.dylib penaut tampaknya melihat /usr/lib/libc++abi.dylib , temukan non -lemah __cxa_throw , dan menyimpulkan bahwa libKSCrash.dylib::__cxa_throw harus diabaikan. Selama pencarian simbol runtime pada waktu lempar dari MyApplication , libKSCrash.dylib::__cxa_throw kemudian diabaikan.

Ini membuat saya percaya bahwa atribut weak harus ditambahkan secara kondisional hanya saat membangun KSCrash sebagai pustaka statis.

Seperti untuk kasus penggunaan pertama, pengecualian apa pun yang dilemparkan dari libDynamicLibrary.dylib tidak akan memicu libKSCrash.dylib::__cxa_throw , dan akan berakhir di /usr/lib/libc++abi.dylib::__cxa_throw .

Masalah ini berpotensi diperbaiki dengan beberapa patch runtime tingkat rendah dari gambar yang dimuat dengan referensi yang tidak ditentukan ke __cxa_throw . Dengan menggunakan aplikasi uji yang dirujuk dalam artikel, saya telah memverifikasi bahwa teknik ini memang bekerja untuk __cxa_throw juga.

cooked_throw

Semua 12 komentar

Adakah keberuntungan dengan ini? Saya mencoba mengintegrasikan KSCrash di aplikasi saya, tetapi macet karena kerangka kerja yang disematkan.
Tolong beri tahu saya jika Anda memiliki pekerjaan untuk ini.

Tidak berhasil, dan saya tidak percaya itu mungkin, setidaknya tidak dalam kasus penggunaan kami. Inilah pemahaman saya tentang situasinya:

Cara KSCrash merekam jejak tumpukan adalah dengan membuat implementasi __cxa_throw-nya sendiri, yang memungkinkan akses ke tumpukan sebelum dibatalkan oleh libc++. Ini berfungsi selama KSCrash ditautkan secara statis dengan kode C++, karena tautan akan menemukan dan menggunakan __cxa_throw dari KSCrash alih-alih implementasi di libc++. Tetapi dalam kasus kerangka kerja tertanam yang tertaut ke libc++, implementasi __cxa_throw dari libc++ akan digunakan, karena kerangka kerja tidak tahu tentang kode di KSCrash. Mungkin ada solusi jika Anda memiliki kendali atas kerangka kerja yang disematkan, tetapi ini tidak akan berfungsi dalam kasus penggunaan kami.

Tolong beri tahu saya jika Anda menemukan solusi.

Saya memiliki kendali atas kerangka kerja yang disematkan. Tapi tidak yakin bagaimana cara memperbaikinya.
Saya juga mencoba PLCrashReporter, masalah yang sama dengannya.

Apakah ini berarti bahwa KSCrash idealnya harus dibangun sebagai perpustakaan statis dan ditautkan ke dalam aplikasi, untuk setidaknya menangkap pengecualian C++ yang dilemparkan ke dalam kode aplikasi?

Tapi itu masih akan meninggalkan pengecualian apa pun yang dilemparkan ke perpustakaan dinamis apa pun yang tidak tertangkap oleh KSCrash jika saya memahami laporan bug Anda dengan benar @pdrtrifork ? Jika kita mengontrol lib dinamis yang disematkan, dapatkah kita menautkan lib statis ke masing-masing lib hanya dengan rintisan __cxa_throw itu, yang hanya akan tunduk pada penangan KSCrash yang dibagikan?

Hah, jadi dalam menyelidiki ini saya berakhir di sini http://stackoverflow.com/questions/36846628/conditionally-overriding-cxa-throw , yang dibuka oleh @kstenerud kami sendiri

Bagaimanapun, PR #219 setidaknya harus mencegah kerusakan selama pelaporan kerusakan.

@kstenerud Saya pikir masalah ini harus diganti namanya menjadi sesuatu seperti _"Jejak tumpukan yang hilang untuk pengecualian C++ yang dilemparkan dari gambar yang tidak ditautkan secara statis dengan KSCrash"_. Sejauh yang saya tahu, penggantian __cxa_throw hanya berfungsi pada gambar yang sama dengan KSCrash, jadi:

  • jika KSCrash dibangun sebagai perpustakaan statis dan ditautkan ke aplikasi utama, Anda mendapatkan pengecualian C++ backtraces jika pengecualian dilemparkan ke aplikasi utama, tetapi tidak ketika dibuang dari perpustakaan yang dimuat secara dinamis
  • jika KSCrash dibuat sebagai pustaka statis dan ditautkan ke pustaka dinamis (pembungkus), Anda mendapatkan pengecualian C++ backtrace jika pengecualian dilempar dari pustaka dinamis itu, tetapi tidak ketika dilempar dari aplikasi utama, atau pustaka lain yang dimuat secara dinamis
  • jika KSCrash dibangun sebagai pustaka bersama (kerangka), Anda mendapatkan pengecualian C++ backtraces jika pengecualian dilemparkan dari KSCrash, tetapi tidak ketika dilemparkan dari aplikasi utama, atau pustaka yang dimuat secara dinamis lainnya

Yang terakhir akan mempengaruhi klien seperti sentry-swift , https://docs.sentry.io/clients/cocoa/ , yang menyematkan KSCrash sebagai kerangka kerja.

Setelah penyelidikan lebih lanjut, sepertinya komentar saya sebelumnya salah:

Saya pikir masalah ini harus diganti namanya menjadi sesuatu seperti _"Jejak tumpukan yang hilang untuk pengecualian C++ yang dilemparkan dari gambar yang tidak ditautkan secara statis dengan KSCrash"_.

Dalam kasus KSCrash ditautkan ke aplikasi utama sebagai perpustakaan statis:

  • MyApplication ( main.o , libKSCrash.a )

    • libDynamicLibrary.dylib ( lib.o )

    • /usr/lib/libc++abi.dylib

Pengecualian apa pun yang dilemparkan dari MyApplication akan masuk ke libKSCrash.a::__cxa_throw . Sebagai tambahan, karena libKSCrash.a mendeklarasikan __cxa_throw sebagai weak , menautkan MyApplication tidak gagal jika main.o memiliki __cxa_throw sendiri libDynamicLibrary.dylib tidak akan memicu libKSCrash.a::__cxa_throw , dan akan berakhir di /usr/lib/libc++abi.dylib::__cxa_throw .

Dalam kasus KSCrash ditautkan ke aplikasi utama sebagai pustaka dinamis:

  • MyApplication ( main.o )

    • libKSCrash.dylib

    • /usr/lib/libc++abi.dylib

    • libDynamicLibrary.dylib ( lib.o )

    • /usr/lib/libc++abi.dylib

Pengecualian apa pun yang dilemparkan dari MyApplication akan masuk ke libKSCrash.dylib::__cxa_throw , tetapi hanya jika:

  1. __cxa_throw diekspor dari libKSCrash.dylib
  2. __cxa_throw tidak ditandai sebagai weak

Jika __cxa_throw ditandai sebagai weak ( 0000000000002e90 (__TEXT,__text) weak external ___cxa_throw ), maka ketika menautkan libKSCrash.dylib penaut tampaknya melihat /usr/lib/libc++abi.dylib , temukan non -lemah __cxa_throw , dan menyimpulkan bahwa libKSCrash.dylib::__cxa_throw harus diabaikan. Selama pencarian simbol runtime pada waktu lempar dari MyApplication , libKSCrash.dylib::__cxa_throw kemudian diabaikan.

Ini membuat saya percaya bahwa atribut weak harus ditambahkan secara kondisional hanya saat membangun KSCrash sebagai pustaka statis.

Seperti untuk kasus penggunaan pertama, pengecualian apa pun yang dilemparkan dari libDynamicLibrary.dylib tidak akan memicu libKSCrash.dylib::__cxa_throw , dan akan berakhir di /usr/lib/libc++abi.dylib::__cxa_throw .

Masalah ini berpotensi diperbaiki dengan beberapa patch runtime tingkat rendah dari gambar yang dimuat dengan referensi yang tidak ditentukan ke __cxa_throw . Dengan menggunakan aplikasi uji yang dirujuk dalam artikel, saya telah memverifikasi bahwa teknik ini memang bekerja untuk __cxa_throw juga.

cooked_throw

Saya mencoba memeriksa kerusakan dalam kerangka kerja di aplikasi saya. Ketika saya mencoba untuk mendapatkan log kerusakan, saya melihat bahwa jejak tumpukan tidak menunjukkan kerusakan yang sebenarnya, melainkan KSCrash yang mogok.

Apakah ini masalah yang sama?

Utas 0 Rusak:
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 (batalkan + 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 Layanan Grafik 0x0000000183f03f84 0x183ef9000 + 44932 (GSEventRunModal + 100)
12 UIKit 0x000000018b61e880 0x18b5ab000 + 473216 (UIApplicationMain + 208)

@torarnv Hai, bisakah Anda membagikan demo mach-o-hook Anda yang sukses dengan kami? Saya mengalami EXC_BAD_ACCESS saat mencoba 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();
    }
}

coba ini ... semoga berhasil

Saya bertemu satu crash dengan KSCrash ,
kscrash

bagaimana mengatasinya?

Kami telah membuat PR yang mengimplementasikan kait dinamis yang disebutkan di atas oleh @huakucha : #375

Apakah halaman ini membantu?
0 / 5 - 0 peringkat