diff --git a/src/main/java/com/code_intelligence/jazzer/autofuzz/Meta.java b/src/main/java/com/code_intelligence/jazzer/autofuzz/Meta.java index 6ddf537ee..3c26f255f 100644 --- a/src/main/java/com/code_intelligence/jazzer/autofuzz/Meta.java +++ b/src/main/java/com/code_intelligence/jazzer/autofuzz/Meta.java @@ -496,7 +496,7 @@ Object consume(FuzzedDataProvider data, Type genericType, AutofuzzCodegenVisitor } else { if (visitor != null) { visitor.pushGroup( - String.format("new %s[]{", type.getComponentType().getName()), ", ", "}"); + String.format("new %s[]{", type.getComponentType().getCanonicalName()), ", ", "}"); } int remainingBytesBeforeFirstElementCreation = data.remainingBytes(); Object firstElement = consume(data, type.getComponentType(), visitor); @@ -593,7 +593,7 @@ Object consume(FuzzedDataProvider data, Type genericType, AutofuzzCodegenVisitor } else if (type.isEnum()) { Enum enumValue = (Enum) data.pickValue(type.getEnumConstants()); if (visitor != null) { - visitor.pushElement(String.format("%s.%s", type.getName(), enumValue.name())); + visitor.pushElement(String.format("%s.%s", type.getCanonicalName(), enumValue.name())); } return enumValue; } else if (type == Class.class) { diff --git a/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java b/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java index 967de53bb..e895df42f 100644 --- a/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java +++ b/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java @@ -125,6 +125,45 @@ public void testConsume() throws NoSuchMethodException { 23, // remaining bytes "foo\nbar")); + // Test for multi-dimensional array codegen + // (https://github.com/CodeIntelligenceTesting/jazzer/issues/1026) + consumeTestCase( + int[][].class, + new int[][] {{1, 2}, {3}}, + "new int[][]{new int[]{1, 2}, new int[]{3}}", + Arrays.asList( + (byte) 1, // do not return null for the outer array + 100, // remainingBytes before first element creation + (byte) 1, // do not return null for first int[] + 50, // remainingBytes for consumeArrayLength inside first consumeInts + new int[] {1, 2}, // consumeInts returns first int[] + 40, // remainingBytes after first element creation + // sizeOfElementEstimate = 100 - 40 = 60 + // consumeArrayLength(data, 60) = remainingBytes / 2 / 60 + // need this to return 2: 240 / 2 / 60 = 2 + 240, // remainingBytes for outer consumeArrayLength + (byte) 1, // do not return null for second int[] + 50, // remainingBytes for consumeArrayLength inside second consumeInts + new int[] {3})); // consumeInts returns second int[] + + // Test that inner class arrays use getCanonicalName() (dot-separated) not getTypeName() which + // would produce '$'-separated names that are not valid Java source. + consumeTestCase( + TestEnum[].class, + new TestEnum[] {TestEnum.BAR}, + "new com.code_intelligence.jazzer.autofuzz.MetaTest.TestEnum[]{" + + "com.code_intelligence.jazzer.autofuzz.MetaTest.TestEnum.BAR}", + Arrays.asList( + (byte) 1, // do not return null for the array + 100, // remainingBytes before first element creation + (byte) 1, // do not return null for the enum value + 1, // pickValue index (BAR) + 90, // remainingBytes after first element creation + // sizeOfElementEstimate = 100 - 90 = 10 + // consumeArrayLength(data, 10) = remainingBytes / 2 / 10 + // need this to return 1: 20 / 2 / 10 = 1 + 20)); // remainingBytes for outer consumeArrayLength + byte[] testInputStreamBytes = new byte[] {(byte) 1, (byte) 2, (byte) 3}; consumeTestCase( new ByteArrayInputStream(testInputStreamBytes), @@ -136,7 +175,7 @@ public void testConsume() throws NoSuchMethodException { consumeTestCase( TestEnum.BAR, - String.format("%s.%s", TestEnum.class.getName(), TestEnum.BAR.name()), + String.format("%s.%s", TestEnum.class.getCanonicalName(), TestEnum.BAR.name()), Arrays.asList( (byte) 1, // do not return null for the enum value 1 /* second value */)); diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index 2eb9b778f..7a7fe9e0c 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -555,6 +555,23 @@ java_fuzz_target_test( ], ) +java_library( + name = "autofuzz_multi_dim_array_target", + srcs = ["src/test/java/com/example/AutofuzzMultiDimArrayTarget.java"], +) + +# Regression test for https://github.com/CodeIntelligenceTesting/jazzer/issues/1026. +java_fuzz_target_test( + name = "AutofuzzMultiDimArrayFuzzer", + allowed_findings = ["java.lang.RuntimeException"], + fuzzer_args = [ + "--autofuzz=com.example.AutofuzzMultiDimArrayTarget::new", + ], + runtime_deps = [ + ":autofuzz_multi_dim_array_target", + ], +) + java_fuzz_target_test( name = "SilencedFuzzer", timeout = "short", diff --git a/tests/src/test/java/com/example/AutofuzzMultiDimArrayTarget.java b/tests/src/test/java/com/example/AutofuzzMultiDimArrayTarget.java new file mode 100644 index 000000000..60ebfdc48 --- /dev/null +++ b/tests/src/test/java/com/example/AutofuzzMultiDimArrayTarget.java @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Code Intelligence GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example; + +// Regression test for https://github.com/CodeIntelligenceTesting/jazzer/issues/1026. +// It also uses a static inner class array parameter to verify that the reproducer codegen uses +// getCanonicalName() (dot-separated) rather than getName()/getTypeName() (which use '$' +// for inner classes and are not valid Java source). +public class AutofuzzMultiDimArrayTarget { + public static class Item { + public Item(int value) {} + } + + public AutofuzzMultiDimArrayTarget(int[][] grid, Item[] items) { + if (grid != null && grid.length > 3 && items != null && items.length > 3) { + throw new RuntimeException(); + } + } +}