Skip to main content

Common Options and Workflows

Using Jazzer standalone

java -cp <classpath>;<path/to/jazzer.jar>;<path/to/jazzer-junit.jar> com.code_intelligence.jazzer.Jazzer --target_class=<fuzz-test-class> [args...]

To call Jazzer directly you need to pass it the project classpath, the path to the jazzer.jar and jazzer-junit.jar along with the Jazzer main class com.code_intelligence.jazzer.Jazzer and target class that contains the Fuzz Test.

Optionally you can add other Jazzer arguments with double dash command-line flags. Because Jazzer is based on libFuzzer, you can add all available libFuzzer arguments with single dash command-line flags. Please refer to libFuzzer for documentation.

The following JVM settings are recommended for running Jazzer:

  • -XX:-OmitStackTraceInFastThrow: Ensures that stack traces are emitted even on hot code paths. This may hurt performance if your Fuzz Test frequently throws and catches exceptions, but also helps find flaky bugs.
  • -XX:+UseParallelGC: Optimizes garbage collection for high throughput rather than low latency.
  • -XX:+CriticalJNINatives: Is supported with JDK 17 and earlier and improves the runtime performance of Jazzer's instrumentation.
  • -XX:+EnableDynamicAgentLoading: Silences a warning with JDK 21 and later triggered by the Java agent that Jazzer attaches to instrument the fuzzed code.

Passing arguments

Jazzer provides multiple configuration settings. The value of a setting item some_opt is obtained from the following sources in increasing order of precedence:

  • the default value
  • META-INF/MANIFEST.MF attribute Jazzer-Some-Opt on the classpath
  • the JAZZER_SOME_OPT environment variable
  • the jazzer.some_opt system property
  • the jazzer.some_opt JUnit configuration parameter
  • the --some_opt CLI parameter

Minimizing a crashing input

With the following argument you can minimize a crashing input to find the smallest input that reproduces the same "bug":

-minimize_crash=1 <path/to/crashing_input>

Coverage instrumentation

The Jazzer agent inserts coverage markers into the JVM bytecode during class loading. It's possible to restrict instrumentation to only a subset of classes with the --instrumentation_includes flag. This is especially useful if coverage inside specific packages is of higher interest, for example, the user library under test rather than an external parsing library in which the Fuzzer is likely to get lost. Similarly, there is --instrumentation_excludes to exclude specific classes from instrumentation. Both flags take a list of glob patterns for the java class name separated by colon:

--instrumentation_includes=com.my_com.**:com.other_com.** --instrumentation_excludes=com.my_com.crypto.**

By default, JVM-internal classes and Java as well as Kotlin standard library classes aren't instrumented, so you don't have to exclude them manually.

Value profile

The runtime flag -use_value_profile=1 enables value profiling mode, analog to libFuzzer.

Custom hooks

In order to obtain information about data passed into functions such as String.equals or String.startsWith, Jazzer hooks invocations to these methods. This feature is also available to fuzz targets, where you can implement custom sanitizers or stub out methods that block the Fuzzer from progressing (for example, checksum verifications or random number generation).

You can declare method hooks with the @MethodHook annotation defined in the com.code_intelligence.jazzer.api package.

To use the compiled method hooks, they have to be available on the classpath and can then be loaded by providing the flag --custom_hooks, which takes a colon-separated list of names of classes to load hooks from. Hooks have to be loaded from separate JAR files so that Jazzer can add it to the bootstrap class loader search. Alternatively you can specify a list of custom hooks with the Jazzer-Hook-Classes attribute in the Fuzz Target JAR's manifest.

--keep_going

With the flag --keep_going=N Jazzer continues fuzzing until N unique stack traces have been encountered. --keep-going=0 keeps the Fuzzer running until another stop condition (for example maximum runtime) is met.

You can ignore particular stack traces based on their DEDUP_TOKEN by passing a comma-separated list of tokens to the command: --ignore=<token_1>,<token2>.

Native libraries

Jazzer supports fuzzing of native libraries loaded by the JVM, for example via System.load(). For the Fuzzer to get coverage feedback, compile these libraries with -fsanitize=Fuzzer-no-link.

Additional sanitizers such as AddressSanitizer or UndefinedBehaviorSanitizer are often useful to uncover bugs inside the native libraries. You can add them with these flags:

  • AddressSanitizer: -fsanitize=Fuzzer-no-link,address
  • UndefinedBehaviorSanitizer: -fsanitize=Fuzzer-no-link,undefined (add -fno-sanitize-recover=all to crash on UBSan reports)

Starting Jazzer with --asan and/or --ubsan automatically preloads the sanitizer runtimes. Jazzer defaults to using the runtimes associated with clang on the PATH. If you used a different compiler to compile the native libraries, specify it with CC to override this default. If no compiler is available in your runtime environment, but you have a directory that contains the required sanitizer libraries, you can specify its path in the JAZZER_NATIVE_SANITIZERS_DIR environment variable.

Note: On macOS, you may see Gatekeeper warnings when using --asan and/or --ubsan since these flags cause the native sanitizer libraries to be preloaded into the co-designed java executable via DYLD_INSERT_LIBRARIES.

Sanitizers other than AddressSanitizer and UndefinedBehaviorSanitizer aren't yet supported. Furthermore, due to the nature of the JVM's Garbage Collector, LeakSanitizer reports too many false positives and won't be supported.