Skip to content

Commit d9e7b7e

Browse files
committedMay 31, 2024
8210471: GZIPInputStream constructor could leak an un-end()ed Inflater
Reviewed-by: lancea
1 parent 1e04ee6 commit d9e7b7e

File tree

2 files changed

+118
-2
lines changed

2 files changed

+118
-2
lines changed
 

‎src/java.base/share/classes/java/util/zip/GZIPInputStream.java

+23-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.io.InputStream;
3232
import java.io.IOException;
3333
import java.io.EOFException;
34+
import java.util.Objects;
3435

3536
/**
3637
* This class implements a stream filter for reading compressed data in
@@ -75,9 +76,29 @@ private void ensureOpen() throws IOException {
7576
* @throws IllegalArgumentException if {@code size <= 0}
7677
*/
7778
public GZIPInputStream(InputStream in, int size) throws IOException {
78-
super(in, in != null ? new Inflater(true) : null, size);
79+
super(in, createInflater(in, size), size);
7980
usesDefaultInflater = true;
80-
readHeader(in);
81+
try {
82+
readHeader(in);
83+
} catch (IOException ioe) {
84+
this.inf.end();
85+
throw ioe;
86+
}
87+
}
88+
89+
/*
90+
* Creates and returns an Inflater only if the input stream is not null and the
91+
* buffer size is > 0.
92+
* If the input stream is null, then this method throws a
93+
* NullPointerException. If the size is <= 0, then this method throws
94+
* an IllegalArgumentException
95+
*/
96+
private static Inflater createInflater(InputStream in, int size) {
97+
Objects.requireNonNull(in);
98+
if (size <= 0) {
99+
throw new IllegalArgumentException("buffer size <= 0");
100+
}
101+
return new Inflater(true);
81102
}
82103

83104
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.io.ByteArrayInputStream;
25+
import java.io.IOException;
26+
import java.util.stream.Stream;
27+
import java.util.zip.GZIPInputStream;
28+
29+
import org.junit.jupiter.api.Assertions;
30+
import org.junit.jupiter.api.function.Executable;
31+
import org.junit.jupiter.params.ParameterizedTest;
32+
import org.junit.jupiter.params.provider.Arguments;
33+
import org.junit.jupiter.params.provider.MethodSource;
34+
35+
/*
36+
* @test
37+
* @summary basic API verification tests for GZIPInputStream
38+
* @run junit BasicGZIPInputStreamTest
39+
*/
40+
public class BasicGZIPInputStreamTest {
41+
42+
43+
private static Stream<Arguments> npeFromConstructors() {
44+
return Stream.of(Arguments.of((Executable) () -> new GZIPInputStream(null)),
45+
Arguments.of((Executable) () -> new GZIPInputStream(null, 1)));
46+
}
47+
48+
/*
49+
* Verifies that the GZIPInputStream constructors throw the expected NullPointerException
50+
*/
51+
@ParameterizedTest
52+
@MethodSource("npeFromConstructors")
53+
public void testNPEFromConstructors(final Executable constructor) {
54+
Assertions.assertThrows(NullPointerException.class, constructor,
55+
"GZIPInputStream constructor did not throw NullPointerException");
56+
}
57+
58+
private static Stream<Arguments> iaeFromConstructors() {
59+
return Stream.of(
60+
Arguments.of((Executable) () -> new GZIPInputStream(
61+
new ByteArrayInputStream(new byte[0]), 0)),
62+
Arguments.of((Executable) () -> new GZIPInputStream(
63+
new ByteArrayInputStream(new byte[0]), -1)),
64+
Arguments.of((Executable) () -> new GZIPInputStream(
65+
new ByteArrayInputStream(new byte[0]), -42)));
66+
}
67+
68+
/*
69+
* Verifies that the GZIPInputStream constructors throw the expected IllegalArgumentException
70+
*/
71+
@ParameterizedTest
72+
@MethodSource("iaeFromConstructors")
73+
public void testIAEFromConstructors(final Executable constructor) {
74+
Assertions.assertThrows(IllegalArgumentException.class, constructor,
75+
"GZIPInputStream constructor did not throw IllegalArgumentException");
76+
}
77+
78+
private static Stream<Arguments> ioeFromConstructors() {
79+
final ByteArrayInputStream notGZIPContent = new ByteArrayInputStream(new byte[0]);
80+
return Stream.of(
81+
Arguments.of((Executable) () -> new GZIPInputStream(notGZIPContent)),
82+
Arguments.of((Executable) () -> new GZIPInputStream(
83+
notGZIPContent, 1024 /* buffer size */)));
84+
}
85+
86+
/*
87+
* Verifies that the GZIPInputStream constructors throw the expected IOException
88+
*/
89+
@ParameterizedTest
90+
@MethodSource("ioeFromConstructors")
91+
public void testIOEFromConstructors(final Executable constructor) {
92+
Assertions.assertThrows(IOException.class, constructor,
93+
"GZIPInputStream constructor did not throw IOException");
94+
}
95+
}

0 commit comments

Comments
 (0)