1. Тема дня
Разбираем:
Fuzzing:
автоматически генерирует и изменяет входные данные,
пытаясь вызвать crash, зависание или ошибку памяти.
Property-based testing:
проверяет общие свойства алгоритма
на большом количестве автоматически созданных входов.Главная мысль: unit-тест проверяет придуманный тобой сценарий. Fuzzer пытается найти сценарий, о котором ты не подумал.
2. Зачем это нужно
EC25
UART может передать ответ фрагментами, с URC посередине, пустыми строками, нулевыми байтами, повреждённым CR/LF или слишком длинной строкой. Fuzzer автоматически перебирает тысячи сочетаний.
Конфигурация
Повреждённый blob может иметь корректный magic, но неверный size; старую version; строку без \0; переполнение generation; правильный CRC для логически недопустимых параметров.
CAN/RS-485/Modbus
Fuzzing полезен для неверного DLC, неожиданных function code, обрезанного кадра, неправильного CRC, широковещательного адреса.
Phase detector
Property-based тесты проверяют:
- timestamp событий не идёт назад;
- sequence увеличивается только при событии;
- короткий импульс короче debounce не меняет stable phase;
- произвольная маска всегда даёт корректный enum.3. Теория
Coverage-guided fuzzing
Fuzzer:
1. Запускает код на исходном corpus.
2. Изменяет байты.
3. Смотрит, какие ветви кода выполнены.
4. Сохраняет вход, если он открыл новый путь.
5. Продолжает изменять интересные входы.Sanitizers
Используй:
AddressSanitizer:
выход за heap/stack/global buffer, use-after-free.
UndefinedBehaviorSanitizer:
signed overflow, некорректные сдвиги, misaligned access.Флаги:
-O1 -g -fno-omit-frame-pointer -fsanitize=fuzzer,address,undefinedХороший fuzz harness
- маленький;
- быстрый;
- детерминированный;
- не использует сеть;
- не запускает потоки;
- не делает sleep;
- полностью сбрасывает состояние перед каждой итерацией.Fragmentation invariance для AT-парсера
Свойство:
feed(all_payload_once) == feed(same_payload_fragmented)Сравнивать надо не внутренние индексы, а канонический результат: последовательность событий AT_EVENT_OK, QMTOPEN, QMTSTAT, ERROR, LINE_TOO_LONG.
4. Типичные ошибки
- Начать с чистого случайного шума без valid seeds.
- Harness сохраняет состояние между итерациями.
- Использовать реальное время.
- Не ограничить размер входа.
- Проверять только “не упало”, без свойств.
- Игнорировать timeout как “неинтересный”.
- Не превращать crash в regression test.
5. Практическое задание
Сделай fuzz target для AT-парсера. План:
1. Вынести parser в host-compatible компонент.
2. Убрать FreeRTOS/UART зависимости.
3. Реализовать canonical event collector.
4. Добавить два режима feed: whole и fragmented.
5. Собрать через Clang с ASan/UBSan.
6. Создать seed corpus.
7. Запустить 50 000 итераций.Пример запуска:
./build-host/fuzz_at_parser \
fuzz/corpus/at \
-runs=50000 \
-max_len=2048 \
-timeout=26. Что попробовать дальше
- Fuzz config blob loader/migration.
- Fuzz Modbus RTU decoder.
- Fuzz CAN codec round-trip.
- Fuzz fault manager как stateful sequence: timeout → late OK → reconnect → URC.
Задание
Определите property test для AT response, разделённого на произвольных границах байтов. Какой результат сравнивать и какое состояние сбрасывать?
Критерии самопроверки: Проверка должна описывать наблюдаемый результат parsing, а не buffer indices; включить valid seeds и malformed bounded inputs.
Показать ответ автора
Передать один payload целиком и fragmented в чистые экземпляры parser. Сравнить canonical event sequence и event data; перед каждой итерацией сбрасывать parser state и event collector.
Задание
Fuzzer сообщил timeout без crash. Объясните сохранение и расследование входа, затем преобразование результата в детерминированный regression test.
Критерии самопроверки: Не игнорировать timeout; каждый запуск начинается с clean state, regression проверяет причину, а не только сохранённые bytes.
Показать ответ автора
Сохранить воспроизводящий input и точные harness/build settings. Повторить с ограниченным execution, проверить parser progress или state transitions и добавить тест termination либо нарушенного progress property без real sleeps.