Как определить, была ли переменная неинициализирована / перехватить 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

РЕДАКТИРОВАТЬ: В системе Linux

3 ответа

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

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

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

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

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

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

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

Другие вопросы по тегам