1. Today’s topic
We examine:
Fuzzing:
automatically generates and mutates input data,
trying to cause a crash, hang, or memory error.
Property-based testing:
checks general properties of an algorithm
across many automatically generated inputs.The central idea: a unit test checks a scenario you imagined. A fuzzer tries to find a scenario you did not think of.
2. Why this matters
EC25
UART may deliver a response in fragments, with a URC in the middle, empty lines, zero bytes, damaged CR/LF, or an excessively long line. A fuzzer automatically explores thousands of combinations.
Configuration
A corrupt blob may have correct magic but wrong size; an old version; a string without \0; generation overflow; or a valid CRC for logically invalid parameters.
CAN/RS-485/Modbus
Fuzzing is useful for invalid DLC, unexpected function code, truncated frames, incorrect CRC, and a broadcast address.
Phase detector
Property-based tests check:
- event timestamp does not go backwards;
- sequence increases only when an event occurs;
- a short pulse shorter than debounce does not change stable phase;
- any mask always yields a valid enum.3. Theory
Coverage-guided fuzzing
The fuzzer:
1. Runs code against the initial corpus.
2. Mutates bytes.
3. Observes which code branches executed.
4. Saves an input if it opens a new path.
5. Continues mutating interesting inputs.Sanitizers
Use:
AddressSanitizer:
heap/stack/global buffer violations, use-after-free.
UndefinedBehaviorSanitizer:
signed overflow, invalid shifts, misaligned access.Flags:
-O1 -g -fno-omit-frame-pointer -fsanitize=fuzzer,address,undefinedA good fuzz harness
- small;
- fast;
- deterministic;
- does not use a network;
- does not start threads;
- does not sleep;
- completely resets state before every iteration.Fragmentation invariance for the AT parser
Property:
feed(all_payload_once) == feed(same_payload_fragmented)Compare the canonical result, not internal indices: the sequence of events AT_EVENT_OK, QMTOPEN, QMTSTAT, ERROR, and LINE_TOO_LONG.
4. Common mistakes
- Starting with pure random noise and no valid seeds.
- The harness retains state between iterations.
- Using real time.
- Not bounding input size.
- Checking only “did not crash”, without properties.
- Ignoring timeouts as “uninteresting”.
- Not converting a crash into a regression test.
5. Practical assignment
Create a fuzz target for the AT parser. Plan:
1. Extract the parser into a host-compatible component.
2. Remove FreeRTOS/UART dependencies.
3. Implement a canonical event collector.
4. Add two feed modes: whole and fragmented.
5. Build with Clang and ASan/UBSan.
6. Create a seed corpus.
7. Run 50 000 iterations.Example invocation:
./build-host/fuzz_at_parser \
fuzz/corpus/at \
-runs=50000 \
-max_len=2048 \
-timeout=26. What to try next
- Fuzz config blob loading/migration.
- Fuzz a Modbus RTU decoder.
- Fuzz CAN codec round-trip.
- Fuzz the fault manager as a stateful sequence: timeout → late OK → reconnect → URC.
Exercise
Define a property test for an AT response split at arbitrary byte boundaries. What output should be compared, and what state must be reset?
Self-check criteria: The assertion must describe observable parsing results rather than buffer indices; include both valid seeds and malformed bounded inputs.
Show the supplied answer
Feed the same payload whole and fragmented into clean parser instances. Compare the canonical event sequence and event data; reset parser state and the event collector before each iteration.
Exercise
A fuzzer reports a timeout without a crash. Explain how to preserve and investigate the input, then convert the finding into a deterministic regression test.
Self-check criteria: Do not dismiss the timeout; ensure each run begins with clean state and that the regression checks the cause, not just the saved bytes.
Show the supplied answer
Keep the reproducing input and exact harness/build settings. Reproduce with bounded execution, inspect parser progress or state transitions, and add a test that asserts termination or the violated progress property without relying on real sleeps.