Skip to content

Commit

Permalink
ChecksumChannel: fix int overrun bug on filling up gaps > Integer.MAX…
Browse files Browse the repository at this point in the history
…_VALUE

ChecksumChannel used int for summing up the number of total bytes read
back or filled up with zeros. If those gaps were greater than 2^31 the
variable would overflow and cause an NegativePosition Exception in the
reading back case and a infinite loop in the filling zeros case.
This patch fixes this by changing the vars to long instead.

Unit tests are included, but @ignored, because they take a long time.

Ticket:
Acked-by:
Target: trunk
Request: 2.12
Require-book: no
Require-notes: no
  • Loading branch information
Karsten Schwank committed May 5, 2015
1 parent 8a4efa1 commit 351ed7f
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,10 @@ private void feedZerosToDigesterForRangeGaps() throws IOException {

for (Range<Long> range : complement) {
long rangeLength = range.upperEndpoint() - range.lowerEndpoint();
for (int totalDigestedZeros = 0; totalDigestedZeros < rangeLength; totalDigestedZeros += _zerosBuffer.limit()) {
for (long totalDigestedZeros = 0; totalDigestedZeros < rangeLength; totalDigestedZeros += _zerosBuffer.limit()) {
_zerosBuffer.clear();
_zerosBuffer.limit((int) Math.min(rangeLength - totalDigestedZeros, _zerosBuffer.capacity()));
long limit = Math.min(_zerosBuffer.capacity(), rangeLength - totalDigestedZeros);
_zerosBuffer.limit((int)limit);
updateChecksum(_zerosBuffer, range.lowerEndpoint() + totalDigestedZeros, _zerosBuffer.limit());
}
}
Expand Down Expand Up @@ -358,10 +359,10 @@ synchronized void updateChecksum(ByteBuffer buffer, long position, long bytes) t
_digest.update(buffer);
long bytesToRead = digestEnd - digestStart;
long lastBytesRead;
for (int totalBytesRead = 0; totalBytesRead < bytesToRead; totalBytesRead += lastBytesRead) {
for (long totalBytesRead = 0; totalBytesRead < bytesToRead; totalBytesRead += lastBytesRead) {
_readBackBuffer.clear();
int limit = (int) Math.min(_readBackBuffer.capacity(), bytesToRead - totalBytesRead);
_readBackBuffer.limit(limit);
long limit = Math.min(_readBackBuffer.capacity(), bytesToRead - totalBytesRead);
_readBackBuffer.limit((int)limit);
lastBytesRead = _channel.read(_readBackBuffer, digestStart + totalBytesRead);
if (lastBytesRead < 0) {
throw new IOException("Checksum: Unexpectedly hit end-of-stream while reading data back from channel.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

import java.io.File;
Expand All @@ -24,6 +25,7 @@

import static com.google.common.collect.Lists.newArrayList;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.mock;
Expand Down Expand Up @@ -255,6 +257,39 @@ public void shouldThrowIllegalStateExceptionOnWritesAfterGetChecksum() throws IO
chksumChannel.write(buffers[0], 0);
}

@Test
@Ignore
public void shouldBeAbleToHandleFilesGreater4Gb() throws IOException {
ByteBuffer bigbuffer = ByteBuffer.allocate(1024*1024);
for (long i = 0; i < 2L*Integer.MAX_VALUE; i += bigbuffer.capacity()) {
chksumChannel.write(bigbuffer, i);
bigbuffer.rewind();
}
assertThat(chksumChannel.getChecksum(), notNullValue());
}

@Test
@Ignore
public void shouldBeAbleToReadBackRangesOfSizeGreater4Gb() throws IOException {
chksumChannel._readBackBuffer = ByteBuffer.allocate(256*1024);
ByteBuffer bigbuffer = ByteBuffer.allocate(1024*1024);
for (long i = bigbuffer.capacity(); i < 2L*Integer.MAX_VALUE; i += bigbuffer.capacity()) {
chksumChannel.write(bigbuffer, i);
bigbuffer.rewind();
}
chksumChannel.write(bigbuffer, 0);
assertThat(chksumChannel.getChecksum(), notNullValue());
}

@Test
@Ignore
public void shouldBeAbleToFillZeroRangesOfSizeGreater4Gb() throws IOException {
chksumChannel._zerosBuffer = ByteBuffer.allocate(256*1024);
chksumChannel._readBackBuffer = ByteBuffer.allocate(256*1024);
chksumChannel.write(buffers[0], 2L*Integer.MAX_VALUE);
assertThat(chksumChannel.getChecksum(), notNullValue());
}

@Test
public void shouldFillUpRangeGapsWithZerosOnGetChecksum() throws IOException {
Map<Long, ByteBuffer> nonZeroBlocksFromByteArray = getNonZeroBlocksFromByteArray(data);
Expand Down

0 comments on commit 351ed7f

Please sign in to comment.