Что такое undefined behavior в C и примеры
Что проверяют
Понимаете ли вы, почему зелёный прогон тестов не доказывает отсутствие ошибки. Для тестировщика undefined behavior это класс дефектов, которые не воспроизводятся по требованию: код работает в отладочной сборке и ломается с оптимизацией, а вывод «у меня не падает» не стоит ничего.
Как отвечать
Undefined behavior это ситуация, на которую стандарт языка не накладывает никаких требований: компилятор вправе сделать что угодно, в том числе выкинуть код, который по его рассуждению недостижим. Сразу отделите UB от соседей: unspecified behavior это выбор из нескольких допустимых вариантов без обязательства его документировать, implementation-defined это выбор, который компилятор документирует (размер int, знаковость char).
Источники, которые стоит назвать: переполнение знакового целого, выход за границы массива, разыменование нулевого или уже освобождённого указателя, чтение неинициализированной переменной, целочисленное деление на ноль, нарушение строгого алиасинга, гонка данных.
int f(int *p) {
int v = *p;
if (p == NULL) return 0; // проверку компилятор вправе удалить
return v;
}Инструменты важнее списка примеров: UBSan, ASan, MSan, Valgrind, статический анализ, сборка разными компиляторами и уровнями оптимизации, фаззинг под санитайзерами.
Где спотыкаются
Ставят знак равенства между UB и падением. Программа с неопределённым поведением может годами отдавать верный ответ и сломаться от смены компилятора или флага, поэтому дефект заводится по факту нарушения, а не по факту краша.
Смешивают UB с зависящим от реализации поведением. Размер типа или порядок вычисления аргументов функции неопределённым поведением не являются, и отчёт с такой формулировкой обесценивает саму находку.
Полагаются на один санитайзер и обычный прогон. Переполнение знакового целого ловит UBSan, а не ASan, часть проверок между собой несовместима, и ни одна не сработает, если тест не проходит по проблемной ветке.