Как определить, была ли переменная неинициализирована / перехватить 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()
, поместите магический номер в заголовок выделенной памяти и проверьте, остается ли он при освобождении.