This is an automated email from the ASF dual-hosted git repository.

iemejia pushed a commit to branch fuzzer
in repository https://gitbox.apache.org/repos/asf/avro.git

commit a850f5d58f4fa4118abc7fcfdeb016297753ddd5
Author: Ismaël Mejía <[email protected]>
AuthorDate: Tue Mar 31 23:01:36 2026 +0000

    Simplify fuzz targets: merge redundant tests, consolidate exception 
handling, lean POM
    
    Reduce 9 fuzz targets to 5 by merging schemas into compound targets that
    exercise the same code paths in fewer tests. Replace per-target exception
    type lists with broad catch(Exception) since any non-Error is expected for
    invalid input. Remove unused maven-jar-plugin, deduplicate jazzer.instrument
    config, and disable build cache for the non-deterministic fuzz module.
---
 lang/java/fuzz/pom.xml                             | 19 +-------
 .../org/apache/avro/fuzz/BinaryDecodingFuzzer.java | 51 ++++++----------------
 .../org/apache/avro/fuzz/DataFileReaderFuzzer.java | 30 +++++--------
 .../org/apache/avro/fuzz/JsonDecodingFuzzer.java   | 41 ++++++-----------
 .../java/org/apache/avro/fuzz/SchemaFuzzer.java    | 26 +++--------
 5 files changed, 46 insertions(+), 121 deletions(-)

diff --git a/lang/java/fuzz/pom.xml b/lang/java/fuzz/pom.xml
index 970b05c523..ec06ca2add 100644
--- a/lang/java/fuzz/pom.xml
+++ b/lang/java/fuzz/pom.xml
@@ -36,6 +36,8 @@
   <properties>
     <jazzer.version>0.22.1</jazzer.version>
     <main.basedir>${project.parent.parent.basedir}</main.basedir>
+    <!-- Fuzz tests are non-deterministic; never serve results from cache -->
+    <maven.build.cache.enabled>false</maven.build.cache.enabled>
   </properties>
 
   <build>
@@ -54,22 +56,6 @@
           <forkCount>1</forkCount>
           <reuseForks>true</reuseForks>
           <redirectTestOutputToFile>false</redirectTestOutputToFile>
-          <properties>
-            <configurationParameters>
-              jazzer.instrument = org.apache.avro.**
-            </configurationParameters>
-          </properties>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestEntries>
-              
<Automatic-Module-Name>org.apache.avro.fuzz</Automatic-Module-Name>
-            </manifestEntries>
-          </archive>
         </configuration>
       </plugin>
     </plugins>
@@ -92,7 +78,6 @@
                 <configurationParameters>
                   jazzer.internal.command_line = true
                   jazzer.duration = 60s
-                  jazzer.instrument = org.apache.avro.**
                 </configurationParameters>
               </properties>
             </configuration>
diff --git 
a/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/BinaryDecodingFuzzer.java 
b/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/BinaryDecodingFuzzer.java
index 4912d89b31..e253c3422e 100644
--- 
a/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/BinaryDecodingFuzzer.java
+++ 
b/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/BinaryDecodingFuzzer.java
@@ -18,7 +18,6 @@
 package org.apache.avro.fuzz;
 
 import com.code_intelligence.jazzer.junit.FuzzTest;
-import org.apache.avro.AvroRuntimeException;
 import org.apache.avro.Schema;
 import org.apache.avro.generic.GenericDatumReader;
 import org.apache.avro.generic.GenericRecord;
@@ -32,58 +31,36 @@ import java.io.IOException;
  *
  * <p>
  * Feeds arbitrary bytes through {@link BinaryDecoder} and
- * {@link GenericDatumReader} using several representative schemas to exercise
- * varint parsing, buffer management, nested record handling, and collection
- * size limit enforcement.
+ * {@link GenericDatumReader} using a compound schema that exercises varint
+ * parsing, buffer management, nested records, enums, arrays, maps, unions, and
+ * collection size limit enforcement in a single target.
  * </p>
  */
 class BinaryDecodingFuzzer {
 
-  /** A record schema with multiple field types to exercise diverse code 
paths. */
-  private static final Schema RECORD_SCHEMA = new Schema.Parser()
-      .parse("{\"type\":\"record\",\"name\":\"TestRecord\",\"fields\":[" + 
"{\"name\":\"id\",\"type\":\"long\"},"
+  /**
+   * A compound schema that nests records, enums, arrays, maps, and unions to
+   * maximise code coverage from a single fuzz target.
+   */
+  private static final Schema SCHEMA = new Schema.Parser()
+      .parse("{\"type\":\"record\",\"name\":\"Root\",\"fields\":[" + 
"{\"name\":\"id\",\"type\":\"long\"},"
           + "{\"name\":\"name\",\"type\":\"string\"}," + 
"{\"name\":\"value\",\"type\":\"double\"},"
           + 
"{\"name\":\"tags\",\"type\":{\"type\":\"array\",\"items\":\"string\"}},"
           + 
"{\"name\":\"metadata\",\"type\":{\"type\":\"map\",\"values\":\"string\"}},"
-          + "{\"name\":\"optionalField\",\"type\":[\"null\",\"string\"]}" + 
"]}");
-
-  /** A schema with nested records to test recursive decoding. */
-  private static final Schema NESTED_SCHEMA = new Schema.Parser()
-      .parse("{\"type\":\"record\",\"name\":\"Outer\",\"fields\":["
+          + "{\"name\":\"optionalField\",\"type\":[\"null\",\"string\"]},"
           + 
"{\"name\":\"inner\",\"type\":{\"type\":\"record\",\"name\":\"Inner\",\"fields\":["
-          + "{\"name\":\"x\",\"type\":\"int\"}," + 
"{\"name\":\"y\",\"type\":\"int\"}" + "]}},"
-          + "{\"name\":\"label\",\"type\":\"string\"}" + "]}");
-
-  /** An enum schema. */
-  private static final Schema ENUM_SCHEMA = new Schema.Parser()
-      .parse("{\"type\":\"record\",\"name\":\"EnumRecord\",\"fields\":["
+          + 
"{\"name\":\"x\",\"type\":\"int\"},{\"name\":\"y\",\"type\":\"int\"}]}},"
           + 
"{\"name\":\"status\",\"type\":{\"type\":\"enum\",\"name\":\"Status\","
           + "\"symbols\":[\"ACTIVE\",\"INACTIVE\",\"PENDING\"]}}," + 
"{\"name\":\"count\",\"type\":\"int\"}" + "]}");
 
   @FuzzTest
-  void fuzzBinaryDecodingRecord(byte[] data) {
-    decodeWithSchema(data, RECORD_SCHEMA);
-  }
-
-  @FuzzTest
-  void fuzzBinaryDecodingNested(byte[] data) {
-    decodeWithSchema(data, NESTED_SCHEMA);
-  }
-
-  @FuzzTest
-  void fuzzBinaryDecodingEnum(byte[] data) {
-    decodeWithSchema(data, ENUM_SCHEMA);
-  }
-
-  private static void decodeWithSchema(byte[] data, Schema schema) {
+  void fuzzBinaryDecoding(byte[] data) {
     try {
       BinaryDecoder decoder = DecoderFactory.get().binaryDecoder(data, null);
-      GenericDatumReader<GenericRecord> reader = new 
GenericDatumReader<>(schema);
+      GenericDatumReader<GenericRecord> reader = new 
GenericDatumReader<>(SCHEMA);
       reader.read(null, decoder);
-    } catch (IOException | AvroRuntimeException | 
ArrayIndexOutOfBoundsException | UnsupportedOperationException e) {
+    } catch (Exception e) {
       // Expected for malformed binary data
-      // UnsupportedOperationException: thrown by SystemLimitException for 
oversized
-      // strings/collections
     }
   }
 }
diff --git 
a/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/DataFileReaderFuzzer.java 
b/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/DataFileReaderFuzzer.java
index fd12ec7109..5e274f36a6 100644
--- 
a/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/DataFileReaderFuzzer.java
+++ 
b/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/DataFileReaderFuzzer.java
@@ -18,7 +18,6 @@
 package org.apache.avro.fuzz;
 
 import com.code_intelligence.jazzer.junit.FuzzTest;
-import org.apache.avro.AvroRuntimeException;
 import org.apache.avro.file.DataFileReader;
 import org.apache.avro.file.DataFileStream;
 import org.apache.avro.file.SeekableByteArrayInput;
@@ -26,7 +25,6 @@ import org.apache.avro.generic.GenericDatumReader;
 import org.apache.avro.generic.GenericRecord;
 
 import java.io.ByteArrayInputStream;
-import java.io.IOException;
 
 /**
  * Fuzz tests for Avro data file (container format) reading.
@@ -35,19 +33,15 @@ import java.io.IOException;
  * Feeds arbitrary bytes through {@link DataFileReader} and
  * {@link DataFileStream} to test the full Avro container format parsing: magic
  * bytes, file header, metadata (including the embedded schema), sync markers,
- * codec decompression, and datum deserialization. This is the highest-value
- * target for finding container format vulnerabilities.
+ * codec decompression, and datum deserialization.
  * </p>
  */
 class DataFileReaderFuzzer {
 
   /**
-   * Fuzz the seekable {@link DataFileReader} path.
-   *
-   * <p>
-   * Uses {@link SeekableByteArrayInput} to wrap the fuzz input, which 
exercises
-   * the random-access container file reading code path including block 
seeking.
-   * </p>
+   * Fuzz the seekable {@link DataFileReader} path via
+   * {@link SeekableByteArrayInput}, exercising random-access container file
+   * reading including block seeking.
    */
   @FuzzTest
   void fuzzDataFileReader(byte[] data) {
@@ -56,19 +50,15 @@ class DataFileReaderFuzzer {
       while (reader.hasNext()) {
         reader.next();
       }
-    } catch (IOException | AvroRuntimeException | 
UnsupportedOperationException e) {
-      // Expected for malformed container files -- invalid magic, bad headers,
-      // corrupt sync markers, unsupported codecs, etc.
+    } catch (Exception e) {
+      // Expected for malformed container files
     }
   }
 
   /**
-   * Fuzz the streaming {@link DataFileStream} path.
-   *
-   * <p>
-   * Uses a plain {@link ByteArrayInputStream}, which exercises the sequential
-   * (non-seekable) container file reading code path.
-   * </p>
+   * Fuzz the streaming {@link DataFileStream} path via
+   * {@link ByteArrayInputStream}, exercising sequential (non-seekable) 
container
+   * file reading.
    */
   @FuzzTest
   void fuzzDataFileStream(byte[] data) {
@@ -77,7 +67,7 @@ class DataFileReaderFuzzer {
       while (stream.hasNext()) {
         stream.next();
       }
-    } catch (IOException | AvroRuntimeException | 
UnsupportedOperationException e) {
+    } catch (Exception e) {
       // Expected for malformed container files
     }
   }
diff --git 
a/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/JsonDecodingFuzzer.java 
b/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/JsonDecodingFuzzer.java
index bfb858b984..362773c838 100644
--- a/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/JsonDecodingFuzzer.java
+++ b/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/JsonDecodingFuzzer.java
@@ -18,61 +18,48 @@
 package org.apache.avro.fuzz;
 
 import com.code_intelligence.jazzer.junit.FuzzTest;
-import org.apache.avro.AvroRuntimeException;
 import org.apache.avro.Schema;
 import org.apache.avro.generic.GenericDatumReader;
 import org.apache.avro.generic.GenericRecord;
 import org.apache.avro.io.DecoderFactory;
 import org.apache.avro.io.JsonDecoder;
 
-import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 
 /**
  * Fuzz tests for Avro JSON decoding.
  *
  * <p>
- * Feeds arbitrary JSON strings through {@link JsonDecoder} with various 
schemas
- * to test the JSON-to-Avro deserialization path, including Jackson JSON
+ * Feeds arbitrary JSON strings through {@link JsonDecoder} with a compound
+ * schema to test the JSON-to-Avro deserialization path, including Jackson JSON
  * parsing, type coercion, union resolution, and error handling for malformed
  * data.
  * </p>
  */
 class JsonDecodingFuzzer {
 
-  /** A record schema with diverse field types. */
-  private static final Schema RECORD_SCHEMA = new Schema.Parser()
+  /**
+   * A compound schema with diverse field types: primitives, arrays, maps, and
+   * unions. This is a superset of the previous separate record and simple
+   * schemas.
+   */
+  private static final Schema SCHEMA = new Schema.Parser()
       .parse("{\"type\":\"record\",\"name\":\"TestRecord\",\"fields\":[" + 
"{\"name\":\"id\",\"type\":\"long\"},"
-          + "{\"name\":\"name\",\"type\":\"string\"}," + 
"{\"name\":\"active\",\"type\":\"boolean\"},"
+          + "{\"name\":\"name\",\"type\":\"string\"}," + 
"{\"name\":\"x\",\"type\":\"int\"},"
+          + "{\"name\":\"active\",\"type\":\"boolean\"},"
           + 
"{\"name\":\"scores\",\"type\":{\"type\":\"array\",\"items\":\"double\"}},"
           + 
"{\"name\":\"props\",\"type\":{\"type\":\"map\",\"values\":\"string\"}},"
           + "{\"name\":\"extra\",\"type\":[\"null\",\"string\",\"long\"]}" + 
"]}");
 
-  /** A simpler schema for basic field decoding. */
-  private static final Schema SIMPLE_SCHEMA = new Schema.Parser()
-      .parse("{\"type\":\"record\",\"name\":\"Simple\",\"fields\":[" + 
"{\"name\":\"x\",\"type\":\"int\"},"
-          + "{\"name\":\"y\",\"type\":\"string\"}" + "]}");
-
-  @FuzzTest
-  void fuzzJsonDecodingRecord(byte[] data) {
-    decodeJsonWithSchema(data, RECORD_SCHEMA);
-  }
-
   @FuzzTest
-  void fuzzJsonDecodingSimple(byte[] data) {
-    decodeJsonWithSchema(data, SIMPLE_SCHEMA);
-  }
-
-  private static void decodeJsonWithSchema(byte[] data, Schema schema) {
+  void fuzzJsonDecoding(byte[] data) {
     String jsonData = new String(data, StandardCharsets.UTF_8);
     try {
-      JsonDecoder decoder = DecoderFactory.get().jsonDecoder(schema, jsonData);
-      GenericDatumReader<GenericRecord> reader = new 
GenericDatumReader<>(schema);
+      JsonDecoder decoder = DecoderFactory.get().jsonDecoder(SCHEMA, jsonData);
+      GenericDatumReader<GenericRecord> reader = new 
GenericDatumReader<>(SCHEMA);
       reader.read(null, decoder);
-    } catch (IOException | AvroRuntimeException | 
UnsupportedOperationException e) {
+    } catch (Exception e) {
       // Expected for malformed JSON or type mismatches
-      // UnsupportedOperationException: thrown by SystemLimitException for 
oversized
-      // strings/collections
     }
   }
 }
diff --git 
a/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/SchemaFuzzer.java 
b/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/SchemaFuzzer.java
index 20cd38ddc4..f7ef7669cf 100644
--- a/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/SchemaFuzzer.java
+++ b/lang/java/fuzz/src/test/java/org/apache/avro/fuzz/SchemaFuzzer.java
@@ -18,7 +18,6 @@
 package org.apache.avro.fuzz;
 
 import com.code_intelligence.jazzer.junit.FuzzTest;
-import org.apache.avro.AvroRuntimeException;
 import org.apache.avro.Schema;
 
 import java.nio.charset.StandardCharsets;
@@ -27,34 +26,21 @@ import java.nio.charset.StandardCharsets;
  * Fuzz tests for Avro schema parsing.
  *
  * <p>
- * Targets {@link Schema#parse(String)} with arbitrary input to find crashes,
- * hangs, or unexpected exceptions in the JSON schema parser. Expected
- * exceptions like {@link SchemaParseException} are caught and ignored since
- * they represent correct rejection of invalid input.
+ * Targets {@link Schema#parse(String, boolean)} with arbitrary input and name
+ * validation enabled. Any exception is treated as expected behavior for 
invalid
+ * input; only JVM-level errors (e.g. {@link StackOverflowError}) escape and 
are
+ * reported as real findings.
  * </p>
  */
 class SchemaFuzzer {
 
   @FuzzTest
   void fuzzSchemaParse(byte[] data) {
-    String schemaJson = new String(data, StandardCharsets.UTF_8);
-    try {
-      Schema.parse(schemaJson);
-    } catch (AvroRuntimeException | IllegalArgumentException | 
NullPointerException e) {
-      // Expected for invalid schema input -- these indicate correct rejection
-      // (SchemaParseException is a subclass of AvroRuntimeException)
-      // NullPointerException: known bug in ParseContext.resolve with 
unresolved
-      // schemas
-    }
-  }
-
-  @FuzzTest
-  void fuzzSchemaParseWithValidation(byte[] data) {
     String schemaJson = new String(data, StandardCharsets.UTF_8);
     try {
       Schema.parse(schemaJson, true);
-    } catch (AvroRuntimeException | IllegalArgumentException | 
NullPointerException e) {
-      // Expected for invalid schema input -- these indicate correct rejection
+    } catch (Exception e) {
+      // Expected for invalid schema input
     }
   }
 }

Reply via email to