libsigsegv и реагирование на переполнение стека - PullRequest
5 голосов
/ 16 февраля 2011

Мы пытаемся протестировать код студента, и, чтобы автоматизировать процесс, мы хотели бы определить, не переполняет ли код студента стек.

Я добился некоторого успеха, используя библиотеку libsigsegv и соответствующий ей stackoverflow_install_handler. Он работает блестяще, пока код студента не ударит стек дважды.

Например, вот несколько примеров вывода:

[# ~]$ ledit ./interpreter
-> (use solution)
-> (fun 1 2)

*** Stack overflow detected ***
-> (fun 1 2)
Signal -10
[# ~]

Начальный «* Обнаружен переполнение стека *» является желаемым выходом. После повторной загрузки стека все, что я получаю, это бесполезный «Сигнал -10», и программа останавливает выполнение. Я хотел бы снова увидеть сообщение об обнаружении переполнения стека и позволить коду продолжить выполнение.

В моем обработчике переполнения стека я просто печатаю сообщение об обнаружении переполнения в stderr и долго возвращаюсь к «ожидающему входному состоянию» в интерпретаторе.

Спасибо за любую помощь!

EDIT

Согласно предложению caf ниже, мы добавили вызов sigsegv_leave_handler () примерно так:

static void continuation(void *arg1, void *arg2, void *arg3) {                  
  (void)(arg1);                                                                 
  (void)(arg2);                                                                 
  (void)(arg3);                                                                 
  siglongjmp(errorjmp, 1);                                                      
}                                                                               

static void handler(int emergency, stackoverflow_context_t context) {           
 (void)emergency;                                                               
 (void)context;                                                                 
 fprintf(stderr, "\n*** Stack overflow detected ***\n");                        
 fflush(stderr);                                                                
 sigsegv_leave_handler(continuation, NULL, NULL, NULL);                         
}  

Однако вывод остается прежним.

Ответы [ 3 ]

3 голосов
/ 17 февраля 2011

Просто долгое удаление от переполнения стека не обязательно достаточно. Я не видел исходного кода для интерпретатора, в который вы его встраиваете, но я догадываюсь, что переполнение стека приводит к повреждению некоторого внутреннего состояния интерпретатора, что может привести к другому сбою. В частности, обратите внимание, что вы получаете сигнал SIGBUS (10), а не SIGSEGV (11).

Представьте себе следующий сценарий: вам не хватает переполнения стека, когда интерпретатор вызывает malloc. Malloc изменяет некоторые внутренние данные, затем вызывает вспомогательную функцию. Происходит переполнение стека, и вы возвращаетесь в основной цикл интерпретатора. Ваш пул malloc теперь поврежден, и вы ничего не можете с этим поделать.

Я бы порекомендовал завершить и перезапустить интерпретатор при обнаружении переполнения стека. Кроме того, точно выясните, как состояние интерпретатора искажается, и сделайте так, чтобы это было меньшей проблемой (это может быть довольно сложно!). Вы также можете использовать явную проверку глубины стека в интерпретаторе, а не перехватывать SIGSEGV; это позволит вам обработать ошибку в безопасной точке, прежде чем SIGSEGV вызовет проблему.

2 голосов
/ 16 февраля 2011

Вы следуете этому предупреждению в документации libsigsegv ?

... обработчик должен обеспечить восстановление нормальная маска сигнала (потому что многие сигналы блокируются, пока обработчик выполняется), и должен также вызвать sigsegv_leave_handler() для перевода контроль; только тогда это может longjmp прочь.

0 голосов
/ 14 октября 2016

Попробуйте более точно следовать примеру кода tests / stackoverflow1.c из пакета libsigsegv.Этот пример кода поддерживает поддержку перехвата двух последовательных переполнений стека подряд.В частности:

  • Используйте longjmp, а не siglongjmp, внутри продолжения.
  • Выполните вызов sigprocmask перед вызовом sigsegv_leave_handler.
...