Как определить, если переменная uninitialized/catch segfault в C

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

void segfault_sigaction(int signal, siginfo_t *si, void *arg)
{
    printf("Caught segfault at address %p\n", si->si_addr);
    exit(0);
}

void myfree(void*p, char * file, int line){

    struct sigaction sa;

    memset(&sa, 0, sizeof(sigaction));
    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction = segfault_sigaction;
    sa.sa_flags   = SA_SIGINFO;

    sigaction(SIGSEGV, &sa, NULL);

    char up = *((char*)p); //Segfault

EDIT: в системе Linux

Ответ 1

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

Кроме того, при хорошей разработке программы вызывающий отвечает за передачу правильных параметров функции. Функция не должна вообще касаться вызывающего абонента. Если неверный параметр передается по ссылке, все ставки отключены.

Доступ к памяти, на которую указывает неинициализированный указатель, приводит к поведению undefined, который включает в себя следующие результаты:

  • Существует ошибка сегментации.
  • Сбой программы.
  • Ничего не происходит, но программа начинает вести себя странно.
  • Ничего не происходит, и программа работает нормально.

Если вы делаете это, потому что хотите защитное программирование, вы должны рассмотреть некоторую проверку правильности значений переменных, предпочтительно через assert() или static_assert().

Ответ 2

Попробуйте использовать Valgrind с помощью инструмента memcheck. Он может обнаруживать неинициализированный доступ к памяти, а также ряд других недопустимых шаблонов доступа. Здесь можно найти здесь. Добавление аргумента --track-originins = yes (требуется версия 3.4.0) может облегчить поиск неинициализированной памяти.

Ответ 3

Указатели не имеют значения по умолчанию, если вы его не инициализировали. Иногда он NULL (если p есть NULL, вы можете поймать SIGSEGV), иногда он указывает на действительную память и кажется, что все в порядке. Значение, которое у них есть, - это все, что было в памяти, которую они используют сейчас. Что касается вашей проблемы, я бы посоветовал написать собственную версию malloc() и free(), поместить магический номер в заголовок выделенной памяти и проверить, остается ли он там при освобождении.