SEGFAULT при записи в переменную стека

У меня очень странный сбой на платформе 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), потому что вызываемый метод является виртуальным. У меня есть одно очень маловероятное предположение, что вместо перехода к первой строке тела виртуального метода он переместился на несколько строк до этого и испортил регистры, но я не понимаю, как это возможно. Также он всегда вылетает на одной строке, даже после изменения кода. Это очень странно.

Может кто-нибудь предложить что-нибудь попробовать? Есть идеи?

Заранее спасибо.

1 ответ

Ошибка происходит, потому что двигатель больше не действителен. Метод, содержащий движок, вероятно, был освобожден - т. Е. Память вашего потока пропала. Таким образом, двигатель-getevents даже не действует в памяти. Что-то произошло где-то еще в вашем коде, и потоки должны были перестать работать - и завершиться. Они не имеют. Это очень похоже на обратный вызов в приложение, которое выходит.

Другие вопросы по тегам