Skip to content

Commit

Permalink
Fix to ensure that SeekableStream#available() never returns a negativ…
Browse files Browse the repository at this point in the history
…e value. (#1255)

* For files that are larger than 2GB (e.g. an uncompressed FASTA) it was previously possible that
`length - position` overflows an int, resulting in a negative value being returned.
  • Loading branch information
tomwhite authored and lbergelson committed Jan 9, 2019
1 parent 5a0ab68 commit 68d9fdb
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,13 @@ public int available() throws IOException {
return 0;
}
final long remaining = length() - position();
// the remaining might be negative if the length is not available (0)
return (remaining < 0) ? 0 : (int) remaining;
if (remaining < 0) { // remaining might be negative if the length is not available (0)
return 0;
} else if (remaining > Integer.MAX_VALUE) { // remaining might be bigger than Integer.MAX_VALUE for very large files
return Integer.MAX_VALUE;
} else {
return (int) remaining;
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.IOException;
import java.util.Random;

/**
Expand Down Expand Up @@ -81,6 +82,15 @@ public void testAvailable() throws Exception {
Assert.assertEquals(stream.available(), 0);
}

@Test
public void testAvailableDoesNotOverflowInteger() throws Exception {
// initiate large stream (longer than Integer.MAX_VALUE)
final long length = Integer.MAX_VALUE * 2L;
final SeekableStream stream = getLargeSeekableStream(length);
// check that available returns Integer.MAX_VALUE (and not a negative number due to overflow)
Assert.assertEquals(stream.available(), Integer.MAX_VALUE);
}

private static SeekableStream getRandomSeekableStream(final int size) {
// generate random array
final byte[] array = new byte[size];
Expand All @@ -89,4 +99,50 @@ private static SeekableStream getRandomSeekableStream(final int size) {
return new SeekableMemoryStream(array, "test");
}

private static SeekableStream getLargeSeekableStream(final long size) {
// a long file of zeros
return new SeekableStream() {
long pos = 0;
@Override
public long length() {
return size;
}

@Override
public long position() throws IOException {
return pos;
}

@Override
public void seek(long position) throws IOException {
pos = position;
}

@Override
public int read(byte[] buffer, int offset, int length) throws IOException {
return length;
}

@Override
public void close() throws IOException {

}

@Override
public boolean eof() throws IOException {
return pos == length();
}

@Override
public String getSource() {
return null;
}

@Override
public int read() throws IOException {
return 0;
}
};
}

}

0 comments on commit 68d9fdb

Please sign in to comment.