Skip to content

Conversation

oetr
Copy link
Contributor

@oetr oetr commented Oct 10, 2025

This allows the users to annotate fuzz tests methods or any type by @DictionaryProvider and provide values directly to the type mutators. Currently, only String mutators make use of this feature, but this feature makes sense for other types as well.

The main motivation is to work around libFuzzer's TORC (table of recent compares) limitation of 64 bytes. libFuzzer dictionaries suffer from the same limitation. But with this PR, the issue below is found in no time.

  public static Stream<?> myDict() {
    return Stream.of(
        "0123456789abcdef".repeat(50),
        "sitting duck suprime".repeat(53),
        // We can mix all kinds of values in the same dictionary.
        // Each mutator only takes the values it can use.
        123);
  }

  @FuzzTest
  // Just propagate the dictionary to all types of the fuzz test method that can use it.
  @DictionaryProvider(
      value = {"myDict"},
      // Don't want to wait, force String mutators to use dictionary values every other time.
      pInv = 2)
  public static void fuzzerTestOneInput(
      @NotNull @WithUtf8Length(max = 10000) String data,
      @NotNull @WithUtf8Length(max = 10000) String data2) {
    /*
     * libFuzzer's table of recent compares only allows 64 bytes, so asking the fuzzer to construct
     * these long strings would run for a very very long time without finding them. With a
     * DictionaryProvider this problem is trivial, because we can directly provide these long strings to
     * the fuzzer, and also force that they are used more often by setting pInv to a low value.
     */
    if (data.equals("0123456789abcdef".repeat(50))
        && data2.equals("sitting duck suprime".repeat(53))) {
      throw new FuzzerSecurityIssueLow("Found the long string!");
    }
  }

@oetr oetr force-pushed the CIF-1785-dictionary-provider branch 9 times, most recently from 4ba9e45 to 9120af0 Compare October 16, 2025 15:17
In addition to primitive arrays, these types are now also possible:
- List<Integer> []
- List<Integer> [][][]
@oetr oetr force-pushed the CIF-1785-dictionary-provider branch from 9120af0 to 076db89 Compare October 16, 2025 15:18
@oetr oetr force-pushed the CIF-1785-dictionary-provider branch 4 times, most recently from 56da09c to 958d54a Compare October 16, 2025 23:19
oetr added 4 commits October 17, 2025 01:22
Enables easy tweaking of probabilities for indidual mutation functions
in the future.
Propagate a new class MutatorRuntime to every mutator. For now the
class only contains the fuzz test method, necessary for implementation
of @DictionaryProvider annotation, in order to extract thunks
returning Stream<?>.
This class can be extended in the future to contain the table of
recent compares, etc. to improve fuzzing performance.
This is just the enabling work. Methods and types annotated by
@DictionaryProvider recursively propagate this annotation down the
type hierarchy by default (can set to be for the annotated type only).

Any mutator can now be adapted to use the user-provided values
this annotation points to.
The mutator now extracts applicable Strings from the provider and uses
them during mutation according to the pInv of the last
@DictionaryProvider annotation it found on this type.
@oetr oetr force-pushed the CIF-1785-dictionary-provider branch from 958d54a to d164e3c Compare October 16, 2025 23:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant