У меня очень странный сбой на платформе ARM linux, вызванный простым кодом.
Проблема в том, что он воспроизводит редко (один раз в день), а другая проблема заключается в том, что он падает, где он на самом деле не может.
Давайте начнем с кода C ++. Функция потока делает это:
event_obj events[EVENTS_MAX]; // EVENTS_MAX = 32
int num = 0;
m_engine->getEvents(events, &num);
engine
это указатель на базовый абстрактный класс, который имеет только одну реализацию на данный момент. getEvents — это чисто виртуальный метод.
getEvents
после некоторых изменений ничего не делает, кроме этого
int engine::getEvents(event_obj*, int* num)
{
if (num != nullptr)
{
*num = 0; // SEGMENTATION FAULT
}
return 1; // ok
}
SEGFAULT происходит при попытке сохранить 0 в num. Сначала я подумал, что это повреждение стека, но после того, как я проверил сгенерированный ассемблерный код, кажется, что здесь ничего не хранится в стеке. Этот метод даже не генерирует защиту стека (-fstack-protector-strong включен), оба параметра хранятся в регистрах r1 и r2.
Давайте посмотрим код для вызова функции:
event_obj events[EVENTS_MAX];
int num = 0;
236f8: 2300 movs r3, #0
236fa: ac06 add r4, sp, #24
236fc: 9306 str r3, [sp, #24]
m_engine->getEvents(events, &num);
236fe: 6803 ldr r3, [r0, #0]
23700: 691b ldr r3, [r3, #16]
23702: 4622 mov r2, r4
23704: a90c add r1, sp, #48 ; 0x30
23706: 4798 blx r3
и код самой функции:
int engine::getEvents(event_obj*, int* num)
{
if (num != nullptr)
251f8: 4613 mov r3, r2
251fa: b10a cbz r2, 25200 <_Z18engine_thread_funcPv+0x9e0>
{
*num = 0;
251fc: 2200 movs r2, #0
251fe: 601a str r2, [r3, #0]
}
return 1; // ok
}
25200: 2001 movs r0, #1
25202: 4770 bx lr
return 1; // ok
}
как видно из сгенерированного кода, указатели ставятся в r1
а также r2
регистры.
23702: 4622 mov r2, r4
23704: a90c add r1, sp, #48 ; 0x30
Даже если стек поврежден, он может испортить значение для num
переменная, но как это может повредить указатель в регистре? Также из краш-журнала я вижу, что LR
адрес неверный.
Сигнал CRASH 11 Адрес ошибки сегментации 0xf0000000 ПК 0x251fe LR
0x6c3c533c
Единственное, что я не вижу здесь, это адрес перехода (blx r3), потому что вызываемый метод является виртуальным.
У меня есть одно очень маловероятное предположение, что вместо перехода к первой строке тела виртуального метода он переместился на несколько строк до этого и испортил регистры, но я не понимаю, как это возможно. Также он всегда вылетает на одной строке, даже после изменения кода. Это очень странно.
Может кто-нибудь предложить что-нибудь попробовать? Есть идеи?
Заранее спасибо.
Ошибка происходит, потому что двигатель больше не действителен. Метод, содержащий движок, вероятно, был освобожден — т. Е. Память вашего потока пропала. Таким образом, двигатель-getevents даже не действует в памяти. Что-то произошло где-то еще в вашем коде, и потоки должны были перестать работать — и завершиться. Они не имеют. Это очень похоже на обратный вызов в приложение, которое выходит.
Других решений пока нет …