Wipe Out the Wolves You Don’t See: Fuzzing to Improve System Robustness
Most embedded verification strategies rely on deterministic methods: unit tests, integration checks, static analysis. These approaches are necessary, but they only validate anticipated behavior. They follow expected paths with known inputs. Those methods cannot prepare us for the moment unexpected data arrives. Entire classes of bugs sit just outside their reach, quietly waiting for the real world to trigger them.
Fuzzing closes that gap. It introduces malformed, random, or invalid inputs, forcing the system to react to scenarios no one thought to test. This method prepares an embedded system to face what it will do in the field. Faulty physical layers, unstable sensors, corrupted wireless packets, or even intentional attacks all feed real-world chaos into devices. Traditional test methods struggle to recreate that kind of noise at scale.
Despite its proven value in other domains, fuzzing remains uncommon in embedded workflows. Most teams either haven’t considered it, or have avoided it altogether afraid that costs outweigh the benefits. Applied correctly, fuzzing becomes a powerful extension of existing test strategies, especially in areas like protocol parsing, hardware interfaces, and edge behavior in state machines. The approach can work without reinventing infrastructure or placing an onerous burden on a development team.
In this talk, we’ll discuss different fuzzing approaches and how they can help you build more trustworthy devices.
What this presentation is about and why it matters
How do you find bugs that only show up when real inputs, weird edge cases, and broken assumptions meet your firmware? Ryan Torvik approaches that question with a hands-on walkthrough of fuzzing for embedded systems, using CodeForge and examples built around CMake, libFuzzer, and a simple message parser plus state machine. The talk stays practical, showing how coverage-guided fuzzing is wired up, what kinds of failures it exposes, and how the workflow fits software-in-the-loop and embedded test setups. It is a good fit for engineers who already test, but want a stronger way to stress their code.
Who will benefit the most from this presentation
- Firmware engineers who already have unit tests, but suspect they miss malformed or unexpected inputs.
- Embedded developers working on parsers, protocols, or state machines with multiple input sources.
- Test engineers who need a desktop-friendly way to explore robustness before hardware testing.
- Technical leads trying to add fuzzing to an existing CMake-based workflow without making the process opaque.
What you need to know
A basic understanding of embedded C or C++ testing will help, along with familiarity with how your project builds and runs tests. A few specifics from the talk will land better if you know:
- What a unit test or harness looks like in your codebase
- How CMake is used to build test targets
- Very basic ideas of parsing, state machines, and input validation
- Why code coverage is useful when exercising test inputs
Glossary (terms used in this talk)
- Fuzzing: A testing technique that feeds many unexpected or malformed inputs into a program to discover crashes, hangs, or surprising behavior. It is especially useful for code that parses external data or handles complex state transitions.
- Mutator: A component that creates test inputs by generating new data or modifying existing inputs. It explores variations such as byte substitutions, insertions, and deletions.
- Harness: A small wrapper around target code that exposes an entry point to a testing tool. It provides a controlled way to run the code repeatedly with generated inputs.
- Corpus: A set of inputs that a fuzzer keeps because they reached new coverage or triggered interesting behavior. The corpus becomes seed material for future mutations and helps the fuzzer focus on useful paths.
- Coverage guidance: A feedback loop where execution coverage determines which inputs are worth keeping and mutating further. Inputs that hit new basic blocks or branches are retained because they may lead to unexplored behavior.
- Crash deduplication: The process of grouping repeated failures that likely come from the same underlying bug. It helps reduce repeated triage work when a fuzzer produces many similar crashing inputs.
- Coverage-based fuzzing: A fuzzing approach that uses code coverage to guide input generation toward new execution paths. Inputs that reach previously unseen code are kept and evolved further.
- Instrumentation: Additional code or compiler support that exposes runtime behavior for testing, such as branch or line coverage. It helps a fuzzer understand which inputs explore new behavior.
Toolbox (mentioned in this talk)
- Visual Studio Code: A lightweight source code editor with broad language support and extension-based integration. It is often used for embedded development and can pair well with containerized workflows.
- Clang: A C and C++ compiler toolchain known for fast diagnostics and modern language support. It is widely used as an alternative or complement to GCC in embedded and desktop development.
- Docker: A containerization platform used to package a development environment and make it repeatable across machines. It is commonly used to keep local development and CI environments aligned.
- LibFuzzer: An in-process coverage-guided fuzzing engine that works with LLVM and Clang. It repeatedly mutates inputs and keeps those that expand code coverage or trigger crashes.
- CodeForge: A fuzzing workflow tool that wraps build, run, corpus viewing, and crash inspection tasks into a more approachable interface. It is used here as a helper around fuzzing examples and debugging.
- QP/C++: A C++ framework for hierarchical state machines and embedded applications. It is used here as the basis for a software-in-the-loop parsing example.
Final thoughts
Practical and slightly opinionated, this session gives you a workable mental model for fitting fuzzing into embedded development without treating it as a specialist-only stunt. You will come away with a clearer sense of how a fuzzer is put together, what it needs from your code, and how to connect results back to debugging. It should be especially helpful for firmware teams, test engineers, and anyone trying to harden parsers or protocols. The spirit is simple: let the weird inputs show themselves early.
This overview is AI-generated from the session transcript. Spot an issue? Let us know.








No comments or questions yet. Be the first to start the conversation!