diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/PackFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/PackFileTest.java index f31bf558c..9a4bc0b1a 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/PackFileTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/PackFileTest.java @@ -47,9 +47,11 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.MessageDigest; +import java.text.MessageFormat; import java.util.Arrays; import java.util.zip.Deflater; +import org.eclipse.jgit.JGitText; import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; import org.eclipse.jgit.junit.TestRepository; @@ -133,7 +135,9 @@ public void testWhole_LargeObject() throws Exception { ol.getCachedBytes(); fail("Should have thrown LargeObjectException"); } catch (LargeObjectException tooBig) { - assertEquals(id.name(), tooBig.getMessage()); + assertEquals(MessageFormat.format( + JGitText.get().largeObjectException, id.name()), tooBig + .getMessage()); } ObjectStream in = ol.openStream(); @@ -257,7 +261,9 @@ public void testDelta_LargeObjectChain() throws Exception { ol.getCachedBytes(); fail("Should have thrown LargeObjectException"); } catch (LargeObjectException tooBig) { - assertEquals(id3.name(), tooBig.getMessage()); + assertEquals(MessageFormat.format( + JGitText.get().largeObjectException, id3.name()), tooBig + .getMessage()); } ObjectStream in = ol.openStream(); @@ -313,7 +319,9 @@ public void testDelta_LargeInstructionStream() throws Exception { ol.getCachedBytes(); fail("Should have thrown LargeObjectException"); } catch (LargeObjectException tooBig) { - assertEquals(id3.name(), tooBig.getMessage()); + assertEquals(MessageFormat.format( + JGitText.get().largeObjectException, id3.name()), tooBig + .getMessage()); } ObjectStream in = ol.openStream(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/UnpackedObjectTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/UnpackedObjectTest.java index 25dfe4c23..ab7445b17 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/UnpackedObjectTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/UnpackedObjectTest.java @@ -135,7 +135,9 @@ public void testStandardFormat_LargeObject() throws Exception { ol.getCachedBytes(); fail("Should have thrown LargeObjectException"); } catch (LargeObjectException tooBig) { - assertEquals(id.name(), tooBig.getMessage()); + assertEquals(MessageFormat.format( + JGitText.get().largeObjectException, id.name()), tooBig + .getMessage()); } ObjectStream in = ol.openStream(); @@ -416,7 +418,9 @@ public void testPackFormat_LargeObject() throws Exception { ol.getCachedBytes(); fail("Should have thrown LargeObjectException"); } catch (LargeObjectException tooBig) { - assertEquals(id.name(), tooBig.getMessage()); + assertEquals(MessageFormat.format( + JGitText.get().largeObjectException, id.name()), tooBig + .getMessage()); } ObjectStream in = ol.openStream(); diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties index 0c3d0e5d8..14c0ba0fc 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties @@ -216,6 +216,10 @@ invalidWildcards=Invalid wildcards {0} invalidWindowSize=Invalid window size isAStaticFlagAndHasNorevWalkInstance={0} is a static flag and has no RevWalk instance kNotInRange=k {0} not in {1} - {2} +largeObjectException={0} exceeds size limit +largeObjectOutOfMemory=Out of memory loading {0} +largeObjectExceedsByteArray=Object {0} exceeds 2 GiB byte array limit +largeObjectExceedsLimit=Object {0} exceeds {1} limit, actual size is {2} lengthExceedsMaximumArraySize=Length exceeds maximum array size listingAlternates=Listing alternates localObjectsIncomplete=Local objects incomplete. @@ -374,6 +378,7 @@ unexpectedReportLine=unexpected report line: {0} unknownDIRCVersion=Unknown DIRC version {0} unknownHost=unknown host unknownIndexVersionOrCorruptIndex=Unknown index version (or corrupt index): {0} +unknownObject=unknown object unknownObjectType=Unknown object type {0}. unknownRepositoryFormat2=Unknown repository format "{0}"; expected "0". unknownRepositoryFormat=Unknown repository format diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java index fc12e5713..ea40fe884 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java @@ -276,6 +276,10 @@ public static JGitText get() { /***/ public String invalidWindowSize; /***/ public String isAStaticFlagAndHasNorevWalkInstance; /***/ public String kNotInRange; + /***/ public String largeObjectException; + /***/ public String largeObjectOutOfMemory; + /***/ public String largeObjectExceedsByteArray; + /***/ public String largeObjectExceedsLimit; /***/ public String lengthExceedsMaximumArraySize; /***/ public String listingAlternates; /***/ public String localObjectsIncomplete; @@ -433,6 +437,7 @@ public static JGitText get() { /***/ public String unknownDIRCVersion; /***/ public String unknownHost; /***/ public String unknownIndexVersionOrCorruptIndex; + /***/ public String unknownObject; /***/ public String unknownObjectType; /***/ public String unknownRepositoryFormat2; /***/ public String unknownRepositoryFormat; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/LargeObjectException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/LargeObjectException.java index f77aecbb4..a1107dc35 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/LargeObjectException.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/LargeObjectException.java @@ -43,6 +43,9 @@ package org.eclipse.jgit.errors; +import java.text.MessageFormat; + +import org.eclipse.jgit.JGitText; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.ObjectId; @@ -73,6 +76,13 @@ public ObjectId getObjectId() { return objectId; } + /** @return either the hex encoded name of the object, or 'unknown object'. */ + protected String getObjectName() { + if (getObjectId() != null) + return getObjectId().name(); + return JGitText.get().unknownObject; + } + /** * Set the identity of the object, if its not already set. * @@ -86,6 +96,68 @@ public void setObjectId(AnyObjectId id) { @Override public String getMessage() { - return objectId != null ? objectId.name() : getClass().getSimpleName(); + return MessageFormat.format(JGitText.get().largeObjectException, + getObjectName()); + } + + /** An error caused by the JVM being out of heap space. */ + public static class OutOfMemory extends LargeObjectException { + private static final long serialVersionUID = 1L; + + /** + * Construct a wrapper around the original OutOfMemoryError. + * + * @param cause + * the original root cause. + */ + public OutOfMemory(OutOfMemoryError cause) { + initCause(cause); + } + + @Override + public String getMessage() { + return MessageFormat.format(JGitText.get().largeObjectOutOfMemory, + getObjectName()); + } + } + + /** Object size exceeds JVM limit of 2 GiB per byte array. */ + public static class ExceedsByteArrayLimit extends LargeObjectException { + private static final long serialVersionUID = 1L; + + @Override + public String getMessage() { + return MessageFormat + .format(JGitText.get().largeObjectExceedsByteArray, + getObjectName()); + } + } + + /** Object size exceeds the caller's upper limit. */ + public static class ExceedsLimit extends LargeObjectException { + private static final long serialVersionUID = 1L; + + private final long limit; + + private final long size; + + /** + * Construct an exception for a particular size being exceeded. + * + * @param limit + * the limit the caller imposed on the object. + * @param size + * the actual size of the object. + */ + public ExceedsLimit(long limit, long size) { + this.limit = limit; + this.size = size; + } + + @Override + public String getMessage() { + return MessageFormat.format(JGitText.get().largeObjectExceedsLimit, + getObjectName(), limit, size); + } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java index b7e58ea15..0fc3bce65 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java @@ -139,7 +139,7 @@ public final byte[] getBytes(int sizeLimit) throws LargeObjectException, try { return cloneArray(cached); } catch (OutOfMemoryError tooBig) { - throw new LargeObjectException(); + throw new LargeObjectException.OutOfMemory(tooBig); } } @@ -195,14 +195,17 @@ public byte[] getCachedBytes(int sizeLimit) throws LargeObjectException, ObjectStream in = openStream(); try { long sz = in.getSize(); - if (sizeLimit < sz || Integer.MAX_VALUE < sz) - throw new LargeObjectException(); + if (sizeLimit < sz) + throw new LargeObjectException.ExceedsLimit(sizeLimit, sz); + + if (Integer.MAX_VALUE < sz) + throw new LargeObjectException.ExceedsByteArrayLimit(); byte[] buf; try { buf = new byte[(int) sz]; } catch (OutOfMemoryError notEnoughHeap) { - throw new LargeObjectException(); + throw new LargeObjectException.OutOfMemory(notEnoughHeap); } IO.readFully(in, buf, 0, buf.length); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LargePackedDeltaObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LargePackedDeltaObject.java index 02e218216..2b98f107f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LargePackedDeltaObject.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LargePackedDeltaObject.java @@ -157,7 +157,9 @@ public byte[] getCachedBytes() throws LargeObjectException { try { throw new LargeObjectException(getObjectId()); } catch (IOException cannotObtainId) { - throw new LargeObjectException(); + LargeObjectException err = new LargeObjectException(); + err.initCause(cannotObtainId); + throw err; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LargePackedWholeObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LargePackedWholeObject.java index 9f5b804ce..9550be4e1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LargePackedWholeObject.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LargePackedWholeObject.java @@ -97,7 +97,9 @@ public byte[] getCachedBytes() throws LargeObjectException { try { throw new LargeObjectException(getObjectId()); } catch (IOException cannotObtainId) { - throw new LargeObjectException(); + LargeObjectException err = new LargeObjectException(); + err.initCause(cannotObtainId); + throw err; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/UnpackedObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/UnpackedObject.java index 78e7b10a7..4065019dc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/UnpackedObject.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/UnpackedObject.java @@ -125,8 +125,12 @@ static ObjectLoader open(InputStream in, File path, AnyObjectId id, if (hdr[p.value++] != 0) throw new CorruptObjectException(id, JGitText.get().corruptObjectGarbageAfterSize); - if (path == null && Integer.MAX_VALUE < size) - throw new LargeObjectException(id.copy()); + if (path == null && Integer.MAX_VALUE < size) { + LargeObjectException.ExceedsByteArrayLimit e; + e = new LargeObjectException.ExceedsByteArrayLimit(); + e.setObjectId(id); + throw e; + } if (size < wc.getStreamFileThreshold() || path == null) { byte[] data = new byte[(int) size]; int n = avail - p.value; @@ -163,8 +167,12 @@ static ObjectLoader open(InputStream in, File path, AnyObjectId id, JGitText.get().corruptObjectInvalidType); } - if (path == null && Integer.MAX_VALUE < size) - throw new LargeObjectException(id.copy()); + if (path == null && Integer.MAX_VALUE < size) { + LargeObjectException.ExceedsByteArrayLimit e; + e = new LargeObjectException.ExceedsByteArrayLimit(); + e.setObjectId(id); + throw e; + } if (size < wc.getStreamFileThreshold() || path == null) { in.reset(); IO.skipFully(in, p); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/DeltaWindow.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/DeltaWindow.java index d5296a03e..6a71ad7dc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/DeltaWindow.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/DeltaWindow.java @@ -424,8 +424,9 @@ private DeltaIndex index(DeltaWindowEntry ent) try { idx = new DeltaIndex(buffer(ent)); } catch (OutOfMemoryError noMemory) { - LargeObjectException e = new LargeObjectException(ent.object); - e.initCause(noMemory); + LargeObjectException.OutOfMemory e; + e = new LargeObjectException.OutOfMemory(noMemory); + e.setObjectId(ent.object); throw e; } if (0 < maxMemory)