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, all available libFuzzer arguments can be added 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 many 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 is 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, e.g., 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 are not instrumented, so these do not need to be excluded 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 functionality is also available to fuzz targets, where it can be used to implement custom sanitizers or stub out methods that block the fuzzer from progressing (e.g. checksum verifications or random number generation).

Method hooks can be declared using 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. The list of custom hooks can alternatively be specified via 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. Specifically --keep-going=0 will keep the fuzzer running until another stop condition (e.g. maximum runtime) is met.

Particular stack traces can also be ignored based on their DEDUP_TOKEN by passing a comma-separated list of tokens via --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, these libraries have to be compiled with -fsanitize=fuzzer-no-link.

Additional sanitizers such as AddressSanitizer or UndefinedBehaviorSanitizer are often useful to uncover bugs inside the native libraries and can be added 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 n ative sanitizer libraries to be preloaded into the codesigned java executable via DYLD_INSERT_LIBRARIES.

Sanitizers other than AddressSanitizer and UndefinedBehaviorSanitizer are not yet supported. Furthermore, due to the nature of the JVM's GC, LeakSanitizer reports too many false positives and will not be supported.