← Back to DevBytes

Honggfuzz: Complete Testing Guide for Developers

Introduction to Honggfuzz

Honggfuzz is a modern, powerful, and actively maintained fuzzing framework designed for finding security vulnerabilities and stability bugs in software. Unlike traditional fuzzers that rely purely on random mutation, Honggfuzz leverages hardware-based feedback (Intel BTS, Intel PT, and hardware performance counters) and software-based instrumentation (SanitizerCoverage, ASAN, LibFuzzer integration) to achieve deep code exploration. It supports fuzzing of binaries, libraries, and network services, and works across Linux, macOS, Windows, and Android. Whether you're auditing a custom C library, testing a JavaScript engine, or hardening a network daemon, Honggfuzz provides the tooling to uncover hidden edge cases and crashes.

Why Honggfuzz Matters for Developers

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

Fuzzing has become a cornerstone of secure software development. Honggfuzz stands out for several reasons:

By integrating Honggfuzz into your CI/CD pipeline or regular testing workflow, you can continuously stress-test your code against billions of mutated inputs, catching bugs before they reach production.

Installation and Setup

Honggfuzz is primarily developed on Linux but can be built on other platforms. The recommended approach is to clone the repository and compile from source to get the latest features.

Prerequisites

Building from Source

# Clone the repository
git clone https://github.com/google/honggfuzz.git
cd honggfuzz

# Build Honggfuzz and its supporting tools
make

# Optionally, install system-wide
sudo make install

After building, the main executable honggfuzz will be available in the project directory. You can verify the build with:

./honggfuzz --help

For sanitizer-based fuzzing, ensure you have a recent Clang compiler with sanitizer support. The hfuzz_cc / hfuzz-clang helpers simplify building target binaries with the correct instrumentation.

Core Concepts and Architecture

Honggfuzz operates by running a target program repeatedly with mutated inputs, monitoring its behavior through feedback mechanisms, and saving any inputs that cause crashes or discover new code paths. The key components are:

Basic Fuzzing Workflow

The simplest way to start fuzzing is to provide a set of initial seed files (corpus) and the command line that runs the target program, using the magic @@ placeholder for the input file path.

Fuzzing a File-Parsing Application

Assume you have a tool called parse-image that reads a file from disk and processes it:

# Prepare a minimal corpus directory with valid samples
mkdir corpus
cp some-valid-image.jpg corpus/

# Run Honggfuzz, replacing @@ with the mutated input file
honggfuzz -i corpus -o results -- ./parse-image @@

Flags explained:

Using Sanitizer Instrumentation

For maximum bug detection, compile your target with AddressSanitizer (ASAN) and UndefinedBehaviorSanitizer (UBSAN). Honggfuzz provides hfuzz-clang wrappers to simplify this.

# Compile target with sanitizers and coverage feedback
hfuzz-clang -g -fsanitize=address,undefined -fprofile-instr-generate -fcoverage-mapping \
    -o parse-image-san parse-image.c -ljpeg

# Create a directory for sanitizer-compatible output
mkdir results

# Fuzz with hardware feedback disabled (software coverage used instead)
honggfuzz -i corpus -o results --linux_perf_ignore_pt -- ./parse-image-san @@

The --linux_perf_ignore_pt flag disables Intel PT/BTS hardware feedback, falling back to SanitizerCoverage counters. This is useful when hardware tracing is unavailable or you prefer the sanitizer coverage granularity.

Advanced Usage Techniques

Persistent Fuzzing (In-Process)

Persistent fuzzing avoids the overhead of spawning a new process per input. The target is invoked once, and then a loop repeatedly calls a function with new input. Honggfuzz supports persistent mode via the __AFL_FUZZ_INIT and __AFL_FUZZ macros, originally from AFL.

Example target harness for a function parse(const uint8_t* data, size_t len):

#include <stdint.h>
#include <stddef.h>
#include "parse.h"

#ifdef __AFL_FUZZ_INIT
__AFL_FUZZ_INIT();
#endif

int main(int argc, char **argv) {
#ifdef __AFL_FUZZ_INIT
    // AFL persistent mode initialization
    unsigned char *buf = __AFL_FUZZ_INIT();
    while (__AFL_FUZZ(10000)) { // loop 10000 iterations
        size_t len = __AFL_FUZZ_SIZE();
        parse(buf, len);
    }
    return 0;
#else
    // Non-persistent fallback: read from stdin
    // ... (not shown)
#endif
}

Compile with hfuzz-clang and run with the --persistent flag:

hfuzz-clang -g -fsanitize=address -o persistent-parse persistent-parse.c

honggfuzz --persistent -i corpus -o results --linux_perf_ignore_pt -- ./persistent-parse

Persistent mode can achieve thousands of executions per second, dramatically accelerating bug discovery.

Network Fuzzing (TCP/UDP)

Honggfuzz can act as a network client or server to fuzz protocols. It connects to a real service and sends mutated traffic, or listens for connections and responds with mutated data.

To fuzz an HTTP server running locally on port 8080:

honggfuzz --net_client --target TCP:127.0.0.1:8080 \
    -i http_corpus -o net_results --timeout 10 \
    --call_stdin_only -- ./http-server-replay @@

The --net_client flag tells Honggfuzz to connect to the specified TCP address and send the mutated input. The target program (http-server-replay) typically just reads stdin and writes to the socket, but you can customize behavior. For complex protocols, you can provide a dedicated fuzzing harness that manages the connection and passes input via stdin.

Dictionary and Grammar Support

Honggfuzz accepts dictionaries (lists of keywords or tokens) to improve mutation quality. Create a plain text file with one token per line:

# dictionary.txt
GET
POST
HTTP/1.1
Host:
User-Agent:
Content-Length:

Use the --dict option to feed the dictionary:

honggfuzz -i http_corpus --dict dictionary.txt -o results -- ./http-parser @@

For more structured formats, consider using grammar-based fuzzing in combination with Honggfuzz as the backend executor, though Honggfuzz itself focuses on mutation-based fuzzing.

Crash Analysis and Triage

Honggfuzz automatically saves crashing inputs in the output directory under results/. Each crash is hashed based on its call stack, so unique bugs are separated. You can analyze them manually:

# List unique crashes
honggfuzz --print_crashdir results

# Replay a specific crash to see the stack trace
honggfuzz --run_crash_file results/SIGABRT.PC.ffffcafe.CODE.ASAN.h1234.fuzz -- ./target @@

For deeper inspection, run the crashing input under GDB or with ASAN symbolization enabled.

Integrating with LibFuzzer Fuzzing Harnesses

Honggfuzz can directly execute LibFuzzer-style fuzz targets (functions named LLVMFuzzerTestOneInput). This allows you to reuse existing fuzzing harnesses written for LibFuzzer with Honggfuzz's hardware feedback and persistent mode.

# Compile a LibFuzzer harness as a shared library
hfuzz-clang -fsanitize=address,undefined -fPIC -shared -o harness.so harness.c

# Run Honggfuzz with the library
honggfuzz --libfuzzer -- ./harness.so

The --libfuzzer flag enables the LibFuzzer interface, and Honggfuzz handles input delivery and feedback collection transparently.

Best Practices for Effective Fuzzing

Example: Fuzzing a JSON Parser End-to-End

Let's walk through a concrete scenario: fuzzing a simple JSON parsing library to find crashes and assertion failures.

Assume the library exposes a function json_parse(const char* input, size_t length).

Step 1: Write the Harness

#include <stdint.h>
#include <stddef.h>
#include "json.h"

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Ensure null-termination for the parser
    if (size == 0) return 0;
    char *str = malloc(size + 1);
    if (!str) return 0;
    memcpy(str, data, size);
    str[size] = '\0';

    json_parse(str, size);

    free(str);
    return 0; // Non-zero return values signal interesting cases in LibFuzzer mode
}

Step 2: Compile with Sanitizers

hfuzz-clang -g -fsanitize=address,undefined -fPIC -shared -o json-harness.so json-harness.c libjson.a

Step 3: Prepare Corpus

mkdir json-corpus
# Add some valid JSON files
echo '{"key":"value"}' > json-corpus/valid1.json
echo '[1,2,3]' > json-corpus/valid2.json

Step 4: Launch Fuzzing

honggfuzz --libfuzzer --timeout 5 -i json-corpus -o json-results -- ./json-harness.so

Step 5: Monitor and Triage

Watch the terminal output for crash counts and coverage progress. After a few hours (or days), inspect the results:

honggfuzz --print_crashdir json-results
# Replay interesting crashes
honggfuzz --run_crash_file json-results/SIGABRT... -- ./json-harness.so

Each crash can then be analyzed, fixed, and added to regression tests.

Conclusion

Honggfuzz is a versatile and high-performance fuzzer that deserves a place in every developer's security testing toolkit. Its combination of hardware-assisted feedback, sanitizer integration, persistent fuzzing, and network fuzzing capabilities makes it suitable for a wide range of targets – from tiny library functions to complex network services. By following the practices outlined in this guide, you can systematically uncover bugs that static analysis and manual review miss, ultimately delivering more robust and secure software. Start with a small corpus, instrument your build with sanitizers, and let Honggfuzz do the heavy lifting of mutation and crash discovery. The result will be a stronger codebase and greater confidence in your software's resilience.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles