From d0a4a4abdc0962411c5db5cdfcd5ca3cbf95cc87 Mon Sep 17 00:00:00 2001 From: Tyler Gregg Date: Fri, 26 Jan 2024 18:49:58 -0800 Subject: [PATCH] Fixes a bug that caused the binary reader not to fail cleanly when parsing incomplete containers in certain cases. --- .../com/amazon/ion/impl/IonCursorBinary.java | 3 + .../IonReaderContinuableCoreBinaryTest.java | 71 +++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/src/main/java/com/amazon/ion/impl/IonCursorBinary.java b/src/main/java/com/amazon/ion/impl/IonCursorBinary.java index 1bfe194c28..3b5f94ca73 100644 --- a/src/main/java/com/amazon/ion/impl/IonCursorBinary.java +++ b/src/main/java/com/amazon/ion/impl/IonCursorBinary.java @@ -1574,6 +1574,9 @@ private boolean uncheckedNextToken() { if (uncheckedNextContainedToken()) { return false; } + if (peekIndex >= limit) { + throw new IonException("Malformed data: declared length exceeds the number of bytes remaining in the container."); + } b = buffer[(int)(peekIndex++)] & SINGLE_BYTE_MASK; } if (uncheckedReadHeader(b, false, valueMarker)) { diff --git a/src/test/java/com/amazon/ion/impl/IonReaderContinuableCoreBinaryTest.java b/src/test/java/com/amazon/ion/impl/IonReaderContinuableCoreBinaryTest.java index 0fc2338b5f..92091c599f 100644 --- a/src/test/java/com/amazon/ion/impl/IonReaderContinuableCoreBinaryTest.java +++ b/src/test/java/com/amazon/ion/impl/IonReaderContinuableCoreBinaryTest.java @@ -3,6 +3,7 @@ package com.amazon.ion.impl; +import com.amazon.ion.IonCursor; import com.amazon.ion.IonException; import com.amazon.ion.IonType; import org.junit.jupiter.api.Test; @@ -496,4 +497,74 @@ public void expectLobWithOverflowingEndIndexToFailCleanly(boolean constructFromB assertThrows(IonException.class, reader::nextValue); reader.close(); } + + @Test + public void expectIncompleteContainerToFailCleanlyAfterFieldSid() { + IonReaderContinuableCoreBinary reader = initializeReader( + true, + 0xE0, 0x01, 0x00, 0xEA, // IVM + 0xDC, // Struct, length 12 + 0x9A // Field SID 26 + // The struct ends unexpectedly + ); + assertEquals(IonCursor.Event.START_CONTAINER, reader.nextValue()); + assertEquals(IonType.STRUCT, reader.getType()); + reader.stepIntoContainer(); + // This is an unexpected EOF, so the reader should fail cleanly. + assertThrows(IonException.class, reader::nextValue); + reader.close(); + } + + @Test + public void expectIncompleteContainerToFailCleanlyAfterTwoByteFieldSid() { + IonReaderContinuableCoreBinary reader = initializeReader( + true, + 0xE0, 0x01, 0x00, 0xEA, // IVM + 0xDC, // Struct, length 12 + 0x00, // First byte of overpadded 2-byte field SID + 0x9A // Field SID 26 + // The struct ends unexpectedly + ); + assertEquals(IonCursor.Event.START_CONTAINER, reader.nextValue()); + assertEquals(IonType.STRUCT, reader.getType()); + reader.stepIntoContainer(); + // This is an unexpected EOF, so the reader should fail cleanly. + assertThrows(IonException.class, reader::nextValue); + reader.close(); + } + + @Test + public void expectIncompleteContainerToFailCleanlyAfterAnnotationHeader() { + IonReaderContinuableCoreBinary reader = initializeReader( + true, + 0xE0, 0x01, 0x00, 0xEA, // IVM + 0xDC, // Struct, length 12 + 0x9A, // Field SID 26 + 0xE4, // Annotation wrapper length 4 + 0x00, 0x81, // VarUInt length 1 (overpadded by 1 byte) + 0x00, 0x84 // VarUInt SID 4 (overpadded by 1 byte) + // The value ends unexpectedly + ); + assertEquals(IonCursor.Event.START_CONTAINER, reader.nextValue()); + assertEquals(IonType.STRUCT, reader.getType()); + reader.stepIntoContainer(); + // This is an unexpected EOF, so the reader should fail cleanly. + assertThrows(IonException.class, reader::nextValue); + reader.close(); + } + + @Test + public void expectIncompleteAnnotationHeaderToFailCleanly() { + IonReaderContinuableCoreBinary reader = initializeReader( + true, + 0xE0, 0x01, 0x00, 0xEA, // IVM + 0xE4, // Annotation wrapper length 5 + 0x81, // VarUInt length 1 + 0x84 // VarUInt SID 4 + // The value ends unexpectedly + ); + // This is an unexpected EOF, so the reader should fail cleanly. + assertThrows(IonException.class, reader::nextValue); + reader.close(); + } }