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
The following commit(s) were added to refs/heads/master by this push: new e0f21a499 [COMPRESS-632] LZWInputStream.initializeTables(int) should throw IllegalArgumentException instead of ArrayIndexOutOfBoundsException #435 e0f21a499 is described below commit e0f21a4996738e0275db0d6ba38cf51b07a711a0 Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Fri Nov 10 08:47:28 2023 -0500 [COMPRESS-632] LZWInputStream.initializeTables(int) should throw IllegalArgumentException instead of ArrayIndexOutOfBoundsException #435 Apply a different version of PR #435 from Yakov Shafranovich --- src/changes/changes.xml | 1 + .../compress/compressors/lzw/LZWInputStream.java | 10 ++++--- .../compressors/z/ZCompressorInputStreamTest.java | 34 ++++++++++++++++++++-- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 6448265ed..412805e02 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -86,6 +86,7 @@ The <action> type attribute can be add,update,fix,remove. <action type="fix" dev="ggregory" due-to="Gary Gregory">Use the root Locale for string conversion of command line options in org.apache.commons.compress.archivers.sevenz.CLI.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">Calling PackingUtils.config(PackingOptions) with null now closes the internal FileHandler.</action> <action type="fix" issue="COMPRESS-650" dev="ggregory" due-to="Chad Preisler">LZ4 compressor throws IndexOutOfBoundsException.</action> + <action type="fix" issue="COMPRESS-632" dev="ggregory" due-to="Yakov Shafranovich, Gary Gregory">LZWInputStream.initializeTables(int) should throw IllegalArgumentException instead of ArrayIndexOutOfBoundsException.</action> <!-- UPDATE --> <action type="update" dev="ggregory" due-to="Dependabot">Bump org.slf4j:slf4j-api from 2.0.8 to 2.0.9 #413.</action> <action type="update" dev="ggregory" due-to="Gary Gregory">Bump commons-io:commons-io from 2.13.0 to 2.15.0.</action> diff --git a/src/main/java/org/apache/commons/compress/compressors/lzw/LZWInputStream.java b/src/main/java/org/apache/commons/compress/compressors/lzw/LZWInputStream.java index cad2a2bba..b51e4b47a 100644 --- a/src/main/java/org/apache/commons/compress/compressors/lzw/LZWInputStream.java +++ b/src/main/java/org/apache/commons/compress/compressors/lzw/LZWInputStream.java @@ -164,13 +164,15 @@ public abstract class LZWInputStream extends CompressorInputStream implements In /** * Initializes the arrays based on the maximum code size. + * * @param maxCodeSize maximum code size - * @throws IllegalArgumentException if {@code maxCodeSize} is not bigger than 0 + * @throws IllegalArgumentException if {@code maxCodeSize} is out of bounds for {@code prefixes} and {@code characters}. */ protected void initializeTables(final int maxCodeSize) { - if (maxCodeSize <= 0) { - throw new IllegalArgumentException("maxCodeSize is " + maxCodeSize - + ", must be bigger than 0"); + // maxCodeSize shifted cannot be less than 256, otherwise the loop in initializeTables() will throw an ArrayIndexOutOfBoundsException + // maxCodeSize cannot be smaller than getCodeSize(), otherwise addEntry() will throw an ArrayIndexOutOfBoundsException + if (1 << maxCodeSize < 256 || getCodeSize() > maxCodeSize) { + throw new IllegalArgumentException("maxCodeSize is " + maxCodeSize + ", must be bigger than 0"); } final int maxTableSize = 1 << maxCodeSize; prefixes = new int[maxTableSize]; diff --git a/src/test/java/org/apache/commons/compress/compressors/z/ZCompressorInputStreamTest.java b/src/test/java/org/apache/commons/compress/compressors/z/ZCompressorInputStreamTest.java index 793360f05..450909205 100644 --- a/src/test/java/org/apache/commons/compress/compressors/z/ZCompressorInputStreamTest.java +++ b/src/test/java/org/apache/commons/compress/compressors/z/ZCompressorInputStreamTest.java @@ -18,17 +18,20 @@ */ package org.apache.commons.compress.compressors.z; -import static org.apache.commons.compress.AbstractTest.getFile; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; import java.nio.file.Files; import java.util.Collections; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import org.apache.commons.compress.AbstractTest; import org.apache.commons.compress.utils.IOUtils; import org.junit.jupiter.api.Test; @@ -45,9 +48,34 @@ public class ZCompressorInputStreamTest { assertThrows(IOException.class, () -> new ZCompressorInputStream(sequenceInputStream)); } + @Test + public void testInvalidMaxCodeSize() throws IOException { + final byte[] bytes = Files.readAllBytes(AbstractTest.getPath("bla.tar.Z")); + + // @formatter:off + final IntStream[] invalid = { + IntStream.range(Byte.MIN_VALUE, -120), + IntStream.range(-97, -88), + IntStream.range(-65, -56), + IntStream.range(-33, -24), + IntStream.range(-1, 8), + IntStream.range(31, 40), + IntStream.range(63, 72), + IntStream.range(95, 104), + IntStream.range(127, 127) + }; + // @formatter:on + + Stream.of(invalid).forEach(ints -> ints.forEach(i -> { + bytes[2] = (byte) i; + assertThrows(IllegalArgumentException.class, () -> new ZCompressorInputStream(new ByteArrayInputStream(bytes), 1024 * 1024), + () -> "value=" + i); + })); + } + @Test public void testMultiByteReadConsistentlyReturnsMinusOneAtEof() throws IOException { - final File input = getFile("bla.tar.Z"); + final File input = AbstractTest.getFile("bla.tar.Z"); final byte[] buf = new byte[2]; try (InputStream is = Files.newInputStream(input.toPath()); ZCompressorInputStream in = new ZCompressorInputStream(is)) { @@ -59,7 +87,7 @@ public class ZCompressorInputStreamTest { @Test public void testSingleByteReadConsistentlyReturnsMinusOneAtEof() throws IOException { - final File input = getFile("bla.tar.Z"); + final File input = AbstractTest.getFile("bla.tar.Z"); try (InputStream is = Files.newInputStream(input.toPath()); ZCompressorInputStream in = new ZCompressorInputStream(is)) { IOUtils.toByteArray(in);