ОЧЕНЬ странное переполнение стека в программе на C ++ - PullRequest
2 голосов
/ 14 июня 2010

Я написал программу некоторое время назад (Mac OS X, C ++, SDL, FMOD), и она работала довольно хорошо. Но в последнее время я хотел расширить его функциональность и добавил еще немного кода. И теперь, когда я запускаю его и пытаюсь протестировать новую функциональность, программа падает с SIGABRT.

Глядя в отладчик, в стеке функций я вижу:

  • _kill
  • убить $ UNIX2003
  • 1010 * подъем *
  • __ * прервать 1012 *
  • __ stack_chk_fail
  • odtworz <- моя функция, которая была изменена </li>

Насколько я знаю, "__stack_chk_fail" указывает на переполнение стека. Но это не самая странная вещь об этом. В этой функции "odtworz" у меня есть такой код:

...

koniec = 0;
while ( koniec == 0 ) {
    ...
    if (mode == 1) {
        ...
    }
    else if (mode == 2) {
        ...
    }
    else if (mode == 3) {
       piesniOrkiestrowe[0] = '\0'; 
       while ( piesniOrkiestrowe[0] == '\0' ) { 
           losowaPiesn(); 
           char * piesnOrkiestrowa = szukajPiesniOrkiestrowej(); 
           if ( piesnOrkiestrowa != NULL ) 
              strcpy(piesniOrkiestrowe, piesnOrkiestrowa); 
       } 
       char nowyPiesnPlik[25]; 
       sprintf(nowyPiesnPlik, "%sorch/%s", PIESNI_DIR.c_str(), piesniOrkiestrowe);
    }
}

mode - это глобальная переменная, для которой в функции задано значение "2". А теперь представьте - если я удаляю третий оператор if (mode == 3), который никогда не выполняется в этом режиме, программа не падает Удаление кода, который даже не выполняется, помогает ситуации!

Теперь я не хочу удалять этот код, потому что он предназначен для другого режима моей программы. И там все отлично работает. Так какие-нибудь подсказки, где я могу искать? Что может быть не так с этим?

Ответы [ 4 ]

16 голосов
/ 14 июня 2010

Это , а не ошибка переполнения стека. __stack_chk_fail вызывается при обнаружении повреждения кадра стека. Традиционный способ разбить стек - переполнение буфера. Код, который вызывает его, находится не в вашем фрагменте, а в точках.


После обновления вопроса кодом из комментария: и вызовы strcpy и sprintf являются отличными кандидатами на повреждение стека. Проблема переполнения буфера, о которой я упоминал в своем первоначальном ответе. Предположение: nowyPiesnPlik выглядит очень маленьким. Функция sprintf () записывает слишком много символов в буфер и перезаписывает «канарейку». Когда на канарейку давят, во время выполнения свистит птица:)

Вы можете сделать массив больше. Не настоящее решение, используйте безопасные альтернативы для этих функций, такие как snprintf (). Я не буду упоминать strncpy ().

2 голосов
/ 18 ноября 2011

У меня возникла очень похожая проблема, код зависает на __stack_chk_fail.В моем случае решение, как рекомендовано выше, состояло в том, чтобы избавиться от sprintf().

0 голосов
/ 14 июня 2010

Нашли!

Преступник был до кода, который я дал, но Ханс Пассант дал мне понять, что искать. Выглядело это так:

char piesnPlik[25];
if ( mode == TRYB_PIANINO )
    sprintf(piesnPlik, "%spiano/%s.mp3", PIESNI_DIR.c_str(), wybranaPiesn);
else if ( tryb == TRYB_ORKIESTRA )
    sprintf(piesnPlik, "%sorch/%s", PIESNI_DIR.c_str(), piesniOrkiestrowe);
else if ( tryb == TRYB_NAGRANIE )
    sprintf(piesnPlik, "%s/%s", NAGRANIA_DIR.c_str(), nazwaNagraniaMP3);

Итак, я добавил сегодня третью переменную пользователя "piesnPlik". Но «nazwaNagraniaMP3» был длиннее, чем две другие переменные, которые были скопированы туда, поэтому он повредил стек. Но невероятно, что ему удалось после этого работать со всеми вещами SDL, а только после сбоя после выхода из функции.

Спасибо всем за Ваши предложения!

0 голосов
/ 14 июня 2010

Не странно.Когда дело доходит до переполнения стека или повреждения кучи, вы должны ожидать странного.Указатель стека, счетчик программ или другое состояние программы были повреждены, поэтому отладчик или инструмент трассировки не могут точно сообщить, где находилась программа в момент сбоя.Ошибка, вероятно, в другом месте вашего кода, далеко от фрагмента, который вы опубликовали.Начните с самого последнего измененного кода.

Редактировать: Вы уже написали хороший пример повреждения стека, как вы уже обнаружили.В любом случае, вот один:

void foo (){ 
    int x[0];
    x[-99] = -1;
}
...