diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/JacksonAvroParserImpl.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/JacksonAvroParserImpl.java index 688704814..07fb43bd2 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/JacksonAvroParserImpl.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/JacksonAvroParserImpl.java @@ -700,13 +700,13 @@ private final void _finishLongText(int len) throws IOException break; case 3: // 4-byte UTF c = _decodeUTF8_4(c); - // Let's add first part right away: - outBuf[outPtr++] = (char) (0xD800 | (c >> 10)); if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; outEnd = outBuf.length; } + // Let's add first part right away: + outBuf[outPtr++] = (char) (0xD800 | (c >> 10)); c = 0xDC00 | (c & 0x3FF); // And let the other char output down below break; diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/fuzz/AvroFuzz449_65618_IOOBETest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/fuzz/AvroFuzz449_65618_65649_IOOBETest.java similarity index 61% rename from avro/src/test/java/com/fasterxml/jackson/dataformat/avro/fuzz/AvroFuzz449_65618_IOOBETest.java rename to avro/src/test/java/com/fasterxml/jackson/dataformat/avro/fuzz/AvroFuzz449_65618_65649_IOOBETest.java index 6e55c8056..c9fa0f5e0 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/fuzz/AvroFuzz449_65618_IOOBETest.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/fuzz/AvroFuzz449_65618_65649_IOOBETest.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.dataformat.avro.AvroTestBase; // [dataformats-binary#449] -public class AvroFuzz449_65618_IOOBETest extends AvroTestBase +public class AvroFuzz449_65618_65649_IOOBETest extends AvroTestBase { @JsonPropertyOrder({ "name", "value" }) static class RootType { @@ -20,26 +20,36 @@ static class RootType { public int value; } - @Test - public void testFuzz65618IOOBE() throws Exception { - final AvroFactory factory = AvroFactory.builderWithNativeDecoder().build(); - final AvroMapper mapper = new AvroMapper(factory); - - final byte[] doc = { - (byte) 2, (byte) 22, (byte) 36, (byte) 2, (byte) 0, - (byte) 0, (byte) 8, (byte) 3, (byte) 3, (byte) 3, - (byte) 122, (byte) 3, (byte) -24 - }; + final private AvroFactory factory = AvroFactory.builderWithNativeDecoder().build(); + final private AvroMapper mapper = new AvroMapper(factory); + private void testFuzzIOOBE(byte[] input, String msg) throws Exception { final AvroSchema schema = mapper.schemaFor(RootType.class); - try (AvroParser p = (AvroParser) mapper.createParser(doc)) { + try (AvroParser p = (AvroParser) mapper.createParser(input)) { p.setSchema(schema); assertToken(JsonToken.START_OBJECT, p.nextToken()); assertToken(JsonToken.FIELD_NAME, p.nextToken()); p.nextToken(); + p.nextToken(); fail("Should not pass (invalid content)"); } catch (StreamReadException e) { - verifyException(e, "Malformed 2-byte UTF-8 character at the end of"); + verifyException(e, msg); } } + + @Test + public void testFuzz65618_IOOBE() throws Exception { + final byte[] doc = { + (byte) 2, (byte) 22, (byte) 36, (byte) 2, (byte) 0, + (byte) 0, (byte) 8, (byte) 3, (byte) 3, (byte) 3, + (byte) 122, (byte) 3, (byte) -24 + }; + testFuzzIOOBE(doc, "Malformed 2-byte UTF-8 character at the end of"); + } + + @Test + public void testFuzz65649_IOOBE() throws Exception { + final byte[] doc = AvroFuzzTestUtil.readResource("/data/fuzz-65649.avro"); + testFuzzIOOBE(doc, "Invalid UTF-8 start byte 0x80"); + } } diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/fuzz/AvroFuzzTestUtil.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/fuzz/AvroFuzzTestUtil.java new file mode 100644 index 000000000..e7e6b30d4 --- /dev/null +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/fuzz/AvroFuzzTestUtil.java @@ -0,0 +1,31 @@ +package com.fasterxml.jackson.dataformat.avro.fuzz; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class AvroFuzzTestUtil +{ + public static byte[] readResource(String ref) + { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + final byte[] buf = new byte[4000]; + + InputStream in = AvroFuzzTestUtil.class.getResourceAsStream(ref); + if (in != null) { + try { + int len; + while ((len = in.read(buf)) > 0) { + bytes.write(buf, 0, len); + } + in.close(); + } catch (IOException e) { + throw new RuntimeException("Failed to read resource '"+ref+"': "+e); + } + } + if (bytes.size() == 0) { + throw new IllegalArgumentException("Failed to read resource '"+ref+"': empty resource?"); + } + return bytes.toByteArray(); + } +} diff --git a/avro/src/test/resources/data/fuzz-65649.avro b/avro/src/test/resources/data/fuzz-65649.avro new file mode 100644 index 000000000..78a1d3bcd Binary files /dev/null and b/avro/src/test/resources/data/fuzz-65649.avro differ