Skip to content

Commit b77c161

Browse files
simonisyakovsh
andcommitted
8315135: Memory leak in the native implementation of Pack200.Unpacker.unpack()
Co-authored-by: Yakov Shafranovich <yakovsh@amazon.com> Reviewed-by: clanger, stuefe
1 parent b984b0a commit b77c161

File tree

4 files changed

+65
-2
lines changed

4 files changed

+65
-2
lines changed

src/java.base/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class NativeUnpack {
6161

6262
// Resets the engine and frees all resources.
6363
// Returns total number of bytes consumed by the engine.
64-
private synchronized native long finish();
64+
synchronized native long finish();
6565

6666
// Setting state in the unpacker.
6767
protected synchronized native boolean setOption(String opt, String value);

src/java.base/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ public synchronized void unpack(InputStream in, JarOutputStream out) throws IOEx
116116
} catch (UnsatisfiedLinkError | NoClassDefFoundError ex) {
117117
// failover to java implementation
118118
(new DoUnpack()).run(in0, out);
119+
} finally {
120+
if (_nunp != null) {
121+
// Free up native memory and JNI handles to prevent leaks
122+
((NativeUnpack) _nunp).finish();
123+
}
119124
}
120125
in0.close();
121126
Utils.markJarFile(out);

src/jdk.pack/share/native/libunpack/jni.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,12 @@ Java_com_sun_java_util_jar_pack_NativeUnpack_getUnusedInput(JNIEnv *env, jobject
314314

315315
JNIEXPORT jlong JNICALL
316316
Java_com_sun_java_util_jar_pack_NativeUnpack_finish(JNIEnv *env, jobject pObj) {
317-
unpacker* uPtr = get_unpacker(env, pObj, false);
317+
// There's no need to create a new unpacker here if we don't already have one
318+
// just to immediatly free it afterwards.
319+
unpacker* uPtr = get_unpacker(env, pObj, /* noCreate= */ true);
318320
CHECK_EXCEPTION_RETURN_VALUE(uPtr, 0);
319321
size_t consumed = uPtr->input_consumed();
322+
// free_unpacker() will set the unpacker field on 'pObj' to null
320323
free_unpacker(env, pObj, uPtr);
321324
return consumed;
322325
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright Amazon.com Inc. 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+
25+
/*
26+
* @test
27+
* @bug 8315135
28+
* @run main/othervm/timeout=300 -Dcom.sun.java.util.jar.pack.disable.native=false -Xmx8m UnpackMalformed
29+
*/
30+
31+
import java.io.ByteArrayInputStream;
32+
import java.io.ByteArrayOutputStream;
33+
import java.io.IOException;
34+
import java.util.jar.JarOutputStream;
35+
import java.util.jar.Pack200;
36+
37+
@SuppressWarnings("removal")
38+
public class UnpackMalformed {
39+
public static void main(String[] args) {
40+
try {
41+
ByteArrayInputStream in = new ByteArrayInputStream("foobar".getBytes());
42+
for (int i=0; i < 1_000; i++) {
43+
try {
44+
JarOutputStream out = new JarOutputStream(new ByteArrayOutputStream());
45+
Pack200.Unpacker unpacker = Pack200.newUnpacker();
46+
unpacker.unpack(in, out);
47+
} catch (IOException e) {
48+
}
49+
}
50+
} catch (OutOfMemoryError e) {
51+
System.out.println(e);
52+
throw e;
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)