setInput should always push at least 1 byte into the Inflater. If 0 bytes (or negative!) are being sent the DfsBlock is inconsistent with the position passed in. This indicates a severe programming problem in the caller, and may cause an infinite loop in DfsReader. Today we saw a handful of live examples of this but don't know what the cause is. Guard against this error condition and throw with a more verbose failure, which may prevent an infinite loop. Callers will eventually catch DataFormatException and rethrow with more detail about the object that cannot be inflated, with the DFE in the chain. Change-Id: I64ed2a471520e48283675c6210c6db8a60634635tags/v4.5.0.201609210915-r
@@ -88,9 +88,16 @@ final class DfsBlock { | |||
return n; | |||
} | |||
int setInput(long pos, Inflater inf) { | |||
int setInput(long pos, Inflater inf) throws DataFormatException { | |||
int ptr = (int) (pos - start); | |||
int cnt = block.length - ptr; | |||
if (cnt <= 0) { | |||
throw new DataFormatException(cnt + " bytes to inflate:" //$NON-NLS-1$ | |||
+ " at pos=" + pos //$NON-NLS-1$ | |||
+ "; block.start=" + start //$NON-NLS-1$ | |||
+ "; ptr=" + ptr //$NON-NLS-1$ | |||
+ "; block.length=" + block.length); //$NON-NLS-1$ | |||
} | |||
inf.setInput(block, ptr, cnt); | |||
return cnt; | |||
} |
@@ -484,7 +484,8 @@ public class DfsInserter extends ObjectInserter { | |||
} | |||
} | |||
private int setInput(long pos, Inflater inf) throws IOException { | |||
private int setInput(long pos, Inflater inf) | |||
throws IOException, DataFormatException { | |||
if (pos < currPos) | |||
return getOrLoadBlock(pos).setInput(pos, inf); | |||
if (pos < currPos + currPtr) { |