OpenJDK / jdk7u / jdk7u-dev / jdk
changeset 6310:5d5ca338574f
8007812: (reflect) Class.getEnclosingMethod problematic for some classes
Summary: Better checking in getEnclosing(Method|Constructor|Class)
Reviewed-by: darcy, ahgross, mchung
author | jfranck |
---|---|
date | Mon, 25 Mar 2013 20:18:21 +0100 |
parents | 141facdacbf0 |
children | a0f09271d2c5 |
files | src/share/classes/java/lang/Class.java src/share/classes/java/lang/invoke/MethodHandleNatives.java test/lib/testlibrary/ClassFileInstaller.java |
diffstat | 3 files changed, 88 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/java/lang/Class.java Mon Mar 25 17:05:30 2013 +0000 +++ b/src/share/classes/java/lang/Class.java Mon Mar 25 20:18:21 2013 +0100 @@ -915,13 +915,22 @@ 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, + ClassLoader.getCallerClassLoader(), 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) { @@ -1042,11 +1051,20 @@ 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, + ClassLoader.getCallerClassLoader(), 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; @@ -1101,18 +1119,28 @@ // 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, + ClassLoader.getCallerClassLoader(), true); + } + return enclosingCandidate; } /**
--- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java Mon Mar 25 17:05:30 2013 +0000 +++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java Mon Mar 25 20:18:21 2013 +0100 @@ -477,6 +477,9 @@ case "getDeclaredField": case "getDeclaredMethod": case "getDeclaredConstructor": + case "getEnclosingClass": + case "getEnclosingMethod": + case "getEnclosingConstructor": return defc == java.lang.Class.class; case "getConnection": case "getDriver":
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/lib/testlibrary/ClassFileInstaller.java Mon Mar 25 20:18:21 2013 +0100 @@ -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); + } + } +}