Возможное повреждение стека - PullRequest
3 голосов
/ 19 октября 2010

Со ссылкой на мой предыдущий вопрос о GDB, не указывающем точку SIGSEGV ,

Мой код темы выглядит следующим образом:

void *runner(void *unused)
{
 do
 {
 sem_wait(&x);
  ...

  if(/*condition 1 check*/)
  {
   sem_post(&x);
   sleep(5);
   sem_wait(&x);
   if(/*repeat condition 1 check; after atleast 5 seconds*/)
   {
    printf("LEAVING...\n");
    sem_post(&x); 
    // putting exit(0); here resolves the dilemma
    return(NULL);  
   }
  }
 sem_post(&x);
 }while(1);

}

Основной код:

sem_t x;    

int main(void)
{   
    sem_init(&x,0,1);
        ...
    pthread_t thrId;
    pthread_create(&thrId,NULL,runner,NULL);
        ...
    pthread_join(thrId,NULL);
    return(0);
}

Редактировать: Наличие выхода (0) в коде потока бегуна делает ошибку исчезающей.


Какие могут быть причины повреждения стека?

Вывод GDB: (0xb7fe2b70 - идентификатор потока бегуна)

LEAVING...
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7fe2b70 (LWP 2604)]
0x00000011 in ?? ()

Выход Valgrind:

==3076== Thread 2:
==3076== Jump to the invalid address stated on the next line
==3076==    at 0x11: ???
==3076==    by 0xA26CCD: clone (clone.S:133)
==3076==  Address 0x11 is not stack'd, malloc'd or (recently) free'd
==3076== 
==3076== 
==3076== Process terminating with default action of signal 11 (SIGSEGV)
==3076==  Bad permissions for mapped region at address 0x11
==3076==    at 0x11: ???
==3076==    by 0xA26CCD: clone (clone.S:133)
==3076==  Address 0x11 is not stack'd, malloc'd or (recently) free'd

Ответы [ 3 ]

7 голосов
/ 19 октября 2010

Напишите новый исходный файл с функцией main, которая выполняет те же действия, что и main, который вы разместили здесь, за исключением того, что вместо pthread_create просто вызываете функцию.Посмотрите, сможете ли вы воссоздать проблему независимо от использования потоков.Судя по тому, как все выглядит, ваши семафоры все равно должны нормально работать в однопоточной среде.

Если это все равно не получится, вам будет проще отладить его.* вместо возврата не выдает ошибку, это предполагает, что вы испортили либо адрес возврата, который находится в стеке при запуске runner.Вызывая exit, вы не полагаетесь на эту область памяти, чтобы получить доступ к функции выхода (если бы вы вернули, pthread_exit был бы вызван кодом библиотеки pthread, который вызвал runner).Я думаю, что вывод valgrind не является точным на 100% - не из-за какой-либо ошибки в valgrind, а потому, что место, где вы вызываете ошибку в сочетании с типом ошибки, которую вы вызываете, очень затрудняет, чтобы быть уверенным, кто вызвал.

Некоторые gcc флаги, которые могут вас заинтересовать:

-fstack-protector-all -Wstack-protector

Опция предупреждения не работает без опции -f.

Вы также можетехочу попробовать:

-fno-omit-frame-pointer
2 голосов
/ 19 октября 2010

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

  • Хранение указателя на элемент в стеке и использование его после того, как объект уже находится вне области видимости.
  • Переполнение буфера, например, наличие в стеке char buffer[20] и запись за пределы (sprintf - фантастический способ сделать это).
  • Неправильное приведение, то есть наличие базового класса A в стеке, приведение его к производному классу и его использование.
1 голос
/ 19 октября 2010

Используйте valgrind или эквивалентный инструмент проверки памяти, чтобы выяснить это.Хватит гадать.Также прекратите публиковать неполный код, особенно если вы не знаете, есть ли у него проблема или нет.Ошибка может быть за пределами этой функции.Например, возможно, семафор не инициализирован.

Из вывода valgrind я могу предположить, что ваша строка pthread_create() должна содержать недопустимый указатель на функцию.Таким образом, pthread переходит на этот поддельный адрес и вылетает.Очевидно, нет стека ...

...