diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel index d894594d7..cca9e77e2 100644 --- a/examples/BUILD.bazel +++ b/examples/BUILD.bazel @@ -123,17 +123,22 @@ java_fuzz_target_test( target_class = "com.example.ExampleValueProfileFuzzer", ) -java_fuzz_target_test( - name = "MazeFuzzer", +[java_fuzz_target_test( + name = "MazeFuzzer_" + mode, srcs = [ "src/main/java/com/example/MazeFuzzer.java", ], allowed_findings = ["com.example.MazeFuzzer$$TreasureFoundException"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, target_class = "com.example.MazeFuzzer", -) - -java_fuzz_target_test( - name = "ExampleOutOfMemoryFuzzer", + verify_crash_reproducer = True if mode == "classic" else False, +) for mode in [ + "classic", + "mutationFramework", +]] + +[java_fuzz_target_test( + name = "ExampleOutOfMemoryFuzzer_" + mode, timeout = "short", srcs = [ "src/main/java/com/example/ExampleOutOfMemoryFuzzer.java", @@ -142,12 +147,17 @@ java_fuzz_target_test( "com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow", "java.lang.OutOfMemoryError", ], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, fuzzer_args = ["--jvm_args=-Xmx512m"], target_class = "com.example.ExampleOutOfMemoryFuzzer", -) - -java_fuzz_target_test( - name = "ExampleStackOverflowFuzzer", + verify_crash_reproducer = True if mode == "classic" else False, +) for mode in [ + "classic", + "mutationFramework", +]] + +[java_fuzz_target_test( + name = "ExampleStackOverflowFuzzer_" + mode, srcs = [ "src/main/java/com/example/ExampleStackOverflowFuzzer.java", ], @@ -155,10 +165,15 @@ java_fuzz_target_test( "com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow", "java.lang.StackOverflowError", ], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, target_class = "com.example.ExampleStackOverflowFuzzer", # Crashes with a segfault before any stack trace printing is reached. target_compatible_with = SKIP_ON_MACOS, -) + verify_crash_reproducer = True if mode == "classic" else False, +) for mode in [ + "classic", + "mutationFramework", +]] # WARNING: This fuzz target uses a vulnerable version of log4j, which could result in the execution # of arbitrary code during fuzzing if executed with an older JDK. Use at your own risk. @@ -207,13 +222,14 @@ java_fuzz_target_test( ], ) -java_fuzz_target_test( - name = "JpegImageParserFuzzer", +[java_fuzz_target_test( + name = "JpegImageParserFuzzer_" + mode, size = "enormous", srcs = [ "src/main/java/com/example/JpegImageParserFuzzer.java", ], allowed_findings = ["java.lang.NegativeArraySizeException"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, fuzzer_args = [ "-fork=2", ], @@ -221,13 +237,17 @@ java_fuzz_target_test( target_class = "com.example.JpegImageParserFuzzer", # The exit codes of the forked libFuzzer processes are not picked up correctly. target_compatible_with = SKIP_ON_MACOS, + verify_crash_reproducer = True if mode == "classic" else False, deps = [ "@maven//:org_apache_commons_commons_imaging", ], -) +) for mode in [ + "classic", + "mutationFramework", +]] -java_fuzz_target_test( - name = "GifImageParserFuzzer", +[java_fuzz_target_test( + name = "GifImageParserFuzzer_" + mode, srcs = [ "src/main/java/com/example/GifImageParserFuzzer.java", ], @@ -236,11 +256,16 @@ java_fuzz_target_test( "java.lang.IllegalArgumentException", "java.lang.OutOfMemoryError", ], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, target_class = "com.example.GifImageParserFuzzer", + verify_crash_reproducer = True if mode == "classic" else False, deps = [ "@maven//:org_apache_commons_commons_imaging", ], -) +) for mode in [ + "classic", + "mutationFramework", +]] java_fuzz_target_test( name = "TiffImageParserFuzzer", @@ -355,19 +380,24 @@ java_fuzz_target_test( ], ) -java_fuzz_target_test( - name = "JacksonCborFuzzer", +[java_fuzz_target_test( + name = "JacksonCborFuzzer_" + mode, srcs = [ "src/main/java/com/example/JacksonCborFuzzer.java", ], allowed_findings = ["java.lang.NullPointerException"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, target_class = "com.example.JacksonCborFuzzer", + verify_crash_reproducer = True if mode == "classic" else False, deps = [ "@maven//:com_fasterxml_jackson_core_jackson_core", "@maven//:com_fasterxml_jackson_core_jackson_databind", "@maven//:com_fasterxml_jackson_dataformat_jackson_dataformat_cbor", ], -) +) for mode in [ + "classic", + "mutationFramework", +]] java_fuzz_target_test( name = "FastJsonFuzzer", @@ -499,8 +529,10 @@ java_binary( ":ExampleFuzzer_target_deploy.jar", ":ExampleValueProfileFuzzer_target_deploy.jar", ":FastJsonFuzzer_target_deploy.jar", - ":JacksonCborFuzzer_target_deploy.jar", - ":JpegImageParserFuzzer_target_deploy.jar", + ":JacksonCborFuzzer_classic_target_deploy.jar", + ":JacksonCborFuzzer_mutationFramework_target_deploy.jar", + ":JpegImageParserFuzzer_classic_target_deploy.jar", + ":JpegImageParserFuzzer_mutationFramework_target_deploy.jar", ":JsonSanitizerDenylistFuzzer_target_deploy.jar", ], ) diff --git a/examples/junit/src/test/java/com/example/BUILD.bazel b/examples/junit/src/test/java/com/example/BUILD.bazel index d8145ebbc..c75f34345 100644 --- a/examples/junit/src/test/java/com/example/BUILD.bazel +++ b/examples/junit/src/test/java/com/example/BUILD.bazel @@ -49,10 +49,11 @@ java_fuzz_target_test( ], ) -java_fuzz_target_test( - name = "ByteFuzzTest", +[java_fuzz_target_test( + name = "ByteFuzzTest_" + mode, srcs = ["ByteFuzzTest.java"], allowed_findings = ["org.opentest4j.AssertionFailedError"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, fuzzer_args = [ "-runs=0", ], @@ -67,7 +68,10 @@ java_fuzz_target_test( "//src/main/java/com/code_intelligence/jazzer/junit:fuzz_test", "@maven//:org_junit_jupiter_junit_jupiter_api", ], -) +) for mode in [ + "classic", + "mutationFramework", +]] java_fuzz_target_test( name = "PerExecutionLifecycleFuzzTest", @@ -94,10 +98,11 @@ java_fuzz_target_test( ], ) -java_fuzz_target_test( - name = "PerExecutionLifecycleWithFindingFuzzTest", +[java_fuzz_target_test( + name = "PerExecutionLifecycleWithFindingFuzzTest_" + mode, srcs = ["PerExecutionLifecycleWithFindingFuzzTest.java"], allowed_findings = ["java.io.IOException"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, expected_warning_or_error = "ERROR: com.example.TestSuccessfulException: Lifecycle methods invoked as expected", fuzzer_args = [ "-runs=3", @@ -116,7 +121,10 @@ java_fuzz_target_test( "@maven//:com_google_truth_truth", "@maven//:org_junit_jupiter_junit_jupiter_api", ], -) +) for mode in [ + "classic", + "mutationFramework", +]] java_fuzz_target_test( name = "PerTestLifecycleFuzzTest", @@ -183,13 +191,14 @@ java_fuzz_target_test( ) # Verifies that fuzzer command-line arguments are honored for @FuzzTests. -java_fuzz_target_test( - name = "CommandLineFuzzTest", +[java_fuzz_target_test( + name = "CommandLineFuzzTest_" + mode, srcs = ["CommandLineFuzzTest.java"], allowed_findings = ["java.lang.Error"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, fuzzer_args = [ # Ignore the first two findings. - "--ignore=d5e250a5298b81e6,d86371e6d41739ec", + "--ignore=d5abe997b6e1c738,c4c41efd6aa94d6c", ], target_class = "com.example.CommandLineFuzzTest", verify_crash_reproducer = False, @@ -201,18 +210,23 @@ java_fuzz_target_test( "//src/main/java/com/code_intelligence/jazzer/junit:fuzz_test", "@maven//:org_junit_jupiter_junit_jupiter_api", ], -) +) for mode in [ + "classic", + "mutationFramework", +]] # Verify that Mockito is properly ignored. # Using version 5+ could otherwise introduce cyclic instrumentation. -java_fuzz_target_test( - name = "MockitoFuzzTest", +[java_fuzz_target_test( + name = "MockitoFuzzTest_" + mode, srcs = ["MockitoFuzzTest.java"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, fuzzer_args = [ "-runs=1", ], tags = ["no-jdk8"], target_class = "com.example.MockitoFuzzTest", + verify_crash_reproducer = True if mode == "classic" else False, runtime_deps = [ ":junit_runtime", ], @@ -222,7 +236,10 @@ java_fuzz_target_test( "@maven//:org_junit_jupiter_junit_jupiter_api", "@maven//:org_mockito_mockito_core", ], -) +) for mode in [ + "classic", + "mutationFramework", +]] java_fuzz_target_test( name = "CharArrayWithLengthFuzzTest", @@ -289,7 +306,10 @@ java_fuzz_target_test( name = "JavaBinarySeedFuzzTest", srcs = ["JavaBinarySeedFuzzTest.java"], allowed_findings = ["java.lang.Error"], - env = {"JAZZER_FUZZ": "1"}, + env = { + "JAZZER_FUZZ": "1", + "JAZZER_MUTATOR_FRAMEWORK": "false", + }, target_class = "com.example.JavaBinarySeedFuzzTest", verify_crash_reproducer = False, runtime_deps = [ diff --git a/examples/junit/src/test/java/com/example/ByteFuzzTest.java b/examples/junit/src/test/java/com/example/ByteFuzzTest.java index 94baf3fc7..283a5865d 100644 --- a/examples/junit/src/test/java/com/example/ByteFuzzTest.java +++ b/examples/junit/src/test/java/com/example/ByteFuzzTest.java @@ -19,10 +19,11 @@ import static org.junit.jupiter.api.Assertions.fail; import com.code_intelligence.jazzer.junit.FuzzTest; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; class ByteFuzzTest { @FuzzTest - void byteFuzz(byte[] data) { + void byteFuzz(byte @NotNull [] data) { if (data.length < 1) { return; } diff --git a/examples/junit/src/test/java/com/example/CommandLineFuzzTest.java b/examples/junit/src/test/java/com/example/CommandLineFuzzTest.java index f4ec8d64f..52f24d127 100644 --- a/examples/junit/src/test/java/com/example/CommandLineFuzzTest.java +++ b/examples/junit/src/test/java/com/example/CommandLineFuzzTest.java @@ -19,12 +19,13 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue; import com.code_intelligence.jazzer.junit.FuzzTest; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; class CommandLineFuzzTest { int run = 0; @FuzzTest - void commandLineFuzz(byte[] bytes) { + void commandLineFuzz(byte @NotNull [] bytes) { assumeTrue(bytes.length > 0); switch (run++) { case 0: diff --git a/examples/junit/src/test/java/com/example/MockitoFuzzTest.java b/examples/junit/src/test/java/com/example/MockitoFuzzTest.java index 8aa665f1c..690ac325a 100644 --- a/examples/junit/src/test/java/com/example/MockitoFuzzTest.java +++ b/examples/junit/src/test/java/com/example/MockitoFuzzTest.java @@ -17,6 +17,7 @@ package com.example; import com.code_intelligence.jazzer.junit.FuzzTest; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; import org.mockito.Mockito; public class MockitoFuzzTest { @@ -27,7 +28,7 @@ public String bar(String ignored) { } @FuzzTest - void fuzzWithMockito(byte[] bytes) { + void fuzzWithMockito(byte @NotNull [] bytes) { // Mock the Foo class to trigger an instrumentation cycle, // if not properly ignored. Foo foo = Mockito.mock(Foo.class); diff --git a/examples/junit/src/test/java/com/example/PerExecutionLifecycleWithFindingFuzzTest.java b/examples/junit/src/test/java/com/example/PerExecutionLifecycleWithFindingFuzzTest.java index fe553e983..323471849 100644 --- a/examples/junit/src/test/java/com/example/PerExecutionLifecycleWithFindingFuzzTest.java +++ b/examples/junit/src/test/java/com/example/PerExecutionLifecycleWithFindingFuzzTest.java @@ -20,6 +20,7 @@ import com.code_intelligence.jazzer.junit.FuzzTest; import com.code_intelligence.jazzer.junit.Lifecycle; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -35,7 +36,7 @@ static void beforeAll() { } @FuzzTest(maxExecutions = RUNS, lifecycle = Lifecycle.PER_EXECUTION) - void lifecycleFuzz(byte[] data) throws IOException { + void lifecycleFuzz(byte @NotNull [] data) throws IOException { addEvent("lifecycleFuzz"); if (data.length != 0) { throw new IOException( diff --git a/examples/src/main/java/com/example/ExampleOutOfMemoryFuzzer.java b/examples/src/main/java/com/example/ExampleOutOfMemoryFuzzer.java index 871e41c47..d173083d7 100644 --- a/examples/src/main/java/com/example/ExampleOutOfMemoryFuzzer.java +++ b/examples/src/main/java/com/example/ExampleOutOfMemoryFuzzer.java @@ -16,10 +16,12 @@ package com.example; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; + public class ExampleOutOfMemoryFuzzer { public static long[] leak; - public static void fuzzerTestOneInput(byte[] input) { + public static void fuzzerTestOneInput(byte @NotNull [] input) { if (input.length == 0) { return; } diff --git a/examples/src/main/java/com/example/GifImageParserFuzzer.java b/examples/src/main/java/com/example/GifImageParserFuzzer.java index 9557971ac..5f51e9945 100644 --- a/examples/src/main/java/com/example/GifImageParserFuzzer.java +++ b/examples/src/main/java/com/example/GifImageParserFuzzer.java @@ -16,6 +16,7 @@ package com.example; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; import java.io.IOException; import java.util.HashMap; import org.apache.commons.imaging.ImageReadException; @@ -25,7 +26,7 @@ // Found https://issues.apache.org/jira/browse/IMAGING-277 and // https://issues.apache.org/jira/browse/IMAGING-278. public class GifImageParserFuzzer { - public static void fuzzerTestOneInput(byte[] input) { + public static void fuzzerTestOneInput(byte @NotNull [] input) { try { new GifImageParser().getBufferedImage(new ByteSourceArray(input), new HashMap<>()); } catch (IOException | ImageReadException ignored) { diff --git a/examples/src/main/java/com/example/JacksonCborFuzzer.java b/examples/src/main/java/com/example/JacksonCborFuzzer.java index 9be82d00e..e317e56ca 100644 --- a/examples/src/main/java/com/example/JacksonCborFuzzer.java +++ b/examples/src/main/java/com/example/JacksonCborFuzzer.java @@ -16,6 +16,7 @@ package com.example; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.cbor.CBORFactory; import java.io.IOException; @@ -24,7 +25,7 @@ // https://github.com/FasterXML/jackson-databind/pull/3032 if executed with // `--keep_going=3 -seed=2735196724`. public class JacksonCborFuzzer { - public static void fuzzerTestOneInput(byte[] input) { + public static void fuzzerTestOneInput(byte @NotNull [] input) { CBORFactory factory = new CBORFactory(); ObjectMapper mapper = new ObjectMapper(factory); mapper.enableDefaultTyping(); diff --git a/examples/src/main/java/com/example/JpegImageParserFuzzer.java b/examples/src/main/java/com/example/JpegImageParserFuzzer.java index 129549b2a..82e281d2d 100644 --- a/examples/src/main/java/com/example/JpegImageParserFuzzer.java +++ b/examples/src/main/java/com/example/JpegImageParserFuzzer.java @@ -16,6 +16,7 @@ package com.example; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; import java.io.IOException; import java.util.HashMap; import org.apache.commons.imaging.ImageReadException; @@ -24,7 +25,7 @@ // Found https://issues.apache.org/jira/browse/IMAGING-275. public class JpegImageParserFuzzer { - public static void fuzzerTestOneInput(byte[] input) { + public static void fuzzerTestOneInput(byte @NotNull [] input) { try { new JpegImageParser().getBufferedImage(new ByteSourceArray(input), new HashMap<>()); } catch (IOException | ImageReadException ignored) { diff --git a/examples/src/main/java/com/example/MazeFuzzer.java b/examples/src/main/java/com/example/MazeFuzzer.java index 9d42a259b..251f262c8 100644 --- a/examples/src/main/java/com/example/MazeFuzzer.java +++ b/examples/src/main/java/com/example/MazeFuzzer.java @@ -18,6 +18,7 @@ import com.code_intelligence.jazzer.api.Consumer3; import com.code_intelligence.jazzer.api.Jazzer; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; import java.util.Arrays; import java.util.Objects; import java.util.stream.Collectors; @@ -56,7 +57,7 @@ public final class MazeFuzzer { private static final char[][] MAZE = parseMaze(); private static final char[][] REACHED_FIELDS = parseMaze(); - public static void fuzzerTestOneInput(byte[] commands) { + public static void fuzzerTestOneInput(byte @NotNull [] commands) { executeCommands( commands, (x, y, won) -> { diff --git a/sanitizers/src/test/java/com/example/BUILD.bazel b/sanitizers/src/test/java/com/example/BUILD.bazel index 76a1d32eb..1c5f25d2c 100644 --- a/sanitizers/src/test/java/com/example/BUILD.bazel +++ b/sanitizers/src/test/java/com/example/BUILD.bazel @@ -1,18 +1,26 @@ load("//bazel:compat.bzl", "SKIP_ON_MACOS") load("//bazel:fuzz_target.bzl", "java_fuzz_target_test") -java_fuzz_target_test( - name = "ObjectInputStreamDeserialization", - srcs = [ - "ObjectInputStreamDeserialization.java", - ], - allowed_findings = [ - "com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh", - "java.lang.ExceptionInInitializerError", - ], - tags = ["dangerous"], - target_class = "com.example.ObjectInputStreamDeserialization", -) +[ + java_fuzz_target_test( + name = "ObjectInputStreamDeserialization_" + mode, + srcs = [ + "ObjectInputStreamDeserialization.java", + ], + allowed_findings = [ + "com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh", + "java.lang.ExceptionInInitializerError", + ], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, + tags = ["dangerous"], + target_class = "com.example.ObjectInputStreamDeserialization", + verify_crash_reproducer = True if mode == "classic" else False, + ) + for mode in [ + "classic", + "mutationFramework", + ] +] java_fuzz_target_test( name = "ReflectiveCall", diff --git a/selffuzz/src/test/java/com/code_intelligence/selffuzz/mutation/ArgumentsMutatorFuzzTest.java b/selffuzz/src/test/java/com/code_intelligence/selffuzz/mutation/ArgumentsMutatorFuzzTest.java index 1e1eef478..98c3e70cb 100644 --- a/selffuzz/src/test/java/com/code_intelligence/selffuzz/mutation/ArgumentsMutatorFuzzTest.java +++ b/selffuzz/src/test/java/com/code_intelligence/selffuzz/mutation/ArgumentsMutatorFuzzTest.java @@ -226,6 +226,8 @@ void fuzzPrimitiveArrays( if (l0 != null) assertThat(l0.length).isAtMost(3); if (by0 != null) assertThat(by0.length).isAtMost(3); if (s0 != null) assertThat(s0.length).isAtMost(3); + if (b1 != null) assertThat(b1.length).isAtMost(1000); + if (by1 != null) assertThat(by1.length).isAtMost(4096); } enum MyEnum { diff --git a/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java b/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java index 6c7106d57..3d87e4924 100644 --- a/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java +++ b/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java @@ -140,7 +140,7 @@ public final class FuzzTargetRunner { useMutatorFramework = Opt.mutatorFramework.get() && Opt.autofuzz.get().isEmpty() - && !(fuzzTarget.usesPrimitiveByteArray() || fuzzTarget.usesFuzzedDataProvider()); + && !fuzzTarget.usesFuzzedDataProvider(); useFuzzedDataProvider = fuzzTarget.usesFuzzedDataProvider(); if (!useFuzzedDataProvider && IS_ANDROID) { diff --git a/src/main/java/com/code_intelligence/jazzer/mutation/mutator/lang/PrimitiveArrayMutatorFactory.java b/src/main/java/com/code_intelligence/jazzer/mutation/mutator/lang/PrimitiveArrayMutatorFactory.java index 01ae3fca8..777cb90c3 100644 --- a/src/main/java/com/code_intelligence/jazzer/mutation/mutator/lang/PrimitiveArrayMutatorFactory.java +++ b/src/main/java/com/code_intelligence/jazzer/mutation/mutator/lang/PrimitiveArrayMutatorFactory.java @@ -73,6 +73,8 @@ public Optional> tryCreate( public static final class PrimitiveArrayMutator extends SerializingMutator { private static final int DEFAULT_MIN_LENGTH = 0; private static final int DEFAULT_MAX_LENGTH = 1000; + // This default is chosen to match libFuzzer's default max length for byte arrays. + private static final int DEFAULT_BYTE_ARRAY_MAX_LENGTH = 4096; private static final Charset FUZZED_DATA_CHARSET = Charset.forName("CESU-8"); private long minRange; private long maxRange; @@ -216,7 +218,12 @@ private void extractRange(AnnotatedType type) { private void extractLength(AnnotatedType type) { Optional withLength = Optional.ofNullable(type.getAnnotation(WithLength.class)); minLength = withLength.map(WithLength::min).orElse(DEFAULT_MIN_LENGTH); - maxLength = withLength.map(WithLength::max).orElse(DEFAULT_MAX_LENGTH); + // Different default max lengths for byte[] and other primitive arrays to match libFuzzer. + int defaultMaxLength = + type.getType().getTypeName().equals("byte[]") + ? DEFAULT_BYTE_ARRAY_MAX_LENGTH + : DEFAULT_MAX_LENGTH; + maxLength = withLength.map(WithLength::max).orElse(defaultMaxLength); } private AnnotatedType convertWithLength(AnnotatedType type, AnnotatedType newType) { diff --git a/src/test/java/com/code_intelligence/jazzer/driver/BUILD.bazel b/src/test/java/com/code_intelligence/jazzer/driver/BUILD.bazel index 4398eda58..fc57fd079 100644 --- a/src/test/java/com/code_intelligence/jazzer/driver/BUILD.bazel +++ b/src/test/java/com/code_intelligence/jazzer/driver/BUILD.bazel @@ -3,6 +3,7 @@ load("@contrib_rules_jvm//java:defs.bzl", "JUNIT5_DEPS", "java_junit5_test") java_test( name = "FuzzTargetRunnerTest", srcs = ["FuzzTargetRunnerTest.java"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"}, jvm_flags = [ "-ea", "-XX:+IgnoreUnrecognizedVMOptions", diff --git a/src/test/java/com/code_intelligence/jazzer/junit/BUILD.bazel b/src/test/java/com/code_intelligence/jazzer/junit/BUILD.bazel index 9da48a9d3..e4335007b 100644 --- a/src/test/java/com/code_intelligence/jazzer/junit/BUILD.bazel +++ b/src/test/java/com/code_intelligence/jazzer/junit/BUILD.bazel @@ -86,6 +86,7 @@ java_test( srcs = ["FuzzingWithCrashTest.java"], env = { "JAZZER_FUZZ": JAZZER_FUZZ, + "JAZZER_MUTATOR_FRAMEWORK": "false", }, test_class = "com.code_intelligence.jazzer.junit.FuzzingWithCrashTest", runtime_deps = [ @@ -118,6 +119,7 @@ java_test( srcs = ["FuzzingWithoutCrashTest.java"], env = { "JAZZER_FUZZ": JAZZER_FUZZ, + "JAZZER_MUTATOR_FRAMEWORK": "false", }, test_class = "com.code_intelligence.jazzer.junit.FuzzingWithoutCrashTest", runtime_deps = [ @@ -147,6 +149,7 @@ java_test( srcs = ["ValueProfileTest.java"], env = { "JAZZER_FUZZ": "true", + "JAZZER_MUTATOR_FRAMEWORK": "false", "JAZZER_VALUE_PROFILE": str(JAZZER_VALUE_PROFILE), }, # The test is both CPU-intensive and sensitive to timing, which causes it to be flaky on @@ -251,6 +254,7 @@ java_test( srcs = ["PerExecutionLifecycleTest.java"], env = { "JAZZER_FUZZ": JAZZER_FUZZ, + "JAZZER_MUTATOR_FRAMEWORK": "false", }, test_class = "com.code_intelligence.jazzer.junit.PerExecutionLifecycleTest", runtime_deps = [ diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/lang/PrimitiveArrayMutatorTest.java b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/lang/PrimitiveArrayMutatorTest.java index 1cadd9713..5e9094650 100644 --- a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/lang/PrimitiveArrayMutatorTest.java +++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/lang/PrimitiveArrayMutatorTest.java @@ -24,10 +24,19 @@ import static com.code_intelligence.jazzer.mutation.mutator.lang.PrimitiveArrayMutatorFactory.PrimitiveArrayMutator.getLongPrimitiveArray; import static com.code_intelligence.jazzer.mutation.mutator.lang.PrimitiveArrayMutatorFactory.PrimitiveArrayMutator.getShortPrimitiveArray; import static com.code_intelligence.jazzer.mutation.mutator.lang.PrimitiveArrayMutatorFactory.PrimitiveArrayMutator.makePrimitiveArrayToBytesConverter; +import static com.code_intelligence.jazzer.mutation.support.TypeSupport.notNull; +import static com.code_intelligence.jazzer.mutation.support.TypeSupport.withLength; import static com.google.common.truth.Truth.assertThat; import static org.junit.jupiter.params.provider.Arguments.arguments; +import com.code_intelligence.jazzer.mutation.api.SerializingMutator; +import com.code_intelligence.jazzer.mutation.engine.ChainedMutatorFactory; import com.code_intelligence.jazzer.mutation.support.TypeHolder; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; import java.lang.reflect.AnnotatedArrayType; import java.lang.reflect.AnnotatedType; import java.util.function.Function; @@ -636,4 +645,68 @@ void testRoundTrip_bytes(byte[] numbers) { assertThat(libfuzzerBytesToBytes.apply(bytesToLibfuzzerBytes.apply(numbers))) .isEqualTo(numbers); } + + /* + Testing that the maxRange for the byte[] type is 4096 bytes, which is the default max range for byte[] in Jazzer. + This is important to ensure that the mutator does not generate byte arrays that are too large, which could lead to out-of-memory errors during fuzzing. + */ + static Stream byteArrayLength() { + AnnotatedType defaultLen = new TypeHolder() {}.annotatedType(); + AnnotatedType defaultLenNN = notNull(new TypeHolder() {}.annotatedType()); + AnnotatedType withLen_10_20 = withLength(new TypeHolder() {}.annotatedType(), 10, 20); + AnnotatedType withLen_10_5000 = + withLength(new TypeHolder() {}.annotatedType(), 10, 5000); + AnnotatedType withLen_10_20_NN = + withLength(notNull(new TypeHolder() {}.annotatedType()), 10, 20); + AnnotatedType withLen_10_5000_NN = + withLength(notNull(new TypeHolder() {}.annotatedType()), 10, 5000); + // type, numBytes to serialize with write(), expectedNumBytes after deserialization with read() + return Stream.of( + arguments(defaultLen, 5000, 4096), + arguments(defaultLen, 100, 100), + arguments(defaultLen, 0, 0), + arguments(defaultLenNN, 5000, 4096), + arguments(defaultLenNN, 100, 100), + arguments(defaultLenNN, 0, 0), + arguments(withLen_10_20, 15, 15), + arguments(withLen_10_20, 25, 20), + arguments(withLen_10_5000, 15, 15), + arguments(withLen_10_5000, 25, 25), + arguments(withLen_10_5000, 5000, 5000), + arguments(withLen_10_5000, 10000, 5000), + arguments(withLen_10_20_NN, 15, 15), + arguments(withLen_10_20_NN, 25, 20), + arguments(withLen_10_5000_NN, 15, 15), + arguments(withLen_10_5000_NN, 25, 25), + arguments(withLen_10_5000_NN, 5000, 5000), + arguments(withLen_10_5000_NN, 10000, 5000)); + } + + @ParameterizedTest + @MethodSource("byteArrayLength") + public void testByteArrayMaxRange_writeReadWithLength( + AnnotatedType type, int serializationLength, int expectedReadLength) throws IOException { + ChainedMutatorFactory factory = ChainedMutatorFactory.of(LangMutators.newFactories()); + SerializingMutator mutator = (SerializingMutator) factory.createOrThrow(type); + + byte[] serialized; + + // serialize with write() + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + mutator.write(new byte[serializationLength], new DataOutputStream(baos)); + serialized = baos.toByteArray(); + + // deserialize with read() + byte[] data = mutator.read(new DataInputStream(new ByteArrayInputStream(serialized))); + assertThat(data.length).isEqualTo(expectedReadLength); + + // serialize with writeExclusive() + baos = new ByteArrayOutputStream(); + mutator.writeExclusive(new byte[serializationLength], new DataOutputStream(baos)); + serialized = baos.toByteArray(); + + // deserialize with readExclusive() + data = mutator.readExclusive(new DataInputStream(new ByteArrayInputStream(serialized))); + assertThat(data.length).isEqualTo(expectedReadLength); + } } diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index b3d88e1a0..37566762e 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -13,6 +13,7 @@ java_fuzz_target_test( data = ["src/test/java/com/example/LongStringFuzzerInput"], # Additionally verify that Jazzer-Fuzz-Target-Class is picked up if --target_class isn't set. deploy_manifest_lines = ["Jazzer-Fuzz-Target-Class: com.example.LongStringFuzzer"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"}, fuzzer_args = [ "$(rlocationpath src/test/java/com/example/LongStringFuzzerInput)", ], @@ -73,8 +74,8 @@ java_fuzz_target_test( ], ) -java_fuzz_target_test( - name = "ForkModeFuzzer", +[java_fuzz_target_test( + name = "ForkModeFuzzer_" + mode, size = "enormous", srcs = [ "src/test/java/com/example/ForkModeFuzzer.java", @@ -82,6 +83,7 @@ java_fuzz_target_test( allowed_findings = ["com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow"], env = { "JAVA_OPTS": "-Dfoo=not_foo -Djava_opts=1", + "JAZZER_MUTATOR_FRAMEWORK": "false" if mode == "classic" else "true", }, fuzzer_args = [ "-fork=2", @@ -98,7 +100,11 @@ java_fuzz_target_test( target_class = "com.example.ForkModeFuzzer", # The exit codes of the forked libFuzzer processes are not picked up correctly. target_compatible_with = SKIP_ON_MACOS, -) + verify_crash_reproducer = True if mode == "classic" else False, +) for mode in [ + "classic", + "mutationFramework", +]] java_fuzz_target_test( name = "CoverageFuzzer", @@ -299,6 +305,7 @@ java_fuzz_target_test( data = [ "src/test/java/com/example/JUnitReproducerTest.seed", ], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"}, fuzzer_args = [ "$(rlocationpath src/test/java/com/example/JUnitReproducerTest.seed)", ], @@ -437,6 +444,7 @@ sh_test( "@jacocoagent//file:jacocoagent.jar", "@jacococli//file:jacococli.jar", ], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"}, target_compatible_with = LINUX_ONLY, ) @@ -572,13 +580,18 @@ java_fuzz_target_test( ], ) -java_fuzz_target_test( - name = "SilencedFuzzer", +[java_fuzz_target_test( + name = "SilencedFuzzer_" + mode, timeout = "short", srcs = ["src/test/java/com/example/SilencedFuzzer.java"], allowed_findings = ["com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, target_class = "com.example.SilencedFuzzer", -) + verify_crash_reproducer = True if mode == "classic" else False, +) for mode in [ + "classic", + "mutationFramework", +]] java_binary( name = "jacococli", @@ -603,22 +616,27 @@ cp jacoco-instrumented/*.jar $@ tools = [":jacococli"], ) -java_fuzz_target_test( - name = "OfflineInstrumentedFuzzer", +[java_fuzz_target_test( + name = "OfflineInstrumentedFuzzer_" + mode, timeout = "short", srcs = ["src/test/java/com/example/OfflineInstrumentedFuzzer.java"], allowed_findings = ["java.lang.IllegalStateException"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, fuzzer_args = [ # Do not instrument the JaCoCo agent. "--instrumentation_includes=com.example.*", "--custom_hook_includes=com.example.*", ], target_class = "com.example.OfflineInstrumentedFuzzer", + verify_crash_reproducer = True if mode == "classic" else False, deps = [ ":OfflineInstrumentedTargetInstrumented", "@jacocoagent//file:jacocoagent.jar", # Offline instrumented classes depend on the jacoco agent ], -) +) for mode in [ + "classic", + "mutationFramework", +]] # TODO: Move to //examples eventually. java_fuzz_target_test( @@ -783,38 +801,52 @@ java_fuzz_target_test( ], ) -java_fuzz_target_test( - name = "StringCompareFuzzer", +[java_fuzz_target_test( + name = "StringCompareFuzzer_" + mode, srcs = ["src/test/java/com/example/StringCompareFuzzer.java"], allowed_findings = ["com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, fuzzer_args = [ "-use_value_profile=1", ], target_class = "com.example.StringCompareFuzzer", -) + verify_crash_reproducer = True if mode == "classic" else False, +) for mode in [ + "classic", + "mutationFramework", +]] kt_jvm_library( name = "kotlin_string_compare_fuzzer", srcs = ["src/test/java/com/example/KotlinStringCompareFuzzer.kt"], + deps = [ + "//deploy:jazzer-api", + ], ) -java_fuzz_target_test( - name = "KotlinStringCompareFuzzer", +[java_fuzz_target_test( + name = "KotlinStringCompareFuzzer_" + mode, allowed_findings = ["java.io.IOException"], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, fuzzer_args = [ "-use_value_profile=1", ], target_class = "com.example.KotlinStringCompareFuzzer", + verify_crash_reproducer = True if mode == "classic" else False, runtime_deps = [":kotlin_string_compare_fuzzer"], -) +) for mode in [ + "classic", + "mutationFramework", +]] -java_fuzz_target_test( - name = "ObjectEqualsStringFuzzer", +[java_fuzz_target_test( + name = "ObjectEqualsStringFuzzer_" + mode, timeout = "short", srcs = ["src/test/java/com/example/ObjectEqualsStringFuzzer.java"], allowed_findings = [ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow", ], + env = {"JAZZER_MUTATOR_FRAMEWORK": "false"} if mode == "classic" else {}, target_class = "com.example.ObjectEqualsStringFuzzer", verify_crash_reproducer = False, runtime_deps = [ @@ -825,7 +857,10 @@ java_fuzz_target_test( "@maven//:org_junit_jupiter_junit_jupiter_api", "@maven//:org_junit_jupiter_junit_jupiter_params", ], -) +) for mode in [ + "classic", + "mutationFramework", +]] java_fuzz_target_test( name = "ObjectEqualsIntegerFuzzer", diff --git a/tests/src/test/java/com/example/KotlinStringCompareFuzzer.kt b/tests/src/test/java/com/example/KotlinStringCompareFuzzer.kt index 312b9ee9e..354a8cdd5 100644 --- a/tests/src/test/java/com/example/KotlinStringCompareFuzzer.kt +++ b/tests/src/test/java/com/example/KotlinStringCompareFuzzer.kt @@ -23,7 +23,10 @@ import kotlin.io.encoding.ExperimentalEncodingApi object KotlinStringCompareFuzzer { @JvmStatic @OptIn(ExperimentalEncodingApi::class) - fun fuzzerTestOneInput(data: ByteArray) { + fun fuzzerTestOneInput(data: ByteArray?) { + if (data == null) { + return + } val text = Base64.encode(data) if (text.startsWith("aGVsbG8K") && // hello diff --git a/tests/src/test/java/com/example/LongStringFuzzer.java b/tests/src/test/java/com/example/LongStringFuzzer.java index dd1e8fcbf..293455382 100644 --- a/tests/src/test/java/com/example/LongStringFuzzer.java +++ b/tests/src/test/java/com/example/LongStringFuzzer.java @@ -27,6 +27,9 @@ */ public class LongStringFuzzer { public static void fuzzerTestOneInput(byte[] data) { + if (data == null) { + return; + } if (data.length > 1024 * 64) { throw new FuzzerSecurityIssueLow("String too long exception"); } diff --git a/tests/src/test/java/com/example/ObjectEqualsStringFuzzer.java b/tests/src/test/java/com/example/ObjectEqualsStringFuzzer.java index c46cc40cd..573cd5a9d 100644 --- a/tests/src/test/java/com/example/ObjectEqualsStringFuzzer.java +++ b/tests/src/test/java/com/example/ObjectEqualsStringFuzzer.java @@ -18,11 +18,12 @@ import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; import com.code_intelligence.jazzer.junit.FuzzTest; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; import java.util.Objects; public class ObjectEqualsStringFuzzer { @FuzzTest - void objectEqualsString(byte[] input) { + void objectEqualsString(byte @NotNull [] input) { String stringInput = new String(input); if (Objects.equals(stringInput, "ObjectsEqualsFuzzer")) { throw new FuzzerSecurityIssueLow("ObjectsEqualsFuzzer works!"); diff --git a/tests/src/test/java/com/example/OfflineInstrumentedFuzzer.java b/tests/src/test/java/com/example/OfflineInstrumentedFuzzer.java index 9a722ca82..cb36432b6 100644 --- a/tests/src/test/java/com/example/OfflineInstrumentedFuzzer.java +++ b/tests/src/test/java/com/example/OfflineInstrumentedFuzzer.java @@ -16,8 +16,10 @@ package com.example; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; + public class OfflineInstrumentedFuzzer { - public static void fuzzerTestOneInput(byte[] data) { + public static void fuzzerTestOneInput(byte @NotNull [] data) { OfflineInstrumentedTarget.someFunction(data); } } diff --git a/tests/src/test/java/com/example/StringCompareFuzzer.java b/tests/src/test/java/com/example/StringCompareFuzzer.java index 0ddcb23bc..7ed88efa1 100644 --- a/tests/src/test/java/com/example/StringCompareFuzzer.java +++ b/tests/src/test/java/com/example/StringCompareFuzzer.java @@ -17,10 +17,11 @@ package com.example; import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; import java.util.Base64; public class StringCompareFuzzer { - public static void fuzzerTestOneInput(byte[] data) { + public static void fuzzerTestOneInput(byte @NotNull [] data) { String text = Base64.getEncoder().encodeToString(data); if (text.startsWith("aGVsbG8K") // hello && text.endsWith("d29ybGQK") // world