Поймать SIGBUS в C и переполнение стека

Я хочу поймать SIGBUS, мой код показан ниже:

#include <stdlib.h>
#include <signal.h>
#include <iostream>
#include <stdio.h>

void catch_sigbus (int sig)
{
//std::cout << "SIGBUS" << std::endl;
printf("SIGBUS\n");
exit(-1);
}int main(int argc, char **argv) {

signal (SIGBUS, catch_sigbus);

int *iptr;
char *cptr;

#if defined(__GNUC__)
# if defined(__i386__)
/* Enable Alignment Checking on x86 */
__asm__("pushf\norl $0x40000,(%esp)\npopf");
# elif defined(__x86_64__)
/* Enable Alignment Checking on x86_64 */
__asm__("pushf\norl $0x40000,(%rsp)\npopf");
# endif
#endif

/* malloc() always provides aligned memory */
cptr = (char*)malloc(sizeof(int) + 1);

/* Increment the pointer by one, making it misaligned */
iptr = (int *) ++cptr;

/* Dereference it as an int pointer, causing an unaligned access */

*iptr = 42;

return 0;
}

Когда я использую printf, он может поймать, вызвав catch_sigbus, но когда я использую cout, он не может. Так кто-нибудь может мне помочь? Я бегу на Ubuntu 12.04.

У меня есть еще один вопрос. Когда я ловлю SIGBUS, как я могу получить si_code? BUS_ADRALN/BUS_ADRERR/BUS_OBJERR

0

Решение

Вы не можете использовать printf или же cout в обработчике сигнала. Вы также не можете позвонить exit, Тебе повезло с printf на этот раз, но вам не так повезло с cout, Если ваша программа находится в другом состоянии, может быть cout будет работать и printf не будет. Или, может быть, ни то, ни другое. Проверьте документацию вашей операционной системы, чтобы увидеть, какие функции безопасны по сигналу (если она существует, она часто очень плохо документирована).

Ваша самая безопасная ставка в этом случае — позвонить write в STDERR_FILENO прямо, а затем позвоните _exit (не exitнебезопасен в обработчике сигналов). На некоторых системах безопасно звонить fprintf в stderr, но я не уверен, является ли glibc одним из них.

Изменить: Чтобы ответить на ваш добавленный вопрос, вам нужно настроить обработчики сигналов с sigaction получить дополнительную информацию. Этот пример настолько далеко, что я бы вошел в обработчик сигналов, я включил альтернативный метод, если вы хотите пойти дальше. Обратите внимание, что запись теоретически небезопасна, потому что она будет ошибочно нарушена, но так как мы делаем _exit это будет безопасно в этом конкретном случае:

#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

void
bus_handler(int sig, siginfo_t *si, void *vuctx)
{
char buf[2];
#if 1
/*
* I happen to know that si_code can only be 1, 2 or 3 on this
* particular system, so we only need to handle one digit.
*/
buf[0] = '0' + si->si_code;
buf[1] = '\n';
write(STDERR_FILENO, buf, sizeof(buf));
#else
/*
* This is a trick I sometimes use for debugging , this will
* be visible in strace while not messing with external state too
* much except breaking errno.
*/
write(-1, NULL, si->si_code);
#endif
_exit(1);
}

int
main(int argc, char **argv)
{
struct sigaction sa;
char *cptr;
int *iptr;

memset(&sa, 0, sizeof(sa));

sa.sa_sigaction = bus_handler;
sa.sa_flags = SA_SIGINFO;
sigfillset(&sa.sa_mask);
sigaction(SIGBUS, &sa, NULL);

#if defined(__GNUC__)
# if defined(__i386__)
/* Enable Alignment Checking on x86 */
__asm__("pushf\norl $0x40000,(%esp)\npopf");
# elif defined(__x86_64__)
/* Enable Alignment Checking on x86_64 */
__asm__("pushf\norl $0x40000,(%rsp)\npopf");
# endif
#endif

/* malloc() always provides aligned memory */
cptr = (char*)malloc(sizeof(int) + 1);

/* Increment the pointer by one, making it misaligned */
iptr = (int *) ++cptr;

/* Dereference it as an int pointer, causing an unaligned access */

*iptr = 42;

return 0;
}
2

Другие решения

Согласно вашему комментарию, вы пытаетесь отладить SIGBUS, и уже существует вопрос об этом:
Отладка SIGBUS на x86 Linux

Это перечисляет ряд возможных причин. Но, вероятно, наиболее вероятная причина для SIGBUS заключается в том, что у вас повреждена память, и она все испортила, поэтому вы получите SIGBUS позже … Так что отладка сигнала может не помочь в устранении ошибки. При этом используйте отладчик, чтобы поймать точку в коде, где генерируется сигнал, и посмотреть, является ли он указателем. Это хорошая отправная точка для попытки выяснить причину.

1

По вопросам рекламы [email protected]