This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-compress.git
commit 1a694c20e9b378d2801f5a156aa86021e5f0c354 Author: Gary D. Gregory <[email protected]> AuthorDate: Sun Aug 3 17:04:10 2025 -0400 Add org.apache.commons.compress.archivers.ArchiveException.addExact(int, int) Use org.apache.commons.compress.archivers.ArchiveException.addExact(long, long) --- src/changes/changes.xml | 1 + .../compress/archivers/ArchiveException.java | 19 ++++++++++++ .../compress/archivers/sevenz/SevenZFile.java | 34 +++++++++++----------- .../archivers/ar/ArArchiveInputStreamTest.java | 16 ++++++++++ 4 files changed, 53 insertions(+), 17 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index f28c848d2..ba2464418 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -74,6 +74,7 @@ The <action> type attribute can be add,update,fix,remove. <action type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.compress.MemoryLimitException.checkBytes(int, long).</action> <action type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.compress.MemoryLimitException.checkKiB(long, long).</action> <action type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.compress.archivers.ArchiveException.addExact(long, long).</action> + <action type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.compress.archivers.ArchiveException.addExact(int, int).</action> <!-- UPDATE --> </release> <release version="1.28.0" date="2025-07-26" description="This is a feature and maintenance release. Java 8 or later is required."> diff --git a/src/main/java/org/apache/commons/compress/archivers/ArchiveException.java b/src/main/java/org/apache/commons/compress/archivers/ArchiveException.java index 0da2edcc2..fad5fac36 100644 --- a/src/main/java/org/apache/commons/compress/archivers/ArchiveException.java +++ b/src/main/java/org/apache/commons/compress/archivers/ArchiveException.java @@ -30,6 +30,24 @@ public class ArchiveException extends CompressException { /** Serial. */ private static final long serialVersionUID = 2772690708123267100L; + /** + * Delegates to {@link Math#addExact(int, int)} wrapping its {@link ArithmeticException} in our {@link ArchiveException}. + * + * @param x the first value. + * @param y the second value. + * @return the result. + * @throws ArchiveException if the result overflows a long. + * @see Math#addExact(int, int) + * @since 1.29.0 + */ + public static int addExact(final int x, final int y) throws ArchiveException { + try { + return Math.addExact(x, y); + } catch (final ArithmeticException e) { + throw new ArchiveException(e); + } + } + /** * Delegates to {@link Math#addExact(long, long)} wrapping its {@link ArithmeticException} in our {@link ArchiveException}. * @@ -37,6 +55,7 @@ public class ArchiveException extends CompressException { * @param y the second value. * @return the result. * @throws ArchiveException if the result overflows a long. + * @see Math#addExact(long, long) * @since 1.29.0 */ public static long addExact(final long x, final long y) throws ArchiveException { diff --git a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java index bd953fcf3..6c809ed93 100644 --- a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java +++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java @@ -779,8 +779,8 @@ private InputStream buildDecoderStack(final Folder folder, final long folderOffs channel.position(folderOffset); InputStream inputStreamStack = new FilterInputStream( new BufferedInputStream(new BoundedSeekableByteChannelInputStream(channel, archive.packSizes[firstPackStreamIndex]))) { - private void count(final int c) { - compressedBytesReadFromCurrentEntry = Math.addExact(compressedBytesReadFromCurrentEntry, c); + private void count(final int c) throws ArchiveException { + compressedBytesReadFromCurrentEntry = ArchiveException.addExact(compressedBytesReadFromCurrentEntry, c); } @Override @@ -916,14 +916,14 @@ private void calculateStreamMap(final Archive archive) throws IOException { final int[] folderFirstPackStreamIndex = new int[numFolders]; for (int i = 0; i < numFolders; i++) { folderFirstPackStreamIndex[i] = nextFolderPackStreamIndex; - nextFolderPackStreamIndex = Math.addExact(nextFolderPackStreamIndex, archive.folders[i].packedStreams.length); + nextFolderPackStreamIndex = ArchiveException.addExact(nextFolderPackStreamIndex, archive.folders[i].packedStreams.length); } long nextPackStreamOffset = 0; final int numPackSizes = archive.packSizes.length; final long[] packStreamOffsets = new long[numPackSizes]; for (int i = 0; i < numPackSizes; i++) { packStreamOffsets[i] = nextPackStreamOffset; - nextPackStreamOffset = Math.addExact(nextPackStreamOffset, archive.packSizes[i]); + nextPackStreamOffset = ArchiveException.addExact(nextPackStreamOffset, archive.packSizes[i]); } final int[] folderFirstFileIndex = new int[numFolders]; final int[] fileFolderIndex = new int[archive.files.length]; @@ -1206,7 +1206,7 @@ public int read(final byte[] b, final int off, final int len) throws IOException @SuppressWarnings("resource") // does not allocate final int current = getCurrentStream().read(b, off, len); if (current > 0) { - uncompressedBytesReadFromCurrentEntry = Math.addExact(uncompressedBytesReadFromCurrentEntry, current); + uncompressedBytesReadFromCurrentEntry = ArchiveException.addExact(uncompressedBytesReadFromCurrentEntry, current); } return current; } @@ -1464,8 +1464,8 @@ private Folder readFolder(final ByteBuffer header) throws IOException { numInStreams = readUint64(header); numOutStreams = readUint64(header); } - totalInStreams = Math.addExact(totalInStreams, numInStreams); - totalOutStreams = Math.addExact(totalOutStreams, numOutStreams); + totalInStreams = ArchiveException.addExact(totalInStreams, numInStreams); + totalOutStreams = ArchiveException.addExact(totalOutStreams, numOutStreams); byte[] properties = null; if (hasAttributes) { final long propertiesSize = readUint64(header); @@ -1660,7 +1660,7 @@ private void readSubStreamsInfo(final ByteBuffer header, final Archive archive) for (final Folder folder : archive.folders) { final long numStreams = readUint64(header); folder.numUnpackSubStreams = (int) numStreams; - unpackStreamsCount = Math.addExact(unpackStreamsCount, numStreams); + unpackStreamsCount = ArchiveException.addExact(unpackStreamsCount, numStreams); } nid = getUnsignedByte(header); } @@ -1675,7 +1675,7 @@ private void readSubStreamsInfo(final ByteBuffer header, final Archive archive) for (int i = 0; i < folder.numUnpackSubStreams - 1; i++) { final long size = readUint64(header); subStreamsInfo.unpackSizes[nextUnpackStream++] = size; - sum = Math.addExact(sum, size); + sum = ArchiveException.addExact(sum, size); } } if (sum > folder.getUnpackSize()) { @@ -1689,7 +1689,7 @@ private void readSubStreamsInfo(final ByteBuffer header, final Archive archive) int numDigests = 0; for (final Folder folder : archive.folders) { if (folder.numUnpackSubStreams != 1 || !folder.hasCrc) { - numDigests = Math.addExact(numDigests, folder.numUnpackSubStreams); + numDigests = ArchiveException.addExact(numDigests, folder.numUnpackSubStreams); } } if (nid == NID.kCRC) { @@ -1929,7 +1929,7 @@ private int sanityCheckFolder(final ByteBuffer header, final ArchiveStatistics s if (numCoders == 0) { throw new ArchiveException("Folder without coders"); } - stats.numberOfCoders = Math.addExact(stats.numberOfCoders, numCoders); + stats.numberOfCoders = ArchiveException.addExact(stats.numberOfCoders, numCoders); long totalOutStreams = 0; long totalInStreams = 0; for (int i = 0; i < numCoders; i++) { @@ -1946,8 +1946,8 @@ private int sanityCheckFolder(final ByteBuffer header, final ArchiveStatistics s totalInStreams++; totalOutStreams++; } else { - totalInStreams = Math.addExact(totalInStreams, assertFitsIntoNonNegativeInt("numInStreams", readUint64(header))); - totalOutStreams = Math.addExact(totalOutStreams, assertFitsIntoNonNegativeInt("numOutStreams", readUint64(header))); + totalInStreams = ArchiveException.addExact(totalInStreams, assertFitsIntoNonNegativeInt("numInStreams", readUint64(header))); + totalOutStreams = ArchiveException.addExact(totalOutStreams, assertFitsIntoNonNegativeInt("numOutStreams", readUint64(header))); } if (hasAttributes) { final int propertiesSize = assertFitsIntoNonNegativeInt("propertiesSize", readUint64(header)); @@ -1958,8 +1958,8 @@ private int sanityCheckFolder(final ByteBuffer header, final ArchiveStatistics s } assertFitsIntoNonNegativeInt("totalInStreams", totalInStreams); assertFitsIntoNonNegativeInt("totalOutStreams", totalOutStreams); - stats.numberOfOutStreams = Math.addExact(stats.numberOfOutStreams, totalOutStreams); - stats.numberOfInStreams = Math.addExact(stats.numberOfInStreams, totalInStreams); + stats.numberOfOutStreams = ArchiveException.addExact(stats.numberOfOutStreams, totalOutStreams); + stats.numberOfInStreams = ArchiveException.addExact(stats.numberOfInStreams, totalInStreams); if (totalOutStreams == 0) { throw new ArchiveException("Total output streams can't be 0"); } @@ -2007,7 +2007,7 @@ private void sanityCheckPackInfo(final ByteBuffer header, final ArchiveStatistic long totalPackSizes = 0; for (int i = 0; i < stats.numberOfPackedStreams; i++) { final long packSize = readUint64(header); - totalPackSizes = Math.addExact(totalPackSizes, packSize); + totalPackSizes = ArchiveException.addExact(totalPackSizes, packSize); final long endOfPackStreams = SIGNATURE_HEADER_SIZE + packPos + totalPackSizes; if (packSize < 0 || endOfPackStreams > channel.size() || endOfPackStreams < packPos) { throw new ArchiveException("packSize (%,d) is out of range", packSize); @@ -2080,7 +2080,7 @@ private void sanityCheckSubStreamsInfo(final ByteBuffer header, final ArchiveSta int folderIdx = 0; for (final int numUnpackSubStreams : numUnpackSubStreamsPerFolder) { if (numUnpackSubStreams != 1 || stats.folderHasCrc == null || !stats.folderHasCrc.get(folderIdx++)) { - numDigests = Math.addExact(numDigests, numUnpackSubStreams); + numDigests = ArchiveException.addExact(numDigests, numUnpackSubStreams); } } } diff --git a/src/test/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStreamTest.java b/src/test/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStreamTest.java index 8325f756c..d6190f5d4 100644 --- a/src/test/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStreamTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStreamTest.java @@ -27,11 +27,15 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; import org.apache.commons.compress.AbstractTest; import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.ArchiveException; import org.apache.commons.compress.utils.ArchiveUtils; import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -99,6 +103,18 @@ private void testCompress661(final boolean checkMarkReadReset) throws IOExceptio } } + /** + * Depending on your setup, this test may need a small stack size {@code -Xss1m}. + */ + @Test + @Disabled + void testGetNextArEntry() throws IOException { + try (ArArchiveInputStream inputStream = new ArArchiveInputStream( + Files.newInputStream(Paths.get("src/test/resources/org/apache/commons/compress/ar/getNextArEntry.bin")))) { + assertThrows(ArchiveException.class, inputStream::getNextEntry); + } + } + @Test void testInvalidBadTableLength() throws Exception { try (InputStream in = newInputStream("org/apache/commons/compress/ar/number_parsing/bad_table_length_gnu-fail.ar");
