From 20c0c1d9d0b24319d980044be00b244d63e9b94c Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Wed, 23 Nov 2016 10:41:25 -0800 Subject: [PATCH] 8136831: Undefined null behavior in ClassLoader.getResourceXXXX() Reviewed-by: alanb, mchung, psandoz --- .../share/classes/java/lang/ClassLoader.java | 9 ++ .../classes/java/net/URLClassLoader.java | 4 + .../lang/ClassLoader/GetResourceNullArg.java | 96 +++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 jdk/test/java/lang/ClassLoader/GetResourceNullArg.java diff --git a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java index 843fd3c3601..adffac17c78 100644 --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java @@ -1335,10 +1335,12 @@ public abstract class ClassLoader { * @return A URL object for reading the resource, or * null if the resource could not be found or the invoker * doesn't have adequate privileges to get the resource. + * @throws NullPointerException If {@code name} is {@code null} * * @since 1.1 */ public URL getResource(String name) { + Objects.requireNonNull(name); URL url; if (parent != null) { url = parent.getResource(name); @@ -1382,12 +1384,14 @@ public abstract class ClassLoader { * * @throws IOException * If I/O errors occur + * @throws NullPointerException If {@code name} is {@code null} * * @see #findResources(String) * * @since 1.2 */ public Enumeration getResources(String name) throws IOException { + Objects.requireNonNull(name); @SuppressWarnings("unchecked") Enumeration[] tmp = (Enumeration[]) new Enumeration[2]; if (parent != null) { @@ -1434,11 +1438,14 @@ public abstract class ClassLoader { * that the class loader doesn't have access to will not be in the * stream. * + * @throws NullPointerException If {@code name} is {@code null} + * * @see #findResources(String) * * @since 9 */ public Stream resources(String name) { + Objects.requireNonNull(name); int characteristics = Spliterator.NONNULL | Spliterator.IMMUTABLE; Supplier> si = () -> { try { @@ -1600,10 +1607,12 @@ public abstract class ClassLoader { * * @return An input stream for reading the resource, or null * if the resource could not be found + * @throws NullPointerException If {@code name} is {@code null} * * @since 1.1 */ public InputStream getResourceAsStream(String name) { + Objects.requireNonNull(name); URL url = getResource(name); try { return url != null ? url.openStream() : null; diff --git a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java index ef166dcdc23..602f9d7f61a 100644 --- a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java +++ b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java @@ -42,6 +42,7 @@ import java.security.SecureClassLoader; import java.util.Enumeration; import java.util.List; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Set; import java.util.WeakHashMap; import java.util.jar.Attributes; @@ -301,9 +302,12 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { * @return An input stream for reading the resource, or {@code null} * if the resource could not be found * + * @throws NullPointerException If {@code name} is {@code null} + * * @since 1.7 */ public InputStream getResourceAsStream(String name) { + Objects.requireNonNull(name); URL url = getResource(name); try { if (url == null) { diff --git a/jdk/test/java/lang/ClassLoader/GetResourceNullArg.java b/jdk/test/java/lang/ClassLoader/GetResourceNullArg.java new file mode 100644 index 00000000000..a8fca625cd4 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/GetResourceNullArg.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Paths; +import java.util.Enumeration; +import java.util.stream.Stream; +import org.testng.annotations.*; + +/* + * @test + * @bug 8136831 + * @summary Test null argument to ClassLoader.getResourceXXXX() + * @run testng GetResourceNullArg + */ + +public class GetResourceNullArg { + private static class MyClassLoader extends ClassLoader { + public MyClassLoader() { + super(null); + } + @Override + public Class findClass(String name) throws ClassNotFoundException { + throw new ClassNotFoundException("Why are you using this?"); + } + } + + @DataProvider + public static ClassLoader[][] provider() { + try { + return new ClassLoader[][] { + { ClassLoader.getSystemClassLoader() }, + { new MyClassLoader() }, + { new URLClassLoader(new URL[]{ Paths.get(".").toUri().toURL() }, + ClassLoader.getSystemClassLoader()) } + }; + } catch (MalformedURLException e) { throw new RuntimeException(e); } + } + + @Test(expectedExceptions = NullPointerException.class) + public void classGetResource() { + this.getClass().getResource(null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void classGetResourceAsStream() { + this.getClass().getResourceAsStream(null); + } + + @Test(dataProvider = "provider", + expectedExceptions = NullPointerException.class) + public void loaderGetResource(ClassLoader cl) { + cl.getResource(null); + } + + @Test(dataProvider = "provider", + expectedExceptions = NullPointerException.class) + public static void loaderGetResources(ClassLoader cl) throws IOException { + Enumeration retVal = cl.getResources(null); + } + + @Test(dataProvider = "provider", + expectedExceptions = NullPointerException.class) + public static void loaderResources(ClassLoader cl) throws IOException { + Stream retVal = cl.resources(null); + } + + @Test(dataProvider = "provider", + expectedExceptions = NullPointerException.class) + public void loaderGetResourceAsStream(ClassLoader cl) { + cl.getResourceAsStream(null); + } +}