diff --git a/src/share/classes/java/lang/Class.java b/src/share/classes/java/lang/Class.java index 5593f2b4898ca5e9d1f1193af098d1d3537d00ce..614ecdf3d4659c45410afb6413cd33c8a7662178 100644 --- a/src/share/classes/java/lang/Class.java +++ b/src/share/classes/java/lang/Class.java @@ -961,9 +961,28 @@ public final class Class implements java.io.Serializable, * * @return the immediately enclosing method of the underlying class, if * that class is a local or anonymous class; otherwise {@code null}. + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + * * @since 1.5 */ - public Method getEnclosingMethod() { + @CallerSensitive + public Method getEnclosingMethod() throws SecurityException { EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo(); if (enclosingInfo == null) @@ -984,13 +1003,22 @@ public final class Class implements java.io.Serializable, for(int i = 0; i < parameterClasses.length; i++) parameterClasses[i] = toClass(parameterTypes[i]); + // Perform access check + Class enclosingCandidate = enclosingInfo.getEnclosingClass(); + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + // + // Note that we need to do this on the enclosing class + enclosingCandidate.checkMemberAccess(Member.DECLARED, + Reflection.getCallerClass(), true); /* * Loop over all declared methods; match method name, * number of and type of parameters, *and* return * type. Matching return type is also necessary * because of covariant returns, etc. */ - for(Method m: enclosingInfo.getEnclosingClass().getDeclaredMethods()) { + for(Method m: enclosingCandidate.getDeclaredMethods()) { if (m.getName().equals(enclosingInfo.getName()) ) { Class[] candidateParamClasses = m.getParameterTypes(); if (candidateParamClasses.length == parameterClasses.length) { @@ -1089,9 +1117,28 @@ public final class Class implements java.io.Serializable, * * @return the immediately enclosing constructor of the underlying class, if * that class is a local or anonymous class; otherwise {@code null}. + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *
    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(enclosingClass, Member.PUBLIC)} denies + * access to the constructors within the enclosing class + * + *
  • the caller's class loader is not the same as or an + * ancestor of the class loader for the enclosing class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of the enclosing class + * + *
* @since 1.5 */ - public Constructor getEnclosingConstructor() { + @CallerSensitive + public Constructor getEnclosingConstructor() throws SecurityException { EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo(); if (enclosingInfo == null) @@ -1111,11 +1158,20 @@ public final class Class implements java.io.Serializable, for(int i = 0; i < parameterClasses.length; i++) parameterClasses[i] = toClass(parameterTypes[i]); + // Perform access check + Class enclosingCandidate = enclosingInfo.getEnclosingClass(); + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + // + // Note that we need to do this on the enclosing class + enclosingCandidate.checkMemberAccess(Member.DECLARED, + Reflection.getCallerClass(), true); /* * Loop over all declared constructors; match number * of and type of parameters. */ - for(Constructor c: enclosingInfo.getEnclosingClass().getDeclaredConstructors()) { + for(Constructor c: enclosingCandidate.getDeclaredConstructors()) { Class[] candidateParamClasses = c.getParameterTypes(); if (candidateParamClasses.length == parameterClasses.length) { boolean matches = true; @@ -1155,9 +1211,16 @@ public final class Class implements java.io.Serializable, * class. If the underlying class is a top level class this * method returns {@code null}. * @return the immediately enclosing class of the underlying class + * @exception SecurityException + * If a security manager, s, is present and the caller's + * class loader is not the same as or an ancestor of the class + * loader for the enclosing class and invocation of {@link + * SecurityManager#checkPackageAccess s.checkPackageAccess()} + * denies access to the package of the enclosing class * @since 1.5 */ - public Class getEnclosingClass() { + @CallerSensitive + public Class getEnclosingClass() throws SecurityException { // There are five kinds of classes (or interfaces): // a) Top level classes // b) Nested classes (static member classes) @@ -1170,18 +1233,28 @@ public final class Class implements java.io.Serializable, // attribute if and only if it is a local class or an // anonymous class. EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo(); + Class enclosingCandidate; if (enclosingInfo == null) { // This is a top level or a nested class or an inner class (a, b, or c) - return getDeclaringClass(); + enclosingCandidate = getDeclaringClass(); } else { Class enclosingClass = enclosingInfo.getEnclosingClass(); // This is a local class or an anonymous class (d or e) if (enclosingClass == this || enclosingClass == null) throw new InternalError("Malformed enclosing method information"); else - return enclosingClass; + enclosingCandidate = enclosingClass; + } + + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + if (enclosingCandidate != null) { + enclosingCandidate.checkMemberAccess(Member.DECLARED, + Reflection.getCallerClass(), true); } + return enclosingCandidate; } /** diff --git a/test/lib/testlibrary/ClassFileInstaller.java b/test/lib/testlibrary/ClassFileInstaller.java new file mode 100644 index 0000000000000000000000000000000000000000..694223e77f30ca3f2e2747a9b3797d17d6a51a29 --- /dev/null +++ b/test/lib/testlibrary/ClassFileInstaller.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013, 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.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +/** + * Dump a class file for a class on the class path in the current directory + */ +public class ClassFileInstaller { + /** + * @param args The names of the classes to dump + * @throws Exception + */ + public static void main(String... args) throws Exception { + for (String arg : args) { + ClassLoader cl = ClassFileInstaller.class.getClassLoader(); + + // Convert dotted class name to a path to a class file + String pathName = arg.replace('.', '/').concat(".class"); + InputStream is = cl.getResourceAsStream(pathName); + + // Create the class file's package directory + Path p = Paths.get(pathName); + Files.createDirectories(p.getParent()); + // Create the class file + Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING); + } + } +}