breakpad не генерирует минидамп на итераторе стирания дважды

Я обнаружил, что иногда breakpad не обрабатывает sigsegv. и я написал простой пример, чтобы воспроизвести его:

#include <vector>
#include <breakpad/client/linux/handler/exception_handler.h>

int InitBreakpad()
{
    char core_file_folder[] = "/tmp/cores/";
    google_breakpad::MinidumpDescriptor descriptor(core_file_folder);
    auto exception_handler_ =
        new google_breakpad::ExceptionHandler(descriptor,
        nullptr,
        nullptr,
        nullptr,
        true,
        -1);
}
int main()
{
     InitBreakpad();

     // int* ptr = nullptr;
     // *ptr = 1;
     std::vector<int> sum;
     sum.push_back(1);
     auto it = sum.begin();
     sum.erase(it);
     sum.erase(it);

     return 0;
}

и gcc - 4.8.5, а моя команда компиляции -

g++ test_breakpad.cpp -I./include -I./include/breakpad -L./lib -lbreakpad -lbreakpad_client -std=c++11 -lpthread

запустить a.out, получить «Ошибка сегментации», но минидамп не создается.

если я раскомментирую запись nullptr, брейкпад сработает!

что я должен сделать, чтобы исправить это?

Вывод отладки GDB:

(gdb) b google_breakpad::ExceptionHandler::~ExceptionHandler()
Breakpoint 2 at 0x402ed0: file src/client/linux/handler/exception_handler.cc, line 264.
(gdb) c
The program is not being run.
(gdb) r
Starting program: /home/zen/tmp/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Breakpoint 1, google_breakpad::ExceptionHandler::ExceptionHandler (this=0x619040, descriptor=..., filter=0x0, callback=0x0, callback_context=0x0, install_handler=true, server_fd=-1) at src/client/linux/handler/exception_handler.cc:224
224     ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor,
Missing separate debuginfos, use: debuginfo-install glibc-2.17-157.el7_3.1.x86_64 libgcc-4.8.5-11.el7.x86_64 libstdc++-4.8.5-11.el7.x86_64
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff712f19d in __memmove_ssse3_back () from /lib64/libc.so.6
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff712f19d in __memmove_ssse3_back () from /lib64/libc.so.6
(gdb) c
Continuing.

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.

и я попробовал breakpad из дампа процесса, но все равно ничего не получил (запись nullptr работает).


person Zendo June    schedule 01.09.2017    source источник


Ответы (1)


После некоторой отладки я думаю, что причина того, что sum.erase(it) не создает минидамп в вашем примере, связана с повреждением стека.

Во время отладки вы можете видеть, что переменная g_handler_stack_ в src/client/linux/handler/exception_handler.cc правильно инициализирована, а экземпляр google_breakpad::ExceptionHandler правильно добавлен в вектор. Однако при вызове google_breakpad::ExceptionHandler::SignalHandler вектор сообщается пустым, несмотря на отсутствие вызовов google_breakpad::ExceptionHandler::~ExceptionHandler или любого из методов std::vector, которые могли бы изменить вектор.

Некоторые дополнительные данные, указывающие на повреждение стека, заключаются в том, что код работает с clang++. Кроме того, как только мы изменим std::vector<int> sum; на std::vector<int>* sum, что гарантирует, что мы не испортим стек, минидамп запишется на диск.

person moggi    schedule 01.09.2017
comment
большое спасибо. но после того, как я изменил сумму на выделение из кучи, блокнот молчит. std::vector<int>* sum_p = new std::vector<int>; sum_p->push_back(1); auto it = sum_p->begin(); sum_p->erase(it); sum_p->erase(it); - person Zendo June; 04.09.2017
comment
Создайте контрольную панель с символами (и, возможно, O0, O2 по умолчанию) и установите точку останова в google_breakpad::ExceptionHandler::HandleSignal. Во время моих сеансов отладки этот метод был надежно вызван, но переменная g_handler_stack_ повреждена вашим кодом двойного стирания при компиляции с помощью gdb. - person moggi; 04.09.2017
comment
это странно. точка останова в google_breakpad::ExceptionHandler::HandleSignal НЕ срабатывает. GDB показывает Program received signal SIGSEGV, Segmentation fault. 0x00007ffff712f19d in __memmove_ssse3_back () from /lib64/libc.so.6. это env отличается? мой env - centos7 64, gcc 4.8.5, gdb 7.6.1. - person Zendo June; 05.09.2017
comment
Это правильно, что gdb сначала сообщает SIGSEGV. Следующим должен быть вызван обработчик сигнала. Вызовите continue в gdb и проверьте, что происходит. - person moggi; 05.09.2017
comment
спасибо за ваше терпение. Обработчик сигнала не вызывается, если я продолжаю вызов. В первый раз, когда я ввожу c, gdb показывает то же самое: Program received signal SIGSEGV, Segmentation fault. 0x00007ffff712f19d in __memmove_ssse3_back () from /lib64/libc.so.6. Когда я второй раз ввожу c, gdb показывает Program terminated with signal SIGSEGV, Segmentation fault. The program no longer exists. - person Zendo June; 05.09.2017
comment
Я бы начал с установки точки останова в конструкторе и деструкторе класса google_breakpad::ExceptionHandler. Убедитесь, что конструктор вызывается до сбоя, а деструктор никогда не вызывается. - person moggi; 05.09.2017
comment
Breakpoint 1, google_breakpad::ExceptionHandler::ExceptionHandler (this=0x619040, descriptor=..., filter=0x0, callback=0x0, callback_context=0x0, install_handler=true, server_fd=-1) at src/client/linux/handler/exception_handler.cc:224 срабатывает, но точка останова деструктора не срабатывает. - person Zendo June; 05.09.2017
comment
Я могу воспроизвести вашу проблему, как только раскомментирую свою функцию обратного вызова. С callback-функцией и переключением на std::vector, сгенерированный в куче, все работает, без callback-функции возникают те же проблемы, что и со стековой версией. - person moggi; 06.09.2017
comment
Этот и еще несколько тестов показывают, что в вашем тесте происходит довольно много искажений (и, поскольку в стеке не так много, вы искажаете почти все свои переменные). clang++ с -O2 не создает минидамп с обратным вызовом или без него, а также с кучей или стеком, выделенным std::vector, clang++ -O0 делает со всеми параметрами. gcc, по-видимому, менее подвержен влиянию уровня оптимизатора и дает те же результаты с O0 и O2. - person moggi; 06.09.2017
comment
В целом, я думаю, вам нужно признать, что ваш код вызывает неопределенное поведение со стеком и, возможно, повреждение кучи, что также может привести к повреждению переменных брейкпада. Я до сих пор не понимаю, почему google_breakpad::ExceptionHandler::HandleSignal вас не вызвали. Это в основном просто зарегистрированная функция обратного вызова для sigaction и должна вызываться системным/низкоуровневым кодом C. - person moggi; 06.09.2017
comment
да, я согласен с тобой. векторный итератор стирания вызывает memcpy, стирание недопустимого итератора может перезаписать некоторые данные с помощью memcpy и может повредить стек вызовов или какую-либо другую кучу. но почему обработчик сигнала не вызывается? - person Zendo June; 06.09.2017
comment
Есть две части, должен быть вызван обработчик сигнала, и я никак не могу воспроизвести настройку, в которой он не вызывается. Однако то, что делает внутренний обработчик сигналов breakpad, например. запись минидампа и вызов обратного вызова хранится в переменной, которая повреждена во втором вызове метода std::vector::erase. Я не могу воспроизвести ни в одном из своих тестов сценарий, который не вызывает обработчик сигнала, только случаи, которые не вызывают обратный вызов и пишут минидампы. - person moggi; 06.09.2017
comment
я имею в виду, что breakpad::ExceptionHandler::SignalHandler() не вызывается. Итератор двойного стирания повредил разделительную панель. Теперь мое решение состоит в том, чтобы включить системные файлы ядра (ulimit -c) и добавить мой sighandler для захвата дампа ядра, кроме breakpad. - person Zendo June; 07.09.2017