Mercurial > hg4j
changeset 399:fdc1db8f7f61 smartgit3
Issue 25: Underflow in InflaterDataAccess; test and fix for hang up when reading past end of compressed data (or zero-length data)
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Sat, 25 Feb 2012 19:31:57 +0100 |
parents | 5e95b0da26f2 |
children | deb64baaa412 31a719b9f95e |
files | src/org/tmatesoft/hg/internal/DataAccess.java src/org/tmatesoft/hg/internal/InflaterDataAccess.java test-data/test-repos.jar test/org/tmatesoft/hg/test/TestStatus.java |
diffstat | 4 files changed, 19 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/internal/DataAccess.java Thu Feb 23 15:31:57 2012 +0100 +++ b/src/org/tmatesoft/hg/internal/DataAccess.java Sat Feb 25 19:31:57 2012 +0100 @@ -32,6 +32,7 @@ public boolean isEmpty() { return true; } + // TODO throws IOException (few subclasses have non-trivial length() operation) public int length() { return 0; } @@ -68,6 +69,10 @@ readBytes(b, 0, 4); return b[0] << 24 | (b[1] & 0xFF) << 16 | (b[2] & 0xFF) << 8 | (b[3] & 0xFF); } + + /** + * Read 8 bytes as long value, big-endian. + */ public long readLong() throws IOException { byte[] b = new byte[8]; readBytes(b, 0, 8);
--- a/src/org/tmatesoft/hg/internal/InflaterDataAccess.java Thu Feb 23 15:31:57 2012 +0100 +++ b/src/org/tmatesoft/hg/internal/InflaterDataAccess.java Sat Feb 25 19:31:57 2012 +0100 @@ -158,20 +158,20 @@ int n; while (len > 0) { while ((n = inflater.inflate(b, off, len)) == 0) { - // FIXME few last bytes (checksum?) may be ignored by inflater, thus inflate may return 0 in + // XXX few last bytes (checksum?) may be ignored by inflater, thus inflate may return 0 in // perfectly legal conditions (when all data already expanded, but there are still some bytes - // in the input stream - if (inflater.finished() || inflater.needsDictionary()) { - throw new EOFException(); - } - if (inflater.needsInput()) { + // in the input stream) + int toRead = -1; + if (inflater.needsInput() && (toRead = super.available()) > 0) { // fill: - int toRead = super.available(); if (toRead > buffer.length) { toRead = buffer.length; } super.readBytes(buffer, 0, toRead); inflater.setInput(buffer, 0, toRead); + } else { + // prevent hang up in this cycle if no more data is available, see Issue 25 + throw new EOFException(String.format("No more compressed data is available to satisfy request for %d bytes. [finished:%b, needDict:%b, needInp:%b, available:%d", len, inflater.finished(), inflater.needsDictionary(), inflater.needsInput(), toRead)); } } off += n;
--- a/test/org/tmatesoft/hg/test/TestStatus.java Thu Feb 23 15:31:57 2012 +0100 +++ b/test/org/tmatesoft/hg/test/TestStatus.java Sat Feb 25 19:31:57 2012 +0100 @@ -537,6 +537,10 @@ * b) That FilterDataAccess (with 0 size represents patch more or less relevantly, but didn't represent actual revision) get successfully * reassigned as lastUserData for the next iteration. And at the next step attempt to apply patch recorded in the next revision failed * because baseRevisionData is 0 length FilterDataAccess + * + * Same applies for + * Issue 25: IOException: Underflow. Rewind past end of the slice in InflaterDataAccess + * with the difference in separate .i and .d (thus not 0 but 'x' first byte was read) * * Sample: * status-5/file1 has 3 revisions, second is zero-length patch: @@ -551,10 +555,12 @@ @Test public void testZeroLengthPatchAgainstNonEmptyBaseRev() throws Exception{ repo = Configuration.get().find("status-5"); - // pretend we modified file in the working copy + // pretend we modified files in the working copy // for HgWorkingCopyStatusCollector to go and retrieve its content from repository File f1 = new File(repo.getWorkingDir(), "file1"); f1.setLastModified(System.currentTimeMillis()); + File f3 = new File(repo.getWorkingDir(), "file3"); + f3.setLastModified(System.currentTimeMillis()); // HgStatusCommand cmd = new HgStatusCommand(repo); cmd.all();