Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions src/main/java/com/amazon/ion/impl/IonCursorBinary.java
Original file line number Diff line number Diff line change
Expand Up @@ -898,17 +898,16 @@ private long calculateEndIndex_1_0(IonTypeID valueTid, boolean isAnnotated) {
}
byte b = buffer[(int) peekIndex++];
if (b < 0) {
endIndex = (b & LOWER_SEVEN_BITS_BITMASK);
endIndex = (b & LOWER_SEVEN_BITS_BITMASK) + peekIndex;
} else {
endIndex = uncheckedReadVarUInt_1_0(b);
endIndex = uncheckedReadVarUInt_1_0(b) + peekIndex;
if (endIndex < 0) {
throw new IonException("Unsupported value: declared length is too long.");
}
}
} else {
endIndex = valueTid.length;
endIndex = valueTid.length + peekIndex;
}
endIndex += peekIndex;
if (valueTid.type != null && valueTid.type.ordinal() >= LIST_TYPE_ORDINAL) {
event = Event.START_CONTAINER;
} else if (valueTid.isNopPad) {
Expand Down Expand Up @@ -1308,13 +1307,19 @@ private boolean slowReadValueHeader(IonTypeID valueTid, boolean isAnnotated, Mar
setCheckpoint(CheckpointLocation.AFTER_SCALAR_HEADER);
event = Event.START_SCALAR;
}
if (refillableState.isSkippingCurrentValue) {
// Any bytes that were skipped directly from the input must still be included in the logical endIndex so
// that the rest of the oversized value's bytes may be skipped.
endIndex = endIndex == DELIMITED_MARKER ? DELIMITED_MARKER : (peekIndex + valueLength + refillableState.individualBytesSkippedWithoutBuffering);
} else {
endIndex = endIndex == DELIMITED_MARKER ? DELIMITED_MARKER : (peekIndex + valueLength);
if (endIndex != DELIMITED_MARKER) {
if (refillableState.isSkippingCurrentValue) {
// Any bytes that were skipped directly from the input must still be included in the logical endIndex so
// that the rest of the oversized value's bytes may be skipped.
endIndex = peekIndex + valueLength + refillableState.individualBytesSkippedWithoutBuffering;
} else {
endIndex = peekIndex + valueLength;
}
if (endIndex < 0) {
throw new IonException("Unsupported value: declared length is too long.");
}
}

if (isAnnotated) {
validateAnnotationWrapperEndIndex(endIndex);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -480,4 +480,20 @@ public void expectAttemptToParseNullDecimalAsJavaPrimitiveToFailCleanly() {
assertReaderThrowsForAllPrimitives(reader);
reader.close();
}

@ParameterizedTest(name = "constructFromBytes={0}")
@ValueSource(booleans = {true, false})
public void expectLobWithOverflowingEndIndexToFailCleanly(boolean constructFromBytes) {
// This test exercises the case where a value's length itself does not overflow a java long, but its end index
// (calculated by adding the reader's current index in the buffer to the value's length) does.
IonReaderContinuableCoreBinary reader = initializeReader(
constructFromBytes,
0xE0, 0x01, 0x00, 0xEA, // IVM
0xAE, // blob with length VarUInt to follow
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFE, // 9-byte VarUInt with value just below Long.MAX_VALUE
0xAF // The first byte of the blob
);
assertThrows(IonException.class, reader::nextValue);
reader.close();
}
}