TemporaryBuffer: fix toByteArray(limit)
Heap always copied whole blocks, which leads to AIOOBEs. LocalFile didn't overwrite the method and thus caused NPEs. Change-Id: Ia37d4a875df9f25d4825e6bc95fed7f0dff42afb Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
parent
cf9433a9b3
commit
84dbc2d431
|
@ -406,4 +406,69 @@ public void testHeapWithEstimatedSize() throws IOException {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeapToByteArrayWithLimit() throws IOException {
|
||||
int sz = 2 * Block.SZ;
|
||||
try (TemporaryBuffer b = new TemporaryBuffer.Heap(sz / 2, sz)) {
|
||||
for (int i = 0; i < sz; i++) {
|
||||
b.write('a' + i % 26);
|
||||
}
|
||||
byte[] prefix = b.toByteArray(5);
|
||||
assertEquals(5, prefix.length);
|
||||
for (int i = 0; i < prefix.length; i++) {
|
||||
assertEquals('a' + i % 26, prefix[i]);
|
||||
}
|
||||
prefix = b.toByteArray(Block.SZ + 37);
|
||||
assertEquals(Block.SZ + 37, prefix.length);
|
||||
for (int i = 0; i < prefix.length; i++) {
|
||||
assertEquals('a' + i % 26, prefix[i]);
|
||||
}
|
||||
prefix = b.toByteArray(sz);
|
||||
assertEquals(sz, prefix.length);
|
||||
for (int i = 0; i < prefix.length; i++) {
|
||||
assertEquals('a' + i % 26, prefix[i]);
|
||||
}
|
||||
prefix = b.toByteArray(sz + 37);
|
||||
assertEquals(sz, prefix.length);
|
||||
for (int i = 0; i < prefix.length; i++) {
|
||||
assertEquals('a' + i % 26, prefix[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileToByteArrayWithLimit() throws IOException {
|
||||
@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
|
||||
TemporaryBuffer b = new TemporaryBuffer.LocalFile(null, 2 * Block.SZ);
|
||||
int sz = 3 * Block.SZ;
|
||||
try {
|
||||
for (int i = 0; i < sz; i++) {
|
||||
b.write('a' + i % 26);
|
||||
}
|
||||
b.close();
|
||||
byte[] prefix = b.toByteArray(5);
|
||||
assertEquals(5, prefix.length);
|
||||
for (int i = 0; i < prefix.length; i++) {
|
||||
assertEquals('a' + i % 26, prefix[i]);
|
||||
}
|
||||
prefix = b.toByteArray(Block.SZ + 37);
|
||||
assertEquals(Block.SZ + 37, prefix.length);
|
||||
for (int i = 0; i < prefix.length; i++) {
|
||||
assertEquals('a' + i % 26, prefix[i]);
|
||||
}
|
||||
prefix = b.toByteArray(sz);
|
||||
assertEquals(sz, prefix.length);
|
||||
for (int i = 0; i < prefix.length; i++) {
|
||||
assertEquals('a' + i % 26, prefix[i]);
|
||||
}
|
||||
prefix = b.toByteArray(sz + 37);
|
||||
assertEquals(sz, prefix.length);
|
||||
for (int i = 0; i < prefix.length; i++) {
|
||||
assertEquals('a' + i % 26, prefix[i]);
|
||||
}
|
||||
} finally {
|
||||
b.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,11 +230,16 @@ public byte[] toByteArray(int limit) throws IOException {
|
|||
if (Integer.MAX_VALUE < len)
|
||||
throw new OutOfMemoryError(
|
||||
JGitText.get().lengthExceedsMaximumArraySize);
|
||||
final byte[] out = new byte[(int) len];
|
||||
int length = (int) len;
|
||||
final byte[] out = new byte[length];
|
||||
int outPtr = 0;
|
||||
for (Block b : blocks) {
|
||||
System.arraycopy(b.buffer, 0, out, outPtr, b.count);
|
||||
outPtr += b.count;
|
||||
int toCopy = Math.min(length - outPtr, b.count);
|
||||
System.arraycopy(b.buffer, 0, out, outPtr, toCopy);
|
||||
outPtr += toCopy;
|
||||
if (outPtr == length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
@ -460,6 +465,30 @@ public byte[] toByteArray() throws IOException {
|
|||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray(int limit) throws IOException {
|
||||
if (onDiskFile == null) {
|
||||
return super.toByteArray(limit);
|
||||
}
|
||||
final long len = Math.min(length(), limit);
|
||||
if (Integer.MAX_VALUE < len) {
|
||||
throw new OutOfMemoryError(
|
||||
JGitText.get().lengthExceedsMaximumArraySize);
|
||||
}
|
||||
final byte[] out = new byte[(int) len];
|
||||
try (FileInputStream in = new FileInputStream(onDiskFile)) {
|
||||
int read = 0;
|
||||
int chunk;
|
||||
while ((chunk = in.read(out, read, out.length - read)) >= 0) {
|
||||
read += chunk;
|
||||
if (read == out.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(OutputStream os, ProgressMonitor pm)
|
||||
throws IOException {
|
||||
|
|
Loading…
Reference in New Issue