LUCENE-8625: int overflow in ByteBuffersDataInput.sliceBufferList

This commit is contained in:
Dawid Weiss 2018-12-28 10:54:16 +01:00
parent 45c50a0273
commit c9c3ef0ef9
3 changed files with 57 additions and 5 deletions

View File

@ -243,6 +243,9 @@ Bug fixes:
* LUCENE-8624: int overflow in ByteBuffersDataOutput.size(). (Mulugeta Mammo,
Dawid Weiss)
* LUCENE-8625: int overflow in ByteBuffersDataInput.sliceBufferList. (Mulugeta Mammo,
Dawid Weiss)
New Features
* LUCENE-8026: ExitableDirectoryReader may now time out queries that run on

View File

@ -290,17 +290,17 @@ public final class ByteBuffersDataInput extends DataInput implements Accountable
if (buffers.size() == 1) {
ByteBuffer cloned = buffers.get(0).asReadOnlyBuffer();
cloned.position(Math.toIntExact(cloned.position() + offset));
cloned.limit(Math.toIntExact(length + cloned.position()));
cloned.limit(Math.toIntExact(cloned.position() + length));
return Arrays.asList(cloned);
} else {
long absStart = buffers.get(0).position() + offset;
long absEnd = Math.toIntExact(absStart + length);
long absEnd = absStart + length;
int blockBytes = ByteBuffersDataInput.determineBlockPage(buffers);
int blockBits = Integer.numberOfTrailingZeros(blockBytes);
int blockMask = (1 << blockBits) - 1;
long blockMask = (1L << blockBits) - 1;
int endOffset = (int) absEnd & blockMask;
int endOffset = Math.toIntExact(absEnd & blockMask);
ArrayList<ByteBuffer> cloned =
buffers.subList(Math.toIntExact(absStart / blockBytes),
@ -313,7 +313,7 @@ public final class ByteBuffersDataInput extends DataInput implements Accountable
cloned.add(ByteBuffer.allocate(0));
}
cloned.get(0).position((int) absStart & blockMask);
cloned.get(0).position(Math.toIntExact(absStart & blockMask));
cloned.get(cloned.size() - 1).limit(endOffset);
return cloned;
}

View File

@ -21,6 +21,7 @@ import static org.junit.Assert.*;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.util.ArrayUtil;
@ -203,4 +204,52 @@ public final class TestByteBuffersDataInput extends RandomizedTest {
in.readBytes(ByteBuffer.allocate(100), 100);
});
}
// https://issues.apache.org/jira/browse/LUCENE-8625
@Test
public void testSlicingLargeBuffers() throws IOException {
// Simulate a "large" (> 4GB) input by duplicating
// buffers with the same content.
int MB = 1024 * 1024;
byte [] pageBytes = randomBytesOfLength(4 * MB);
ByteBuffer page = ByteBuffer.wrap(pageBytes);
// Add some head shift on the first buffer.
final int shift = randomIntBetween(0, pageBytes.length / 2);
final long simulatedLength =
randomLongBetween(0, 2018) + 4L * Integer.MAX_VALUE;
List<ByteBuffer> buffers = new ArrayList<>();
long remaining = simulatedLength + shift;
while (remaining > 0) {
ByteBuffer bb = page.duplicate();
if (bb.remaining() > remaining) {
bb.limit(Math.toIntExact(bb.position() + remaining));
}
buffers.add(bb);
remaining -= bb.remaining();
}
buffers.get(0).position(shift);
ByteBuffersDataInput dst = new ByteBuffersDataInput(buffers);
assertEquals(simulatedLength, dst.size());
final long max = dst.size();
long offset = 0;
for (; offset < max; offset += randomIntBetween(MB, 4 * MB)) {
assertEquals(0, dst.slice(offset, 0).size());
assertEquals(1, dst.slice(offset, 1).size());
long window = Math.min(max - offset, 1024);
ByteBuffersDataInput slice = dst.slice(offset, window);
assertEquals(window, slice.size());
// Sanity check of the content against original pages.
for (int i = 0; i < window; i++) {
byte expected = pageBytes[(int) ((shift + offset + i) % pageBytes.length)];
assertEquals(expected, slice.readByte(i));
}
}
}
}