# HG changeset patch # User yhuang # Date 1366185885 25200 # Node ID 779ba708fee3182f6fed7ef396a6eef4834c7b9f # Parent 414384c3b3eb95cfec948c623117b6421f870d79# Parent da6addef956e6d1074288dcc60097f07749eed9b Merge diff -r 414384c3b3eb -r 779ba708fee3 make/java/java/FILES_c.gmk --- a/make/java/java/FILES_c.gmk Tue Apr 16 22:28:47 2013 -0700 +++ b/make/java/java/FILES_c.gmk Wed Apr 17 01:04:45 2013 -0700 @@ -48,7 +48,6 @@ Proxy.c \ RandomAccessFile.c \ RandomAccessFile_md.c \ - ResourceBundle.c \ Runtime.c \ SecurityManager.c \ Shutdown.c \ diff -r 414384c3b3eb -r 779ba708fee3 make/java/java/mapfile-vers --- a/make/java/java/mapfile-vers Tue Apr 16 22:28:47 2013 -0700 +++ b/make/java/java/mapfile-vers Wed Apr 17 01:04:45 2013 -0700 @@ -134,7 +134,6 @@ Java_java_lang_ClassLoader_00024NativeLibrary_load; Java_java_lang_ClassLoader_00024NativeLibrary_unload; Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib; - Java_java_lang_ClassLoader_getCaller; Java_java_lang_ClassLoader_registerNatives; Java_java_lang_Compiler_registerNatives; Java_java_lang_Double_longBitsToDouble; @@ -233,7 +232,6 @@ Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2; Java_java_security_AccessController_getStackAccessControlContext; Java_java_security_AccessController_getInheritedAccessControlContext; - Java_java_util_ResourceBundle_getClassContext; Java_java_util_TimeZone_getSystemTimeZoneID; Java_java_util_TimeZone_getSystemGMTOffsetID; Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8; diff -r 414384c3b3eb -r 779ba708fee3 make/java/java/reorder-i586 --- a/make/java/java/reorder-i586 Tue Apr 16 22:28:47 2013 -0700 +++ b/make/java/java/reorder-i586 Wed Apr 17 01:04:45 2013 -0700 @@ -73,7 +73,6 @@ # Test Sleep # Test IntToString # Test LoadToolkit -text: .text%Java_java_util_ResourceBundle_getClassContext; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess; diff -r 414384c3b3eb -r 779ba708fee3 make/java/java/reorder-sparc --- a/make/java/java/reorder-sparc Tue Apr 16 22:28:47 2013 -0700 +++ b/make/java/java/reorder-sparc Wed Apr 17 01:04:45 2013 -0700 @@ -78,7 +78,6 @@ # Test Sleep # Test IntToString # Test LoadToolkit -text: .text%Java_java_util_ResourceBundle_getClassContext; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess; diff -r 414384c3b3eb -r 779ba708fee3 make/java/java/reorder-sparcv9 --- a/make/java/java/reorder-sparcv9 Tue Apr 16 22:28:47 2013 -0700 +++ b/make/java/java/reorder-sparcv9 Wed Apr 17 01:04:45 2013 -0700 @@ -74,7 +74,6 @@ # Test Sleep # Test IntToString # Test LoadToolkit -text: .text%Java_java_util_ResourceBundle_getClassContext; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess; diff -r 414384c3b3eb -r 779ba708fee3 makefiles/mapfiles/libjava/mapfile-vers --- a/makefiles/mapfiles/libjava/mapfile-vers Tue Apr 16 22:28:47 2013 -0700 +++ b/makefiles/mapfiles/libjava/mapfile-vers Wed Apr 17 01:04:45 2013 -0700 @@ -134,7 +134,6 @@ Java_java_lang_ClassLoader_00024NativeLibrary_load; Java_java_lang_ClassLoader_00024NativeLibrary_unload; Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib; - Java_java_lang_ClassLoader_getCaller; Java_java_lang_ClassLoader_registerNatives; Java_java_lang_Compiler_registerNatives; Java_java_lang_Double_longBitsToDouble; @@ -233,7 +232,6 @@ Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2; Java_java_security_AccessController_getStackAccessControlContext; Java_java_security_AccessController_getInheritedAccessControlContext; - Java_java_util_ResourceBundle_getClassContext; Java_java_util_TimeZone_getSystemTimeZoneID; Java_java_util_TimeZone_getSystemGMTOffsetID; Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8; diff -r 414384c3b3eb -r 779ba708fee3 makefiles/mapfiles/libjava/reorder-sparc --- a/makefiles/mapfiles/libjava/reorder-sparc Tue Apr 16 22:28:47 2013 -0700 +++ b/makefiles/mapfiles/libjava/reorder-sparc Wed Apr 17 01:04:45 2013 -0700 @@ -78,7 +78,6 @@ # Test Sleep # Test IntToString # Test LoadToolkit -text: .text%Java_java_util_ResourceBundle_getClassContext; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess; diff -r 414384c3b3eb -r 779ba708fee3 makefiles/mapfiles/libjava/reorder-sparcv9 --- a/makefiles/mapfiles/libjava/reorder-sparcv9 Tue Apr 16 22:28:47 2013 -0700 +++ b/makefiles/mapfiles/libjava/reorder-sparcv9 Wed Apr 17 01:04:45 2013 -0700 @@ -74,7 +74,6 @@ # Test Sleep # Test IntToString # Test LoadToolkit -text: .text%Java_java_util_ResourceBundle_getClassContext; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess; diff -r 414384c3b3eb -r 779ba708fee3 makefiles/mapfiles/libjava/reorder-x86 --- a/makefiles/mapfiles/libjava/reorder-x86 Tue Apr 16 22:28:47 2013 -0700 +++ b/makefiles/mapfiles/libjava/reorder-x86 Wed Apr 17 01:04:45 2013 -0700 @@ -73,7 +73,6 @@ # Test Sleep # Test IntToString # Test LoadToolkit -text: .text%Java_java_util_ResourceBundle_getClassContext; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess; diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/Class.java --- a/src/share/classes/java/lang/Class.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/Class.java Wed Apr 17 01:04:45 2013 -0700 @@ -53,6 +53,7 @@ import java.util.HashMap; import java.util.Objects; import sun.misc.Unsafe; +import sun.reflect.CallerSensitive; import sun.reflect.ConstantPool; import sun.reflect.Reflection; import sun.reflect.ReflectionFactory; @@ -250,9 +251,11 @@ * by this method fails * @exception ClassNotFoundException if the class cannot be located */ + @CallerSensitive public static Class forName(String className) throws ClassNotFoundException { - return forName0(className, true, ClassLoader.getCallerClassLoader()); + return forName0(className, true, + ClassLoader.getClassLoader(Reflection.getCallerClass())); } @@ -317,6 +320,7 @@ * @see java.lang.ClassLoader * @since 1.2 */ + @CallerSensitive public static Class forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException @@ -324,7 +328,7 @@ if (sun.misc.VM.isSystemDomainLoader(loader)) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ClassLoader ccl = ClassLoader.getCallerClassLoader(); + ClassLoader ccl = ClassLoader.getClassLoader(Reflection.getCallerClass()); if (!sun.misc.VM.isSystemDomainLoader(ccl)) { sm.checkPermission( SecurityConstants.GET_CLASSLOADER_PERMISSION); @@ -386,18 +390,14 @@ * * */ + @CallerSensitive public T newInstance() throws InstantiationException, IllegalAccessException { if (System.getSecurityManager() != null) { - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false); } - return newInstance0(); - } - private T newInstance0() - throws InstantiationException, IllegalAccessException - { // NOTE: the following code may not be strictly correct under // the current Java memory model. @@ -432,7 +432,7 @@ // Security check (same as in java.lang.reflect.Constructor) int modifiers = tmpConstructor.getModifiers(); if (!Reflection.quickCheckMemberAccess(this, modifiers)) { - Class caller = Reflection.getCallerClass(3); + Class caller = Reflection.getCallerClass(); if (newInstanceCallerCache != caller) { Reflection.ensureMemberAccess(caller, this, null, modifiers); newInstanceCallerCache = caller; @@ -674,16 +674,14 @@ * @see SecurityManager#checkPermission * @see java.lang.RuntimePermission */ + @CallerSensitive public ClassLoader getClassLoader() { ClassLoader cl = getClassLoader0(); if (cl == null) return null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ClassLoader ccl = ClassLoader.getCallerClassLoader(); - if (ClassLoader.needsClassLoaderPermissionCheck(ccl, cl)) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } + ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass()); } return cl; } @@ -1392,11 +1390,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Class[] getClasses() { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false); // Privileged so this implementation can look at DECLARED classes, // something the caller might not have privilege to do. The code here @@ -1467,11 +1463,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Field[] getFields() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); return copyFields(privateGetPublicFields(null)); } @@ -1518,11 +1512,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Method[] getMethods() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); return copyMethods(privateGetPublicMethods()); } @@ -1567,11 +1559,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Constructor[] getConstructors() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); return copyConstructors(privateGetDeclaredConstructors(true)); } @@ -1625,12 +1615,10 @@ * * @since JDK1.1 */ + @CallerSensitive public Field getField(String name) throws NoSuchFieldException, SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); Field field = getField0(name); if (field == null) { throw new NoSuchFieldException(name); @@ -1710,12 +1698,10 @@ * * @since JDK1.1 */ + @CallerSensitive public Method getMethod(String name, Class... parameterTypes) throws NoSuchMethodException, SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); Method method = getMethod0(name, parameterTypes); if (method == null) { throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); @@ -1764,12 +1750,10 @@ * * @since JDK1.1 */ + @CallerSensitive public Constructor getConstructor(Class... parameterTypes) throws NoSuchMethodException, SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); return getConstructor0(parameterTypes, Member.PUBLIC); } @@ -1807,11 +1791,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Class[] getDeclaredClasses() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), false); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), false); return getDeclaredClasses0(); } @@ -1851,11 +1833,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Field[] getDeclaredFields() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return copyFields(privateGetDeclaredFields(false)); } @@ -1899,11 +1879,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Method[] getDeclaredMethods() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return copyMethods(privateGetDeclaredMethods(false)); } @@ -1944,11 +1922,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Constructor[] getDeclaredConstructors() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return copyConstructors(privateGetDeclaredConstructors(false)); } @@ -1987,12 +1963,10 @@ * * @since JDK1.1 */ + @CallerSensitive public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); Field field = searchFields(privateGetDeclaredFields(false), name); if (field == null) { throw new NoSuchFieldException(name); @@ -2042,12 +2016,10 @@ * * @since JDK1.1 */ + @CallerSensitive public Method getDeclaredMethod(String name, Class... parameterTypes) throws NoSuchMethodException, SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes); if (method == null) { throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); @@ -2092,12 +2064,10 @@ * * @since JDK1.1 */ + @CallerSensitive public Constructor getDeclaredConstructor(Class... parameterTypes) throws NoSuchMethodException, SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return getConstructor0(parameterTypes, Member.DECLARED); } @@ -2255,23 +2225,40 @@ */ static native Class getPrimitiveClass(String name); + private static boolean isCheckMemberAccessOverridden(SecurityManager smgr) { + if (smgr.getClass() == SecurityManager.class) return false; + + Class[] paramTypes = new Class[] {Class.class, int.class}; + return smgr.getClass().getMethod0("checkMemberAccess", paramTypes). + getDeclaringClass() != SecurityManager.class; + } /* * Check if client is allowed to access members. If access is denied, * throw a SecurityException. * - * Be very careful not to change the stack depth of this checkMemberAccess - * call for security reasons. - * See java.lang.SecurityManager.checkMemberAccess. - * *

Default policy: allow all clients access with normal Java access * control. */ - private void checkMemberAccess(int which, ClassLoader ccl, boolean checkProxyInterfaces) { - SecurityManager s = System.getSecurityManager(); + private void checkMemberAccess(int which, Class caller, boolean checkProxyInterfaces) { + final SecurityManager s = System.getSecurityManager(); if (s != null) { - s.checkMemberAccess(this, which); - ClassLoader cl = getClassLoader0(); + final ClassLoader ccl = ClassLoader.getClassLoader(caller); + final ClassLoader cl = getClassLoader0(); + if (!isCheckMemberAccessOverridden(s)) { + // Inlined SecurityManager.checkMemberAccess + if (which != Member.PUBLIC) { + if (ccl != cl) { + s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); + } + } + } else { + // Don't refactor; otherwise break the stack depth for + // checkMemberAccess of subclasses of SecurityManager as specified. + s.checkMemberAccess(this, which); + } + + if (ReflectUtil.needsPackageAccessCheck(ccl, cl)) { String name = this.getName(); int i = name.lastIndexOf('.'); diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/ClassLoader.java --- a/src/share/classes/java/lang/ClassLoader.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/ClassLoader.java Wed Apr 17 01:04:45 2013 -0700 @@ -55,6 +55,7 @@ import sun.misc.Resource; import sun.misc.URLClassPath; import sun.misc.VM; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; @@ -1159,11 +1160,6 @@ return java.util.Collections.emptyEnumeration(); } - // index 0: java.lang.ClassLoader.class - // index 1: the immediate caller of index 0. - // index 2: the immediate caller of index 1. - private static native Class getCaller(int index); - /** * Registers the caller as parallel capable.

* The registration succeeds if and only if all of the following @@ -1179,8 +1175,11 @@ * * @since 1.7 */ + @CallerSensitive protected static boolean registerAsParallelCapable() { - return ParallelLoaders.register(getCaller(1)); + Class callerClass = + Reflection.getCallerClass().asSubclass(ClassLoader.class); + return ParallelLoaders.register(callerClass); } /** @@ -1340,15 +1339,13 @@ * * @since 1.2 */ + @CallerSensitive public final ClassLoader getParent() { if (parent == null) return null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ClassLoader ccl = getCallerClassLoader(); - if (needsClassLoaderPermissionCheck(ccl, this)) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } + checkClassLoaderPermission(this, Reflection.getCallerClass()); } return parent; } @@ -1408,6 +1405,7 @@ * * @revised 1.4 */ + @CallerSensitive public static ClassLoader getSystemClassLoader() { initSystemClassLoader(); if (scl == null) { @@ -1415,10 +1413,7 @@ } SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ClassLoader ccl = getCallerClassLoader(); - if (needsClassLoaderPermissionCheck(ccl, scl)) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } + checkClassLoaderPermission(scl, Reflection.getCallerClass()); } return scl; } @@ -1471,8 +1466,8 @@ // class loader 'from' is same as class loader 'to' or an ancestor // of 'to'. The class loader in a system domain can access // any class loader. - static boolean needsClassLoaderPermissionCheck(ClassLoader from, - ClassLoader to) + private static boolean needsClassLoaderPermissionCheck(ClassLoader from, + ClassLoader to) { if (from == to) return false; @@ -1483,13 +1478,8 @@ return !to.isAncestor(from); } - // Returns the invoker's class loader, or null if none. - // NOTE: This must always be invoked when there is exactly one intervening - // frame from the core libraries on the stack between this method's - // invocation and the desired invoker. - static ClassLoader getCallerClassLoader() { - // NOTE use of more generic Reflection.getCallerClass() - Class caller = Reflection.getCallerClass(3); + // Returns the class's class loader, or null if none. + static ClassLoader getClassLoader(Class caller) { // This can be null if the VM is requesting it if (caller == null) { return null; @@ -1498,6 +1488,17 @@ return caller.getClassLoader0(); } + static void checkClassLoaderPermission(ClassLoader cl, Class caller) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + // caller can be null if the VM is requesting it + ClassLoader ccl = getClassLoader(caller); + if (needsClassLoaderPermissionCheck(ccl, cl)) { + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + } + } + // The class loader for the system // @GuardedBy("ClassLoader.class") private static ClassLoader scl; diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/Package.java --- a/src/share/classes/java/lang/Package.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/Package.java Wed Apr 17 01:04:45 2013 -0700 @@ -49,6 +49,8 @@ import java.util.Iterator; import sun.net.www.ParseUtil; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; import java.lang.annotation.Annotation; @@ -273,8 +275,9 @@ * @return the package of the requested name. It may be null if no package * information is available from the archive or codebase. */ + @CallerSensitive public static Package getPackage(String name) { - ClassLoader l = ClassLoader.getCallerClassLoader(); + ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); if (l != null) { return l.getPackage(name); } else { @@ -294,8 +297,9 @@ * @return a new array of packages known to the callers {@code ClassLoader} * instance. An zero length array is returned if none are known. */ + @CallerSensitive public static Package[] getPackages() { - ClassLoader l = ClassLoader.getCallerClassLoader(); + ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); if (l != null) { return l.getPackages(); } else { diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/Runtime.java --- a/src/share/classes/java/lang/Runtime.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/Runtime.java Wed Apr 17 01:04:45 2013 -0700 @@ -27,6 +27,8 @@ import java.io.*; import java.util.StringTokenizer; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; /** * Every Java application has a single instance of class @@ -790,8 +792,9 @@ * @see java.lang.SecurityException * @see java.lang.SecurityManager#checkLink(java.lang.String) */ + @CallerSensitive public void load(String filename) { - load0(System.getCallerClass(), filename); + load0(Reflection.getCallerClass(), filename); } synchronized void load0(Class fromClass, String filename) { @@ -850,8 +853,9 @@ * @see java.lang.SecurityException * @see java.lang.SecurityManager#checkLink(java.lang.String) */ + @CallerSensitive public void loadLibrary(String libname) { - loadLibrary0(System.getCallerClass(), libname); + loadLibrary0(Reflection.getCallerClass(), libname); } synchronized void loadLibrary0(Class fromClass, String libname) { diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/SecurityManager.java --- a/src/share/classes/java/lang/SecurityManager.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/SecurityManager.java Wed Apr 17 01:04:45 2013 -0700 @@ -36,10 +36,10 @@ import java.net.NetPermission; import java.util.Hashtable; import java.net.InetAddress; -import java.lang.reflect.Member; import java.lang.reflect.*; import java.net.URL; +import sun.reflect.CallerSensitive; import sun.security.util.SecurityConstants; /** @@ -1679,6 +1679,7 @@ * @since JDK1.1 * @see #checkPermission(java.security.Permission) checkPermission */ + @CallerSensitive public void checkMemberAccess(Class clazz, int which) { if (clazz == null) { throw new NullPointerException("class can't be null"); diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/System.java --- a/src/share/classes/java/lang/System.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/System.java Wed Apr 17 01:04:45 2013 -0700 @@ -35,6 +35,7 @@ import java.nio.channels.Channel; import java.nio.channels.spi.SelectorProvider; import sun.nio.ch.Interruptible; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; import sun.reflect.annotation.AnnotationType; @@ -1072,8 +1073,9 @@ * @see java.lang.Runtime#load(java.lang.String) * @see java.lang.SecurityManager#checkLink(java.lang.String) */ + @CallerSensitive public static void load(String filename) { - Runtime.getRuntime().load0(getCallerClass(), filename); + Runtime.getRuntime().load0(Reflection.getCallerClass(), filename); } /** @@ -1107,8 +1109,9 @@ * @see java.lang.Runtime#loadLibrary(java.lang.String) * @see java.lang.SecurityManager#checkLink(java.lang.String) */ + @CallerSensitive public static void loadLibrary(String libname) { - Runtime.getRuntime().loadLibrary0(getCallerClass(), libname); + Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname); } /** @@ -1245,10 +1248,4 @@ } }); } - - /* returns the class of the caller. */ - static Class getCallerClass() { - // NOTE use of more generic Reflection.getCallerClass() - return Reflection.getCallerClass(3); - } } diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/Thread.java --- a/src/share/classes/java/lang/Thread.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/Thread.java Wed Apr 17 01:04:45 2013 -0700 @@ -37,6 +37,8 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.LockSupport; import sun.nio.ch.Interruptible; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; import sun.security.util.SecurityConstants; @@ -1443,15 +1445,14 @@ * * @since 1.2 */ + @CallerSensitive public ClassLoader getContextClassLoader() { if (contextClassLoader == null) return null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ClassLoader ccl = ClassLoader.getCallerClassLoader(); - if (ClassLoader.needsClassLoaderPermissionCheck(ccl, contextClassLoader)) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } + ClassLoader.checkClassLoaderPermission(contextClassLoader, + Reflection.getCallerClass()); } return contextClassLoader; } diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/invoke/BoundMethodHandle.java --- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java Wed Apr 17 01:04:45 2013 -0700 @@ -709,7 +709,9 @@ InvokerBytecodeGenerator.maybeDump(className, classFile); Class bmhClass = //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class); - UNSAFE.defineClass(className, classFile, 0, classFile.length).asSubclass(BoundMethodHandle.class); + UNSAFE.defineClass(className, classFile, 0, classFile.length, + BoundMethodHandle.class.getClassLoader(), null) + .asSubclass(BoundMethodHandle.class); UNSAFE.ensureClassInitialized(bmhClass); return bmhClass; diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/invoke/MemberName.java --- a/src/share/classes/java/lang/invoke/MemberName.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/invoke/MemberName.java Wed Apr 17 01:04:45 2013 -0700 @@ -391,10 +391,11 @@ // private flags, not part of RECOGNIZED_MODIFIERS: static final int - IS_METHOD = MN_IS_METHOD, // method (not constructor) - IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor - IS_FIELD = MN_IS_FIELD, // field - IS_TYPE = MN_IS_TYPE; // nested type + IS_METHOD = MN_IS_METHOD, // method (not constructor) + IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor + IS_FIELD = MN_IS_FIELD, // field + IS_TYPE = MN_IS_TYPE, // nested type + CALLER_SENSITIVE = MN_CALLER_SENSITIVE; // @CallerSensitive annotation detected static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED; static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE; @@ -430,6 +431,10 @@ public boolean isPackage() { return !testAnyFlags(ALL_ACCESS); } + /** Query whether this member has a CallerSensitive annotation. */ + public boolean isCallerSensitive() { + return testAllFlags(CALLER_SENSITIVE); + } /** Utility method to query whether this member is accessible from a given lookup class. */ public boolean isAccessibleFrom(Class lookupClass) { diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/invoke/MethodHandleImpl.java --- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Apr 17 01:04:45 2013 -0700 @@ -34,6 +34,8 @@ import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyType; import sun.invoke.util.Wrapper; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; @@ -891,9 +893,11 @@ } } + @CallerSensitive private static boolean checkCallerClass(Class expected, Class expected2) { - final int FRAME_COUNT_ARG = 2; // [0] Reflection [1] BindCaller [2] Expected - Class actual = sun.reflect.Reflection.getCallerClass(FRAME_COUNT_ARG); + // This method is called via MH_checkCallerClass and so it's + // correct to ask for the immediate caller here. + Class actual = Reflection.getCallerClass(); if (actual != expected && actual != expected2) throw new InternalError("found "+actual.getName()+", expected "+expected.getName() +(expected == expected2 ? "" : ", or else "+expected2.getName())); diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/invoke/MethodHandleNatives.java --- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java Wed Apr 17 01:04:45 2013 -0700 @@ -26,7 +26,6 @@ package java.lang.invoke; import java.lang.invoke.MethodHandles.Lookup; -import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.*; @@ -34,7 +33,7 @@ /** * The JVM interface for the method handles package is all here. - * This is an interface internal and private to an implemetantion of JSR 292. + * This is an interface internal and private to an implementation of JSR 292. * This class is not part of the JSR 292 standard. * @author jrose */ @@ -101,6 +100,7 @@ MN_IS_CONSTRUCTOR = 0x00020000, // constructor MN_IS_FIELD = 0x00040000, // field MN_IS_TYPE = 0x00080000, // nested type + MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected MN_REFERENCE_KIND_SHIFT = 24, // refKind MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT, // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers: @@ -391,129 +391,24 @@ * I.e., does it call Reflection.getCallerClass or a similer method * to ask about the identity of its caller? */ - // FIXME: Replace this pattern match by an annotation @sun.reflect.CallerSensitive. static boolean isCallerSensitive(MemberName mem) { if (!mem.isInvocable()) return false; // fields are not caller sensitive + + return mem.isCallerSensitive() || canBeCalledVirtual(mem); + } + + static boolean canBeCalledVirtual(MemberName mem) { + assert(mem.isInvocable()); Class defc = mem.getDeclaringClass(); switch (mem.getName()) { - case "doPrivileged": - case "doPrivilegedWithCombiner": - return defc == java.security.AccessController.class; case "checkMemberAccess": return canBeCalledVirtual(mem, java.lang.SecurityManager.class); - case "getUnsafe": - return defc == sun.misc.Unsafe.class; - case "lookup": - return defc == java.lang.invoke.MethodHandles.class; - case "findStatic": - case "findVirtual": - case "findConstructor": - case "findSpecial": - case "findGetter": - case "findSetter": - case "findStaticGetter": - case "findStaticSetter": - case "bind": - case "unreflect": - case "unreflectSpecial": - case "unreflectConstructor": - case "unreflectGetter": - case "unreflectSetter": - return defc == java.lang.invoke.MethodHandles.Lookup.class; - case "invoke": - return defc == java.lang.reflect.Method.class; - case "get": - case "getBoolean": - case "getByte": - case "getChar": - case "getShort": - case "getInt": - case "getLong": - case "getFloat": - case "getDouble": - case "set": - case "setBoolean": - case "setByte": - case "setChar": - case "setShort": - case "setInt": - case "setLong": - case "setFloat": - case "setDouble": - return defc == java.lang.reflect.Field.class; - case "newInstance": - if (defc == java.lang.reflect.Constructor.class) return true; - if (defc == java.lang.Class.class) return true; - break; - case "forName": - case "getClassLoader": - case "getClasses": - case "getFields": - case "getMethods": - case "getConstructors": - case "getDeclaredClasses": - case "getDeclaredFields": - case "getDeclaredMethods": - case "getDeclaredConstructors": - case "getField": - case "getMethod": - case "getConstructor": - case "getDeclaredField": - case "getDeclaredMethod": - case "getDeclaredConstructor": - return defc == java.lang.Class.class; - case "getConnection": - case "getDriver": - case "getDrivers": - case "deregisterDriver": - return defc == getClass("java.sql.DriverManager"); - case "newUpdater": - if (defc == java.util.concurrent.atomic.AtomicIntegerFieldUpdater.class) return true; - if (defc == java.util.concurrent.atomic.AtomicLongFieldUpdater.class) return true; - if (defc == java.util.concurrent.atomic.AtomicReferenceFieldUpdater.class) return true; - break; case "getContextClassLoader": return canBeCalledVirtual(mem, java.lang.Thread.class); - case "getPackage": - case "getPackages": - return defc == java.lang.Package.class; - case "getParent": - case "getSystemClassLoader": - return defc == java.lang.ClassLoader.class; - case "load": - case "loadLibrary": - if (defc == java.lang.Runtime.class) return true; - if (defc == java.lang.System.class) return true; - break; - case "getCallerClass": - if (defc == sun.reflect.Reflection.class) return true; - if (defc == java.lang.System.class) return true; - break; - case "getCallerClassLoader": - return defc == java.lang.ClassLoader.class; - case "registerAsParallelCapable": - return canBeCalledVirtual(mem, java.lang.ClassLoader.class); - case "getProxyClass": - case "newProxyInstance": - return defc == java.lang.reflect.Proxy.class; - case "asInterfaceInstance": - return defc == java.lang.invoke.MethodHandleProxies.class; - case "getBundle": - case "clearCache": - return defc == java.util.ResourceBundle.class; } return false; } - // avoid static dependency to a class in other modules - private static Class getClass(String cn) { - try { - return Class.forName(cn, false, - MethodHandleNatives.class.getClassLoader()); - } catch (ClassNotFoundException e) { - throw new InternalError(e); - } - } static boolean canBeCalledVirtual(MemberName symbolicRef, Class definingClass) { Class symbolicRefClass = symbolicRef.getDeclaringClass(); if (symbolicRefClass == definingClass) return true; diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/invoke/MethodHandleProxies.java --- a/src/share/classes/java/lang/invoke/MethodHandleProxies.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/invoke/MethodHandleProxies.java Wed Apr 17 01:04:45 2013 -0700 @@ -30,6 +30,7 @@ import java.security.PrivilegedAction; import sun.invoke.WrapperInstance; import java.util.ArrayList; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.reflect.misc.ReflectUtil; @@ -137,14 +138,14 @@ // entry points, must be covered by hand-written or automatically // generated adapter classes. // + @CallerSensitive public static T asInterfaceInstance(final Class intfc, final MethodHandle target) { if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) throw new IllegalArgumentException("not a public interface: "+intfc.getName()); final MethodHandle mh; if (System.getSecurityManager() != null) { - final int CALLER_FRAME = 2; // 0: Reflection, 1: asInterfaceInstance, 2: caller - final Class caller = Reflection.getCallerClass(CALLER_FRAME); + final Class caller = Reflection.getCallerClass(); final ClassLoader ccl = caller != null ? caller.getClassLoader() : null; ReflectUtil.checkProxyPackageAccess(ccl, intfc); mh = ccl != null ? bindCaller(target, caller) : target; diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/invoke/MethodHandles.java --- a/src/share/classes/java/lang/invoke/MethodHandles.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/invoke/MethodHandles.java Wed Apr 17 01:04:45 2013 -0700 @@ -26,13 +26,17 @@ package java.lang.invoke; import java.lang.reflect.*; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyAccess; import sun.invoke.util.Wrapper; -import java.util.List; -import java.util.ArrayList; -import java.util.Arrays; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; +import sun.security.util.SecurityConstants; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleNatives.Constants.*; @@ -65,8 +69,9 @@ * This lookup object is a capability which may be delegated to trusted agents. * Do not store it in place where untrusted code can access it. */ + @CallerSensitive public static Lookup lookup() { - return new Lookup(); + return new Lookup(Reflection.getCallerClass()); } /** @@ -416,20 +421,13 @@ * for method handle creation. * Must be called by from a method in this package, * which in turn is called by a method not in this package. - *

- * Also, don't make it private, lest javac interpose - * an access$N method. */ - Lookup() { - this(getCallerClassAtEntryPoint(false), ALL_MODES); + Lookup(Class lookupClass) { + this(lookupClass, ALL_MODES); // make sure we haven't accidentally picked up a privileged class: checkUnprivilegedlookupClass(lookupClass); } - Lookup(Class lookupClass) { - this(lookupClass, ALL_MODES); - } - private Lookup(Class lookupClass, int allowedModes) { this.lookupClass = lookupClass; this.allowedModes = allowedModes; @@ -554,20 +552,6 @@ } } - /* Obtain the external caller class, when called from Lookup. or a first-level subroutine. */ - private static Class getCallerClassAtEntryPoint(boolean inSubroutine) { - final int CALLER_DEPTH = 4; - // Stack for the constructor entry point (inSubroutine=false): - // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint, - // 2: Lookup., 3: MethodHandles.*, 4: caller - // The stack is slightly different for a subroutine of a Lookup.find* method: - // 2: Lookup.*, 3: Lookup.find*.*, 4: caller - // Note: This should be the only use of getCallerClass in this file. - assert(Reflection.getCallerClass(CALLER_DEPTH-2) == Lookup.class); - assert(Reflection.getCallerClass(CALLER_DEPTH-1) == (inSubroutine ? Lookup.class : MethodHandles.class)); - return Reflection.getCallerClass(CALLER_DEPTH); - } - /** * Produces a method handle for a static method. * The type of the method handle will be that of the method. @@ -594,12 +578,14 @@ * refuses access * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findStatic(Class refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type); - checkSecurityManager(refc, method); // stack walk magic: do not refactor - Class callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor - return getDirectMethod(REF_invokeStatic, refc, method, callerClass); + Class callerClass = Reflection.getCallerClass(); + checkSecurityManager(refc, method, callerClass); + return getDirectMethod(REF_invokeStatic, refc, method, + findBoundCallerClass(method, callerClass)); } /** @@ -645,6 +631,7 @@ * refuses access * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findVirtual(Class refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { if (refc == MethodHandle.class) { MethodHandle mh = findVirtualForMH(name, type); @@ -652,9 +639,10 @@ } byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual); MemberName method = resolveOrFail(refKind, refc, name, type); - checkSecurityManager(refc, method); // stack walk magic: do not refactor - Class callerClass = findBoundCallerClass(method); - return getDirectMethod(refKind, refc, method, callerClass); + Class callerClass = Reflection.getCallerClass(); + checkSecurityManager(refc, method, callerClass); + return getDirectMethod(refKind, refc, method, + findBoundCallerClass(method, callerClass)); } private MethodHandle findVirtualForMH(String name, MethodType type) { // these names require special lookups because of the implicit MethodType argument @@ -691,10 +679,11 @@ * refuses access * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findConstructor(Class refc, MethodType type) throws NoSuchMethodException, IllegalAccessException { String name = ""; MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type); - checkSecurityManager(refc, ctor); // stack walk magic: do not refactor + checkSecurityManager(refc, ctor, Reflection.getCallerClass()); return getDirectConstructor(refc, ctor); } @@ -732,14 +721,16 @@ * refuses access * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findSpecial(Class refc, String name, MethodType type, Class specialCaller) throws NoSuchMethodException, IllegalAccessException { checkSpecialCaller(specialCaller); Lookup specialLookup = this.in(specialCaller); MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type); - checkSecurityManager(refc, method); // stack walk magic: do not refactor - Class callerClass = findBoundCallerClass(method); - return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, callerClass); + Class callerClass = Reflection.getCallerClass(); + checkSecurityManager(refc, method, callerClass); + return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, + findBoundCallerClass(method, callerClass)); } /** @@ -759,9 +750,10 @@ * refuses access * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findGetter(Class refc, String name, Class type) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(REF_getField, refc, name, type); - checkSecurityManager(refc, field); // stack walk magic: do not refactor + checkSecurityManager(refc, field, Reflection.getCallerClass()); return getDirectField(REF_getField, refc, field); } @@ -782,9 +774,10 @@ * refuses access * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findSetter(Class refc, String name, Class type) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(REF_putField, refc, name, type); - checkSecurityManager(refc, field); // stack walk magic: do not refactor + checkSecurityManager(refc, field, Reflection.getCallerClass()); return getDirectField(REF_putField, refc, field); } @@ -804,9 +797,10 @@ * refuses access * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findStaticGetter(Class refc, String name, Class type) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(REF_getStatic, refc, name, type); - checkSecurityManager(refc, field); // stack walk magic: do not refactor + checkSecurityManager(refc, field, Reflection.getCallerClass()); return getDirectField(REF_getStatic, refc, field); } @@ -826,9 +820,10 @@ * refuses access * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findStaticSetter(Class refc, String name, Class type) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(REF_putStatic, refc, name, type); - checkSecurityManager(refc, field); // stack walk magic: do not refactor + checkSecurityManager(refc, field, Reflection.getCallerClass()); return getDirectField(REF_putStatic, refc, field); } @@ -878,12 +873,14 @@ * refuses access * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { Class refc = receiver.getClass(); // may get NPE MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type); - checkSecurityManager(refc, method); // stack walk magic: do not refactor - Class callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor - MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, callerClass); + Class callerClass = Reflection.getCallerClass(); + checkSecurityManager(refc, method, callerClass); + MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, + findBoundCallerClass(method, callerClass)); return mh.bindReceiver(receiver).setVarargs(method); } @@ -908,13 +905,14 @@ * is set and {@code asVarargsCollector} fails * @throws NullPointerException if the argument is null */ + @CallerSensitive public MethodHandle unreflect(Method m) throws IllegalAccessException { MemberName method = new MemberName(m); byte refKind = method.getReferenceKind(); if (refKind == REF_invokeSpecial) refKind = REF_invokeVirtual; assert(method.isMethod()); - Class callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor + Class callerClass = findBoundCallerClass(method, Reflection.getCallerClass()); Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this; return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, callerClass); } @@ -940,12 +938,13 @@ * is set and {@code asVarargsCollector} fails * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle unreflectSpecial(Method m, Class specialCaller) throws IllegalAccessException { checkSpecialCaller(specialCaller); Lookup specialLookup = this.in(specialCaller); MemberName method = new MemberName(m, true); assert(method.isMethod()); - Class callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor + Class callerClass = findBoundCallerClass(method, Reflection.getCallerClass()); // ignore m.isAccessible: this is a new kind of access return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, callerClass); } @@ -1050,20 +1049,35 @@ * If this lookup object has private access, then the caller class is the lookupClass. * Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual). * This is the same caller class as is used by checkSecurityManager. - * This function performs stack walk magic: do not refactor it. */ - Class findBoundCallerClass(MemberName m) { + Class findBoundCallerClass(MemberName m, Class callerAtEntryPoint) { Class callerClass = null; if (MethodHandleNatives.isCallerSensitive(m)) { // Do not refactor this to a more "logical" place, since it is stack walk magic. // Note that this is the same expression as in Step 2 below in checkSecurityManager. callerClass = ((allowedModes & PRIVATE) != 0 ? lookupClass // for strong access modes, no extra check - // next line does stack walk magic; do not refactor: - : getCallerClassAtEntryPoint(true)); + : callerAtEntryPoint); } return callerClass; } + + /** + * Determine whether a security manager has an overridden + * SecurityManager.checkMemberAccess method. + */ + private boolean isCheckMemberAccessOverridden(SecurityManager sm) { + final Class cls = sm.getClass(); + if (cls == SecurityManager.class) return false; + + try { + return cls.getMethod("checkMemberAccess", Class.class, int.class). + getDeclaringClass() != SecurityManager.class; + } catch (NoSuchMethodException e) { + throw new InternalError("should not reach here"); + } + } + /** * Perform necessary access checks. * Determines a trustable caller class to compare with refc, the symbolic reference class. @@ -1071,46 +1085,55 @@ * Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual). * This function performs stack walk magic: do not refactor it. */ - void checkSecurityManager(Class refc, MemberName m) { + void checkSecurityManager(Class refc, MemberName m, Class caller) { SecurityManager smgr = System.getSecurityManager(); if (smgr == null) return; if (allowedModes == TRUSTED) return; + + final boolean overridden = isCheckMemberAccessOverridden(smgr); // Step 1: - smgr.checkMemberAccess(refc, Member.PUBLIC); + { + // Default policy is to allow Member.PUBLIC; no need to check + // permission if SecurityManager is the default implementation + final int which = Member.PUBLIC; + final Class clazz = refc; + if (overridden) { + // Don't refactor; otherwise break the stack depth for + // checkMemberAccess of subclasses of SecurityManager as specified. + smgr.checkMemberAccess(clazz, which); + } + } + // Step 2: Class callerClass = ((allowedModes & PRIVATE) != 0 ? lookupClass // for strong access modes, no extra check - // next line does stack walk magic; do not refactor: - : getCallerClassAtEntryPoint(true)); + : caller); if (!VerifyAccess.classLoaderIsAncestor(lookupClass, refc) || (callerClass != lookupClass && !VerifyAccess.classLoaderIsAncestor(callerClass, refc))) smgr.checkPackageAccess(VerifyAccess.getPackageName(refc)); + // Step 3: if (m.isPublic()) return; Class defc = m.getDeclaringClass(); - smgr.checkMemberAccess(defc, Member.DECLARED); // STACK WALK HERE + { + // Inline SecurityManager.checkMemberAccess + final int which = Member.DECLARED; + final Class clazz = defc; + if (!overridden) { + if (caller.getClassLoader() != clazz.getClassLoader()) { + smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); + } + } else { + // Don't refactor; otherwise break the stack depth for + // checkMemberAccess of subclasses of SecurityManager as specified. + smgr.checkMemberAccess(clazz, which); + } + } + // Step 4: if (defc != refc) smgr.checkPackageAccess(VerifyAccess.getPackageName(defc)); - - // Comment from SM.checkMemberAccess, where which=DECLARED: - /* - * stack depth of 4 should be the caller of one of the - * methods in java.lang.Class that invoke checkMember - * access. The stack should look like: - * - * someCaller [3] - * java.lang.Class.someReflectionAPI [2] - * java.lang.Class.checkMemberAccess [1] - * SecurityManager.checkMemberAccess [0] - * - */ - // For us it is this stack: - // someCaller [3] - // Lookup.findSomeMember [2] - // Lookup.checkSecurityManager [1] - // SecurityManager.checkMemberAccess [0] } void checkMethod(byte refKind, Class refc, MemberName m) throws IllegalAccessException { diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/reflect/Constructor.java --- a/src/share/classes/java/lang/reflect/Constructor.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/reflect/Constructor.java Wed Apr 17 01:04:45 2013 -0700 @@ -25,6 +25,7 @@ package java.lang.reflect; +import sun.reflect.CallerSensitive; import sun.reflect.ConstructorAccessor; import sun.reflect.Reflection; import sun.reflect.generics.repository.ConstructorRepository; @@ -392,14 +393,14 @@ * @exception ExceptionInInitializerError if the initialization provoked * by this method fails. */ + @CallerSensitive public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(2); - + Class caller = Reflection.getCallerClass(); checkAccess(caller, clazz, null, modifiers); } } diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/reflect/Field.java --- a/src/share/classes/java/lang/reflect/Field.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/reflect/Field.java Wed Apr 17 01:04:45 2013 -0700 @@ -25,6 +25,7 @@ package java.lang.reflect; +import sun.reflect.CallerSensitive; import sun.reflect.FieldAccessor; import sun.reflect.Reflection; import sun.reflect.generics.repository.FieldRepository; @@ -376,9 +377,16 @@ * @exception ExceptionInInitializerError if the initialization provoked * by this method fails. */ + @CallerSensitive public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).get(obj); } @@ -404,9 +412,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public boolean getBoolean(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getBoolean(obj); } @@ -432,9 +447,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public byte getByte(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getByte(obj); } @@ -462,9 +484,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public char getChar(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getChar(obj); } @@ -492,9 +521,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public short getShort(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getShort(obj); } @@ -522,9 +558,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public int getInt(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getInt(obj); } @@ -552,9 +595,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public long getLong(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getLong(obj); } @@ -582,9 +632,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public float getFloat(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getFloat(obj); } @@ -612,9 +669,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public double getDouble(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getDouble(obj); } @@ -684,9 +748,16 @@ * @exception ExceptionInInitializerError if the initialization provoked * by this method fails. */ + @CallerSensitive public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).set(obj, value); } @@ -714,9 +785,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setBoolean(Object obj, boolean z) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setBoolean(obj, z); } @@ -744,9 +822,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setByte(Object obj, byte b) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setByte(obj, b); } @@ -774,9 +859,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setChar(Object obj, char c) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setChar(obj, c); } @@ -804,9 +896,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setShort(Object obj, short s) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setShort(obj, s); } @@ -834,9 +933,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setInt(Object obj, int i) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setInt(obj, i); } @@ -864,9 +970,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setLong(Object obj, long l) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setLong(obj, l); } @@ -894,9 +1007,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setFloat(Object obj, float f) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setFloat(obj, f); } @@ -924,20 +1044,26 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setDouble(Object obj, double d) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setDouble(obj, d); } - // Convenience routine which performs security checks + // security check is done before calling this method private FieldAccessor getFieldAccessor(Object obj) throws IllegalAccessException { - doSecurityCheck(obj); boolean ov = override; - FieldAccessor a = (ov)? overrideFieldAccessor : fieldAccessor; - return (a != null)? a : acquireFieldAccessor(ov); + FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor; + return (a != null) ? a : acquireFieldAccessor(ov); } // NOTE that there is no synchronization used here. It is correct @@ -982,19 +1108,6 @@ } } - // NOTE: be very careful if you change the stack depth of this - // routine. The depth of the "getCallerClass" call is hardwired so - // that the compiler can have an easier time if this gets inlined. - private void doSecurityCheck(Object obj) throws IllegalAccessException { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(4); - - checkAccess(caller, clazz, obj, modifiers); - } - } - } - /** * @throws NullPointerException {@inheritDoc} * @since 1.5 diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/reflect/Method.java --- a/src/share/classes/java/lang/reflect/Method.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/reflect/Method.java Wed Apr 17 01:04:45 2013 -0700 @@ -25,6 +25,7 @@ package java.lang.reflect; +import sun.reflect.CallerSensitive; import sun.reflect.MethodAccessor; import sun.reflect.Reflection; import sun.reflect.generics.repository.MethodRepository; @@ -472,14 +473,14 @@ * @exception ExceptionInInitializerError if the initialization * provoked by this method fails. */ + @CallerSensitive public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(1); - + Class caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } } diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/lang/reflect/Proxy.java --- a/src/share/classes/java/lang/reflect/Proxy.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/lang/reflect/Proxy.java Wed Apr 17 01:04:45 2013 -0700 @@ -39,6 +39,8 @@ import java.util.List; import java.util.WeakHashMap; import sun.misc.ProxyGenerator; +import sun.misc.VM; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants; @@ -408,28 +410,21 @@ * @throws NullPointerException if the {@code interfaces} array * argument or any of its elements are {@code null} */ + @CallerSensitive public static Class getProxyClass(ClassLoader loader, Class... interfaces) throws IllegalArgumentException { - return getProxyClass0(loader, interfaces); // stack walk magic: do not refactor - } - - private static void checkProxyLoader(ClassLoader ccl, - ClassLoader loader) - { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - if (loader == null && ccl != null) { - if (!ProxyAccessHelper.allowNullLoader) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } - } + checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); } + + return getProxyClass0(loader, interfaces); } /* - * Generate a proxy class (caller-sensitive). + * Check permissions required to create a Proxy class. * * To define a proxy class, it performs the access checks as in * Class.forName (VM will invoke ClassLoader.checkPackageAccess): @@ -446,17 +441,28 @@ * will throw IllegalAccessError when the generated proxy class is * being defined via the defineClass0 method. */ - private static Class getProxyClass0(ClassLoader loader, - Class... interfaces) { + private static void checkProxyAccess(Class caller, + ClassLoader loader, + Class... interfaces) + { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - final int CALLER_FRAME = 3; // 0: Reflection, 1: getProxyClass0 2: Proxy 3: caller - final Class caller = Reflection.getCallerClass(CALLER_FRAME); - final ClassLoader ccl = caller.getClassLoader(); - checkProxyLoader(ccl, loader); + ClassLoader ccl = caller.getClassLoader(); + if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) { + if (!ProxyAccessHelper.allowNullLoader) { + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + } ReflectUtil.checkProxyPackageAccess(ccl, interfaces); } + } + /** + * Generate a proxy class. Must call the checkProxyAccess method + * to perform permission checks before calling this. + */ + private static Class getProxyClass0(ClassLoader loader, + Class... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } @@ -698,6 +704,7 @@ * if the invocation handler, {@code h}, is * {@code null} */ + @CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) @@ -707,10 +714,15 @@ throw new NullPointerException(); } + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); + } + /* * Look up or generate the designated proxy class. */ - Class cl = getProxyClass0(loader, interfaces); // stack walk magic: do not refactor + Class cl = getProxyClass0(loader, interfaces); /* * Invoke its constructor with the designated invocation handler. @@ -718,7 +730,6 @@ try { final Constructor cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; - SecurityManager sm = System.getSecurityManager(); if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/security/AccessController.java --- a/src/share/classes/java/security/AccessController.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/security/AccessController.java Wed Apr 17 01:04:45 2013 -0700 @@ -26,6 +26,8 @@ package java.security; import sun.security.util.Debug; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; /** *

The AccessController class is used for access control operations @@ -264,6 +266,7 @@ * @see java.security.DomainCombiner */ + @CallerSensitive public static native T doPrivileged(PrivilegedAction action); /** @@ -288,14 +291,15 @@ * * @since 1.6 */ + @CallerSensitive public static T doPrivilegedWithCombiner(PrivilegedAction action) { - AccessControlContext acc = getStackAccessControlContext(); if (acc == null) { return AccessController.doPrivileged(action); } DomainCombiner dc = acc.getAssignedCombiner(); - return AccessController.doPrivileged(action, preserveCombiner(dc)); + return AccessController.doPrivileged(action, + preserveCombiner(dc, Reflection.getCallerClass())); } @@ -326,6 +330,7 @@ * @see #doPrivileged(PrivilegedAction) * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext) */ + @CallerSensitive public static native T doPrivileged(PrivilegedAction action, AccessControlContext context); @@ -353,6 +358,7 @@ * @see #doPrivilegedWithCombiner(PrivilegedExceptionAction) * @see java.security.DomainCombiner */ + @CallerSensitive public static native T doPrivileged(PrivilegedExceptionAction action) throws PrivilegedActionException; @@ -383,34 +389,29 @@ * * @since 1.6 */ - public static T doPrivilegedWithCombiner - (PrivilegedExceptionAction action) throws PrivilegedActionException { - + @CallerSensitive + public static T doPrivilegedWithCombiner(PrivilegedExceptionAction action) + throws PrivilegedActionException + { AccessControlContext acc = getStackAccessControlContext(); if (acc == null) { return AccessController.doPrivileged(action); } DomainCombiner dc = acc.getAssignedCombiner(); - return AccessController.doPrivileged(action, preserveCombiner(dc)); + return AccessController.doPrivileged(action, + preserveCombiner(dc, Reflection.getCallerClass())); } /** * preserve the combiner across the doPrivileged call */ - private static AccessControlContext preserveCombiner - (DomainCombiner combiner) { - - /** - * callerClass[0] = Reflection.getCallerClass - * callerClass[1] = AccessController.preserveCombiner - * callerClass[2] = AccessController.doPrivileged - * callerClass[3] = caller - */ - final Class callerClass = sun.reflect.Reflection.getCallerClass(3); + private static AccessControlContext preserveCombiner(DomainCombiner combiner, + Class caller) + { ProtectionDomain callerPd = doPrivileged (new PrivilegedAction() { public ProtectionDomain run() { - return callerClass.getProtectionDomain(); + return caller.getProtectionDomain(); } }); @@ -455,6 +456,7 @@ * @see #doPrivileged(PrivilegedAction) * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext) */ + @CallerSensitive public static native T doPrivileged(PrivilegedExceptionAction action, AccessControlContext context) diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/sql/DriverManager.java --- a/src/share/classes/java/sql/DriverManager.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/sql/DriverManager.java Wed Apr 17 01:04:45 2013 -0700 @@ -30,6 +30,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.CopyOnWriteArrayList; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; @@ -192,14 +193,11 @@ * has been exceeded and has at least tried to cancel the * current database connection attempt */ + @CallerSensitive public static Connection getConnection(String url, java.util.Properties info) throws SQLException { - // Gets the classloader of the code that called this method, may - // be null. - ClassLoader callerCL = DriverManager.getCallerClassLoader(); - - return (getConnection(url, info, callerCL)); + return (getConnection(url, info, Reflection.getCallerClass())); } /** @@ -226,14 +224,11 @@ * has been exceeded and has at least tried to cancel the * current database connection attempt */ + @CallerSensitive public static Connection getConnection(String url, String user, String password) throws SQLException { java.util.Properties info = new java.util.Properties(); - // Gets the classloader of the code that called this method, may - // be null. - ClassLoader callerCL = DriverManager.getCallerClassLoader(); - if (user != null) { info.put("user", user); } @@ -241,7 +236,7 @@ info.put("password", password); } - return (getConnection(url, info, callerCL)); + return (getConnection(url, info, Reflection.getCallerClass())); } /** @@ -259,16 +254,12 @@ * has been exceeded and has at least tried to cancel the * current database connection attempt */ + @CallerSensitive public static Connection getConnection(String url) throws SQLException { java.util.Properties info = new java.util.Properties(); - - // Gets the classloader of the code that called this method, may - // be null. - ClassLoader callerCL = DriverManager.getCallerClassLoader(); - - return (getConnection(url, info, callerCL)); + return (getConnection(url, info, Reflection.getCallerClass())); } /** @@ -282,21 +273,20 @@ * that can connect to the given URL * @exception SQLException if a database access error occurs */ + @CallerSensitive public static Driver getDriver(String url) throws SQLException { println("DriverManager.getDriver(\"" + url + "\")"); - // Gets the classloader of the code that called this method, may - // be null. - ClassLoader callerCL = DriverManager.getCallerClassLoader(); + Class callerClass = Reflection.getCallerClass(); // Walk through the loaded registeredDrivers attempting to locate someone // who understands the given URL. for (DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. - if(isDriverAllowed(aDriver.driver, callerCL)) { + if(isDriverAllowed(aDriver.driver, callerClass)) { try { if(aDriver.driver.acceptsURL(url)) { // Success! @@ -350,20 +340,18 @@ * @param driver the JDBC Driver to drop * @exception SQLException if a database access error occurs */ + @CallerSensitive public static synchronized void deregisterDriver(Driver driver) throws SQLException { if (driver == null) { return; } - // Gets the classloader of the code that called this method, - // may be null. - ClassLoader callerCL = DriverManager.getCallerClassLoader(); println("DriverManager.deregisterDriver: " + driver); DriverInfo aDriver = new DriverInfo(driver); if(registeredDrivers.contains(aDriver)) { - if (isDriverAllowed(driver, callerCL)) { + if (isDriverAllowed(driver, Reflection.getCallerClass())) { registeredDrivers.remove(aDriver); } else { // If the caller does not have permission to load the driver then @@ -384,18 +372,17 @@ * * @return the list of JDBC Drivers loaded by the caller's class loader */ + @CallerSensitive public static java.util.Enumeration getDrivers() { java.util.Vector result = new java.util.Vector<>(); - // Gets the classloader of the code that called this method, may - // be null. - ClassLoader callerCL = DriverManager.getCallerClassLoader(); + Class callerClass = Reflection.getCallerClass(); // Walk through the loaded registeredDrivers. for(DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. - if(isDriverAllowed(aDriver.driver, callerCL)) { + if(isDriverAllowed(aDriver.driver, callerClass)) { result.addElement(aDriver.driver); } else { println(" skipping: " + aDriver.getClass().getName()); @@ -493,17 +480,13 @@ //------------------------------------------------------------------------ - // Internal method used to get the caller's class loader. - // Replaces the call to the native method - private static ClassLoader getCallerClassLoader() { - Class cc = Reflection.getCallerClass(3); - ClassLoader cl = (cc != null) ? cc.getClassLoader() : null; - return cl; + // Indicates whether the class object that would be created if the code calling + // DriverManager is accessible. + private static boolean isDriverAllowed(Driver driver, Class caller) { + ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; + return isDriverAllowed(driver, callerCL); } - - // Indicates whether the class object that would be created if the code calling - // DriverManager is accessible. private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) { boolean result = false; if(driver != null) { @@ -586,18 +569,19 @@ // Worker method called by the public getConnection() methods. private static Connection getConnection( - String url, java.util.Properties info, ClassLoader callerCL) throws SQLException { + String url, java.util.Properties info, Class caller) throws SQLException { /* * When callerCl is null, we should check the application's * (which is invoking this class indirectly) * classloader, so that the JDBC driver class outside rt.jar * can be loaded from here. */ + ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; synchronized(DriverManager.class) { - // synchronize loading of the correct classloader. - if(callerCL == null) { - callerCL = Thread.currentThread().getContextClassLoader(); - } + // synchronize loading of the correct classloader. + if (callerCL == null) { + callerCL = Thread.currentThread().getContextClassLoader(); + } } if(url == null) { diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/util/ResourceBundle.java --- a/src/share/classes/java/util/ResourceBundle.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/util/ResourceBundle.java Wed Apr 17 01:04:45 2013 -0700 @@ -57,6 +57,8 @@ import java.util.jar.JarEntry; import java.util.spi.ResourceBundleControlProvider; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; import sun.util.locale.BaseLocale; import sun.util.locale.LocaleObjectCache; @@ -440,14 +442,10 @@ /* * Automatic determination of the ClassLoader to be used to load - * resources on behalf of the client. N.B. The client is getLoader's - * caller's caller. + * resources on behalf of the client. */ - private static ClassLoader getLoader() { - Class[] stack = getClassContext(); - /* Magic number 2 identifies our caller's caller */ - Class c = stack[2]; - ClassLoader cl = (c == null) ? null : c.getClassLoader(); + private static ClassLoader getLoader(Class caller) { + ClassLoader cl = caller == null ? null : caller.getClassLoader(); if (cl == null) { // When the caller's loader is the boot class loader, cl is null // here. In that case, ClassLoader.getSystemClassLoader() may @@ -461,8 +459,6 @@ return cl; } - private static native Class[] getClassContext(); - /** * A wrapper of ClassLoader.getSystemClassLoader(). */ @@ -746,11 +742,11 @@ * if no resource bundle for the specified base name can be found * @return a resource bundle for the given base name and the default locale */ + @CallerSensitive public static final ResourceBundle getBundle(String baseName) { return getBundleImpl(baseName, Locale.getDefault(), - /* must determine loader here, else we break stack invariant */ - getLoader(), + getLoader(Reflection.getCallerClass()), getDefaultControl(baseName)); } @@ -788,11 +784,11 @@ * needed. * @since 1.6 */ + @CallerSensitive public static final ResourceBundle getBundle(String baseName, Control control) { return getBundleImpl(baseName, Locale.getDefault(), - /* must determine loader here, else we break stack invariant */ - getLoader(), + getLoader(Reflection.getCallerClass()), control); } @@ -817,12 +813,12 @@ * if no resource bundle for the specified base name can be found * @return a resource bundle for the given base name and locale */ + @CallerSensitive public static final ResourceBundle getBundle(String baseName, Locale locale) { return getBundleImpl(baseName, locale, - /* must determine loader here, else we break stack invariant */ - getLoader(), + getLoader(Reflection.getCallerClass()), getDefaultControl(baseName)); } @@ -863,11 +859,11 @@ * needed. * @since 1.6 */ + @CallerSensitive public static final ResourceBundle getBundle(String baseName, Locale targetLocale, Control control) { return getBundleImpl(baseName, targetLocale, - /* must determine loader here, else we break stack invariant */ - getLoader(), + getLoader(Reflection.getCallerClass()), control); } @@ -1721,8 +1717,9 @@ * @since 1.6 * @see ResourceBundle.Control#getTimeToLive(String,Locale) */ + @CallerSensitive public static final void clearCache() { - clearCache(getLoader()); + clearCache(getLoader(Reflection.getCallerClass())); } /** diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java --- a/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java Wed Apr 17 01:04:45 2013 -0700 @@ -37,6 +37,9 @@ import java.util.function.IntUnaryOperator; import java.util.function.IntBinaryOperator; import sun.misc.Unsafe; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; + import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.security.AccessController; @@ -77,8 +80,9 @@ * or the field is inaccessible to the caller according to Java language * access control */ + @CallerSensitive public static AtomicIntegerFieldUpdater newUpdater(Class tclass, String fieldName) { - return new AtomicIntegerFieldUpdaterImpl(tclass, fieldName); + return new AtomicIntegerFieldUpdaterImpl(tclass, fieldName, Reflection.getCallerClass()); } /** @@ -365,9 +369,11 @@ private final Class tclass; private final Class cclass; - AtomicIntegerFieldUpdaterImpl(final Class tclass, final String fieldName) { + AtomicIntegerFieldUpdaterImpl(final Class tclass, + final String fieldName, + final Class caller) + { final Field field; - final Class caller; final int modifiers; try { field = AccessController.doPrivileged( @@ -376,7 +382,6 @@ return tclass.getDeclaredField(fieldName); } }); - caller = sun.reflect.Reflection.getCallerClass(3); modifiers = field.getModifiers(); sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers); diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java --- a/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java Wed Apr 17 01:04:45 2013 -0700 @@ -37,6 +37,9 @@ import java.util.function.LongUnaryOperator; import java.util.function.LongBinaryOperator; import sun.misc.Unsafe; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; + import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.security.AccessController; @@ -77,11 +80,13 @@ * or the field is inaccessible to the caller according to Java language * access control */ + @CallerSensitive public static AtomicLongFieldUpdater newUpdater(Class tclass, String fieldName) { + Class caller = Reflection.getCallerClass(); if (AtomicLong.VM_SUPPORTS_LONG_CAS) - return new CASUpdater(tclass, fieldName); + return new CASUpdater(tclass, fieldName, caller); else - return new LockedUpdater(tclass, fieldName); + return new LockedUpdater(tclass, fieldName, caller); } /** @@ -365,9 +370,8 @@ private final Class tclass; private final Class cclass; - CASUpdater(final Class tclass, final String fieldName) { + CASUpdater(final Class tclass, final String fieldName, final Class caller) { final Field field; - final Class caller; final int modifiers; try { field = AccessController.doPrivileged( @@ -376,7 +380,6 @@ return tclass.getDeclaredField(fieldName); } }); - caller = sun.reflect.Reflection.getCallerClass(3); modifiers = field.getModifiers(); sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers); @@ -490,9 +493,8 @@ private final Class tclass; private final Class cclass; - LockedUpdater(final Class tclass, final String fieldName) { + LockedUpdater(final Class tclass, final String fieldName, final Class caller) { Field field = null; - Class caller = null; int modifiers = 0; try { field = AccessController.doPrivileged( @@ -501,7 +503,6 @@ return tclass.getDeclaredField(fieldName); } }); - caller = sun.reflect.Reflection.getCallerClass(3); modifiers = field.getModifiers(); sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers); diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java --- a/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java Wed Apr 17 01:04:45 2013 -0700 @@ -37,6 +37,9 @@ import java.util.function.UnaryOperator; import java.util.function.BinaryOperator; import sun.misc.Unsafe; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; + import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.security.AccessController; @@ -96,10 +99,12 @@ * or the field is inaccessible to the caller according to Java language * access control */ + @CallerSensitive public static AtomicReferenceFieldUpdater newUpdater(Class tclass, Class vclass, String fieldName) { return new AtomicReferenceFieldUpdaterImpl(tclass, vclass, - fieldName); + fieldName, + Reflection.getCallerClass()); } /** @@ -297,10 +302,11 @@ AtomicReferenceFieldUpdaterImpl(final Class tclass, Class vclass, - final String fieldName) { + final String fieldName, + final Class caller) + { final Field field; final Class fieldClass; - final Class caller; final int modifiers; try { field = AccessController.doPrivileged( @@ -309,7 +315,6 @@ return tclass.getDeclaredField(fieldName); } }); - caller = sun.reflect.Reflection.getCallerClass(3); modifiers = field.getModifiers(); sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers); diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/java/util/logging/Logger.java --- a/src/share/classes/java/util/logging/Logger.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/java/util/logging/Logger.java Wed Apr 17 01:04:45 2013 -0700 @@ -36,6 +36,8 @@ import java.util.ResourceBundle; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; /** * A Logger object is used to log messages for a specific @@ -333,13 +335,10 @@ } } - private static Logger demandLogger(String name, String resourceBundleName) { + private static Logger demandLogger(String name, String resourceBundleName, Class caller) { LogManager manager = LogManager.getLogManager(); SecurityManager sm = System.getSecurityManager(); if (sm != null && !SystemLoggerHelper.disableCallerCheck) { - // 0: Reflection 1: Logger.demandLogger 2: Logger.getLogger 3: caller - final int SKIP_FRAMES = 3; - Class caller = sun.reflect.Reflection.getCallerClass(SKIP_FRAMES); if (caller.getClassLoader() == null) { return manager.demandSystemLogger(name, resourceBundleName); } @@ -377,6 +376,7 @@ // Synchronization is not required here. All synchronization for // adding a new Logger object is handled by LogManager.addLogger(). + @CallerSensitive public static Logger getLogger(String name) { // This method is intentionally not a wrapper around a call // to getLogger(name, resourceBundleName). If it were then @@ -388,7 +388,7 @@ // would throw an IllegalArgumentException in the second call // because the wrapper would result in an attempt to replace // the existing "resourceBundleForFoo" with null. - return demandLogger(name, null); + return demandLogger(name, null, Reflection.getCallerClass()); } /** @@ -434,8 +434,9 @@ // Synchronization is not required here. All synchronization for // adding a new Logger object is handled by LogManager.addLogger(). + @CallerSensitive public static Logger getLogger(String name, String resourceBundleName) { - Logger result = demandLogger(name, resourceBundleName); + Logger result = demandLogger(name, resourceBundleName, Reflection.getCallerClass()); // MissingResourceException or IllegalArgumentException can be // thrown by setupResourceInfo(). diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/javax/script/ScriptEngineManager.java --- a/src/share/classes/javax/script/ScriptEngineManager.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/javax/script/ScriptEngineManager.java Wed Apr 17 01:04:45 2013 -0700 @@ -28,6 +28,7 @@ import java.security.*; import java.util.ServiceLoader; import java.util.ServiceConfigurationError; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; @@ -60,9 +61,10 @@ * * @see java.lang.Thread#getContextClassLoader */ + @CallerSensitive public ScriptEngineManager() { ClassLoader ctxtLoader = Thread.currentThread().getContextClassLoader(); - if (canCallerAccessLoader(ctxtLoader)) { + if (canCallerAccessLoader(ctxtLoader, Reflection.getCallerClass())) { if (DEBUG) System.out.println("using " + ctxtLoader); init(ctxtLoader); } else { @@ -419,10 +421,10 @@ /** Global bindings associated with script engines created by this manager. */ private Bindings globalScope; - private boolean canCallerAccessLoader(ClassLoader loader) { + private boolean canCallerAccessLoader(ClassLoader loader, Class caller) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ClassLoader callerLoader = getCallerClassLoader(); + ClassLoader callerLoader = getClassLoader(caller); if (!sun.misc.VM.isSystemDomainLoader(callerLoader)) { if (loader != callerLoader || !isAncestor(loader, callerLoader)) { try { @@ -438,10 +440,9 @@ return true; } - // Note that this code is same as ClassLoader.getCallerClassLoader(). + // Note that this code is same as ClassLoader.getClassLoader(). // But, that method is package private and hence we can't call here. - private ClassLoader getCallerClassLoader() { - Class caller = Reflection.getCallerClass(3); + private ClassLoader getClassLoader(Class caller) { if (caller == null) { return null; } diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/sun/misc/Unsafe.java --- a/src/share/classes/sun/misc/Unsafe.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/sun/misc/Unsafe.java Wed Apr 17 01:04:45 2013 -0700 @@ -28,6 +28,9 @@ import java.security.*; import java.lang.reflect.*; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; + /** * A collection of methods for performing low-level, unsafe operations. @@ -80,9 +83,10 @@ * checkPropertiesAccess method doesn't allow * access to the system properties. */ + @CallerSensitive public static Unsafe getUnsafe() { - Class cc = sun.reflect.Reflection.getCallerClass(2); - if (!VM.isSystemDomainLoader(cc.getClassLoader())) + Class caller = Reflection.getCallerClass(); + if (!VM.isSystemDomainLoader(caller.getClassLoader())) throw new SecurityException("Unsafe"); return theUnsafe; } @@ -817,8 +821,6 @@ ClassLoader loader, ProtectionDomain protectionDomain); - public native Class defineClass(String name, byte[] b, int off, int len); - /** * Define a class but do not make it known to the class loader or system dictionary. *

diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/sun/reflect/CallerSensitive.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/reflect/CallerSensitive.java Wed Apr 17 01:04:45 2013 -0700 @@ -0,0 +1,41 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.reflect; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; + +/** + * A method annotated @CallerSensitive is sensitive to its calling class, + * via {@link sun.reflect.Reflection#getCallerClass Reflection.getCallerClass}, + * or via some equivalent. + * + * @author John R. Rose + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({CONSTRUCTOR, METHOD}) +public @interface CallerSensitive { +} diff -r 414384c3b3eb -r 779ba708fee3 src/share/classes/sun/reflect/Reflection.java --- a/src/share/classes/sun/reflect/Reflection.java Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/classes/sun/reflect/Reflection.java Wed Apr 17 01:04:45 2013 -0700 @@ -51,16 +51,11 @@ methodFilterMap = new HashMap<>(); } - /** Returns the class of the method realFramesToSkip - frames up the stack (zero-based), ignoring frames associated - with java.lang.reflect.Method.invoke() and its implementation. - The first frame is that associated with this method, so - getCallerClass(0) returns the Class object for - sun.reflect.Reflection. Frames associated with - java.lang.reflect.Method.invoke() and its implementation are - completely ignored and do not count toward the number of "real" - frames skipped. */ - public static native Class getCallerClass(int realFramesToSkip); + /** Returns the class of the caller of the method calling this method, + ignoring frames associated with java.lang.reflect.Method.invoke() + and its implementation. */ + @CallerSensitive + public static native Class getCallerClass(); /** Retrieves the access flags written to the class file. For inner classes these flags may differ from those returned by @@ -321,4 +316,27 @@ } return newMembers; } + + /** + * Tests if the given method is caller-sensitive and the declaring class + * is defined by either the bootstrap class loader or extension class loader. + */ + public static boolean isCallerSensitive(Method m) { + final ClassLoader loader = m.getDeclaringClass().getClassLoader(); + if (sun.misc.VM.isSystemDomainLoader(loader) || isExtClassLoader(loader)) { + return m.isAnnotationPresent(CallerSensitive.class); + } + return false; + } + + private static boolean isExtClassLoader(ClassLoader loader) { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + while (cl != null) { + if (cl.getParent() == null && cl == loader) { + return true; + } + cl = cl.getParent(); + } + return false; + } } diff -r 414384c3b3eb -r 779ba708fee3 src/share/javavm/export/jvm.h --- a/src/share/javavm/export/jvm.h Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/javavm/export/jvm.h Wed Apr 17 01:04:45 2013 -0700 @@ -350,16 +350,21 @@ /* * java.lang.Class and java.lang.ClassLoader */ + +#define JVM_DEPTH -1 + /* - * Returns the class in which the code invoking the native method - * belongs. + * Returns the immediate caller class of the native method invoking + * JVM_GetCallerClass. The Method.invoke and other frames due to + * reflection machinery are skipped. * - * Note that in JDK 1.1, native methods did not create a frame. - * In 1.2, they do. Therefore native methods like Class.forName - * can no longer look at the current frame for the caller class. + * The depth parameter must be -1 (JVM_DEPTH). The caller is expected + * to be marked with sun.reflect.CallerSensitive. The JVM will throw + * an error if it is not marked propertly. */ JNIEXPORT jclass JNICALL -JVM_GetCallerClass(JNIEnv *env, int n); +JVM_GetCallerClass(JNIEnv *env, int depth); + /* * Find primitive classes diff -r 414384c3b3eb -r 779ba708fee3 src/share/native/java/lang/ClassLoader.c --- a/src/share/native/java/lang/ClassLoader.c Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/native/java/lang/ClassLoader.c Wed Apr 17 01:04:45 2013 -0700 @@ -492,24 +492,6 @@ (*env)->ReleaseStringUTFChars(env, name, cname); return res; } - -JNIEXPORT jobject JNICALL -Java_java_lang_ClassLoader_getCaller(JNIEnv *env, jclass cls, jint index) -{ - jobjectArray jcallerStack; - int len; - - jcallerStack = JVM_GetClassContext(env); - if ((*env)->ExceptionCheck(env)) { - return NULL; - } - len = (*env)->GetArrayLength(env, jcallerStack); - if (index < len) { - return (*env)->GetObjectArrayElement(env, jcallerStack, index); - } - return NULL; -} - /* * Class: java_lang_ClassLoader_NativeLibrary * Method: findBuiltinLib diff -r 414384c3b3eb -r 779ba708fee3 src/share/native/java/lang/ResourceBundle.c --- a/src/share/native/java/lang/ResourceBundle.c Tue Apr 16 22:28:47 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 1997, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -#include "jni.h" -#include "jvm.h" - -#include "java_util_ResourceBundle.h" - -JNIEXPORT jobjectArray JNICALL -Java_java_util_ResourceBundle_getClassContext(JNIEnv *env, jobject this) -{ - return JVM_GetClassContext(env); -} diff -r 414384c3b3eb -r 779ba708fee3 src/share/native/java/lang/SecurityManager.c --- a/src/share/native/java/lang/SecurityManager.c Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/native/java/lang/SecurityManager.c Wed Apr 17 01:04:45 2013 -0700 @@ -29,7 +29,6 @@ #include "java_lang_SecurityManager.h" #include "java_lang_ClassLoader.h" -#include "java_util_ResourceBundle.h" /* * Make sure a security manager instance is initialized. diff -r 414384c3b3eb -r 779ba708fee3 src/share/native/sun/reflect/Reflection.c --- a/src/share/native/sun/reflect/Reflection.c Tue Apr 16 22:28:47 2013 -0700 +++ b/src/share/native/sun/reflect/Reflection.c Wed Apr 17 01:04:45 2013 -0700 @@ -27,9 +27,9 @@ #include "sun_reflect_Reflection.h" JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass -(JNIEnv *env, jclass unused, jint depth) +(JNIEnv *env, jclass unused) { - return JVM_GetCallerClass(env, depth); + return JVM_GetCallerClass(env, JVM_DEPTH); // JVM_DEPTH is only the expected value } JNIEXPORT jint JNICALL Java_sun_reflect_Reflection_getClassAccessFlags diff -r 414384c3b3eb -r 779ba708fee3 test/Makefile --- a/test/Makefile Tue Apr 16 22:28:47 2013 -0700 +++ b/test/Makefile Wed Apr 17 01:04:45 2013 -0700 @@ -478,7 +478,7 @@ # Stable agentvm testruns (minus items from PROBLEM_LIST) JDK_ALL_TARGETS += jdk_lang JDK_DEFAULT_TARGETS += jdk_lang -jdk_lang: $(call TestDirs, java/lang sun/invoke sun/misc vm) +jdk_lang: $(call TestDirs, java/lang sun/invoke sun/misc sun/reflect vm) $(call RunAgentvmBatch) # Stable othervm testruns (minus items from PROBLEM_LIST) diff -r 414384c3b3eb -r 779ba708fee3 test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java Wed Apr 17 01:04:45 2013 -0700 @@ -0,0 +1,216 @@ +/* + * 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 com.sun.tools.classfile.*; +import com.sun.tools.jdeps.ClassFileReader; +import static com.sun.tools.classfile.ConstantPool.*; +import java.io.File; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; + +/* + * @test + * @bug 8010117 + * @summary Verify if CallerSensitive methods are annotated with + * sun.reflect.CallerSensitive annotation + * @build CallerSensitiveFinder MethodFinder + * @run main/othervm/timeout=900 -mx600m CallerSensitiveFinder + */ +public class CallerSensitiveFinder extends MethodFinder { + private static int numThreads = 3; + private static boolean verbose = false; + public static void main(String[] args) throws Exception { + List classes = new ArrayList<>(); + String testclasses = System.getProperty("test.classes", "."); + int i = 0; + while (i < args.length) { + String arg = args[i++]; + if (arg.equals("-v")) { + verbose = true; + } else { + Path p = Paths.get(testclasses, arg); + if (!p.toFile().exists()) { + throw new IllegalArgumentException(arg + " does not exist"); + } + classes.add(p); + } + } + if (classes.isEmpty()) { + classes.addAll(PlatformClassPath.getJREClasses()); + } + final String method = "sun/reflect/Reflection.getCallerClass"; + CallerSensitiveFinder csfinder = new CallerSensitiveFinder(method); + + List errors = csfinder.run(classes); + if (!errors.isEmpty()) { + throw new RuntimeException(errors.size() + + " caller-sensitive methods are missing @CallerSensitive annotation"); + } + } + + private final List csMethodsMissingAnnotation = new ArrayList<>(); + public CallerSensitiveFinder(String... methods) { + super(methods); + } + + public List run(List classes) throws IOException, InterruptedException, + ExecutionException, ConstantPoolException + { + ExecutorService pool = Executors.newFixedThreadPool(numThreads); + for (Path path : classes) { + ClassFileReader reader = ClassFileReader.newInstance(path.toFile()); + for (ClassFile cf : reader.getClassFiles()) { + String classFileName = cf.getName(); + // for each ClassFile + // parse constant pool to find matching method refs + // parse each method (caller) + // - visit and find method references matching the given method name + pool.submit(getTask(cf)); + } + } + waitForCompletion(); + pool.shutdown(); + return csMethodsMissingAnnotation; + } + + private static final String CALLER_SENSITIVE_ANNOTATION = "Lsun/reflect/CallerSensitive;"; + private static boolean isCallerSensitive(Method m, ConstantPool cp) + throws ConstantPoolException + { + RuntimeAnnotations_attribute attr = + (RuntimeAnnotations_attribute)m.attributes.get(Attribute.RuntimeVisibleAnnotations); + int index = 0; + if (attr != null) { + for (int i = 0; i < attr.annotations.length; i++) { + Annotation ann = attr.annotations[i]; + String annType = cp.getUTF8Value(ann.type_index); + if (CALLER_SENSITIVE_ANNOTATION.equals(annType)) { + return true; + } + } + } + return false; + } + + public void referenceFound(ClassFile cf, Method m, Set refs) + throws ConstantPoolException + { + String name = String.format("%s#%s %s", cf.getName(), + m.getName(cf.constant_pool), + m.descriptor.getValue(cf.constant_pool)); + if (!CallerSensitiveFinder.isCallerSensitive(m, cf.constant_pool)) { + csMethodsMissingAnnotation.add(name); + System.err.println("Missing @CallerSensitive: " + name); + } else { + if (verbose) { + System.out.format("@CS %s%n", name); + } + } + } + + private final List> tasks = new ArrayList>(); + private FutureTask getTask(final ClassFile cf) { + FutureTask task = new FutureTask(new Callable() { + public String call() throws Exception { + return parse(cf); + } + }); + tasks.add(task); + return task; + } + + private void waitForCompletion() throws InterruptedException, ExecutionException { + for (FutureTask t : tasks) { + String s = t.get(); + } + System.out.println("Parsed " + tasks.size() + " classfiles"); + } + + static class PlatformClassPath { + static List getJREClasses() throws IOException { + List result = new ArrayList(); + Path home = Paths.get(System.getProperty("java.home")); + + if (home.endsWith("jre")) { + // jar files in /jre/lib + // skip /lib + result.addAll(addJarFiles(home.resolve("lib"))); + } else if (home.resolve("lib").toFile().exists()) { + // either a JRE or a jdk build image + File classes = home.resolve("classes").toFile(); + if (classes.exists() && classes.isDirectory()) { + // jdk build outputdir + result.add(classes.toPath()); + } + // add other JAR files + result.addAll(addJarFiles(home.resolve("lib"))); + } else { + throw new RuntimeException("\"" + home + "\" not a JDK home"); + } + return result; + } + + static List addJarFiles(final Path root) throws IOException { + final List result = new ArrayList(); + final Path ext = root.resolve("ext"); + Files.walkFileTree(root, new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) + throws IOException { + if (dir.equals(root) || dir.equals(ext)) { + return FileVisitResult.CONTINUE; + } else { + // skip other cobundled JAR files + return FileVisitResult.SKIP_SUBTREE; + } + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + File f = file.toFile(); + String fn = f.getName(); + // parse alt-rt.jar as well + if (fn.endsWith(".jar") && !fn.equals("jfxrt.jar")) { + result.add(file); + } + return FileVisitResult.CONTINUE; + } + }); + return result; + } + } +} diff -r 414384c3b3eb -r 779ba708fee3 test/sun/reflect/CallerSensitive/MethodFinder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/reflect/CallerSensitive/MethodFinder.java Wed Apr 17 01:04:45 2013 -0700 @@ -0,0 +1,201 @@ +/* + * 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.util.*; +import com.sun.tools.classfile.*; +import static com.sun.tools.classfile.ConstantPool.*; +import com.sun.tools.classfile.Instruction.TypeKind; + +/** + * MethodFinder utility class to find references to the given methods. + */ +public abstract class MethodFinder { + final List methods; + public MethodFinder(String... methods) { + this.methods = Arrays.asList(methods); + } + + /** + * A callback method will be invoked when a method referencing + * any of the lookup methods. + * + * @param cf ClassFile + * @param m Method + * @param refs Set of constant pool indices that reference the methods + * matching the given lookup method names + */ + public abstract void referenceFound(ClassFile cf, Method m, Set refs) + throws ConstantPoolException; + + public String parse(ClassFile cf) throws ConstantPoolException { + List cprefs = new ArrayList(); + int index = 1; + for (ConstantPool.CPInfo cpInfo : cf.constant_pool.entries()) { + if (cpInfo.accept(cpVisitor, null)) { + cprefs.add(index); + } + index += cpInfo.size(); + } + + if (!cprefs.isEmpty()) { + for (Method m : cf.methods) { + Set refs = new HashSet(); + Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code); + if (c_attr != null) { + for (Instruction instr : c_attr.getInstructions()) { + int idx = instr.accept(codeVisitor, cprefs); + if (idx > 0) { + refs.add(idx); + } + } + } + if (refs.size() > 0) { + referenceFound(cf, m, refs); + } + } + } + return cprefs.isEmpty() ? "" : cf.getName(); + } + + private ConstantPool.Visitor cpVisitor = + new ConstantPool.Visitor() + { + private boolean matches(CPRefInfo info) { + try { + CONSTANT_NameAndType_info nat = info.getNameAndTypeInfo(); + return matches(info.getClassName(), nat.getName(), nat.getType()); + } catch (ConstantPoolException ex) { + return false; + } + } + + private boolean matches(String cn, String name, String type) { + return methods.contains(cn + "." + name); + } + + public Boolean visitClass(CONSTANT_Class_info info, Void p) { + return false; + } + + public Boolean visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) { + return matches(info); + } + + public Boolean visitMethodref(CONSTANT_Methodref_info info, Void p) { + return matches(info); + } + + public Boolean visitDouble(CONSTANT_Double_info info, Void p) { + return false; + } + + public Boolean visitFieldref(CONSTANT_Fieldref_info info, Void p) { + return false; + } + + public Boolean visitFloat(CONSTANT_Float_info info, Void p) { + return false; + } + + public Boolean visitInteger(CONSTANT_Integer_info info, Void p) { + return false; + } + + public Boolean visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Void p) { + return false; + } + + public Boolean visitLong(CONSTANT_Long_info info, Void p) { + return false; + } + + public Boolean visitNameAndType(CONSTANT_NameAndType_info info, Void p) { + return false; + } + + public Boolean visitMethodHandle(CONSTANT_MethodHandle_info info, Void p) { + return false; + } + + public Boolean visitMethodType(CONSTANT_MethodType_info info, Void p) { + return false; + } + + public Boolean visitString(CONSTANT_String_info info, Void p) { + return false; + } + + public Boolean visitUtf8(CONSTANT_Utf8_info info, Void p) { + return false; + } + }; + + private Instruction.KindVisitor> codeVisitor = + new Instruction.KindVisitor>() + { + public Integer visitNoOperands(Instruction instr, List p) { + return 0; + } + + public Integer visitArrayType(Instruction instr, TypeKind kind, List p) { + return 0; + } + + public Integer visitBranch(Instruction instr, int offset, List p) { + return 0; + } + + public Integer visitConstantPoolRef(Instruction instr, int index, List p) { + return p.contains(index) ? index : 0; + } + + public Integer visitConstantPoolRefAndValue(Instruction instr, int index, int value, List p) { + return p.contains(index) ? index : 0; + } + + public Integer visitLocal(Instruction instr, int index, List p) { + return 0; + } + + public Integer visitLocalAndValue(Instruction instr, int index, int value, List p) { + return 0; + } + + public Integer visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, List p) { + return 0; + } + + public Integer visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, List p) { + return 0; + } + + public Integer visitValue(Instruction instr, int value, List p) { + return 0; + } + + public Integer visitUnknown(Instruction instr, List p) { + return 0; + } + }; +} + diff -r 414384c3b3eb -r 779ba708fee3 test/sun/reflect/CallerSensitive/MissingCallerSensitive.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java Wed Apr 17 01:04:45 2013 -0700 @@ -0,0 +1,65 @@ +/* + * 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. + */ + + +/* + * @test + * @bug 8010117 + * @summary Test CallerSensitiveFinder to find missing annotation + * @compile -XDignore.symbol.file MissingCallerSensitive.java + * @build CallerSensitiveFinder MethodFinder + * @run main MissingCallerSensitive + */ + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +public class MissingCallerSensitive { + public static void main(String[] args) throws Exception { + String testclasses = System.getProperty("test.classes", "."); + List classes = new ArrayList<>(); + classes.add(Paths.get(testclasses, "MissingCallerSensitive.class")); + + final String method = "sun/reflect/Reflection.getCallerClass"; + CallerSensitiveFinder csfinder = new CallerSensitiveFinder(method); + List errors = csfinder.run(classes); + if (errors.size() != 1) { + throw new RuntimeException("Unexpected number of methods found: " + errors.size()); + } + String m = errors.get(0); + if (!m.startsWith("MissingCallerSensitive#missingCallerSensitiveAnnotation")) { + throw new RuntimeException("Unexpected method missing annotation: " + m); + } + } + + @sun.reflect.CallerSensitive + public ClassLoader getCallerLoader() { + Class c = sun.reflect.Reflection.getCallerClass(); + return c.getClassLoader(); + } + + public ClassLoader missingCallerSensitiveAnnotation() { + Class c = sun.reflect.Reflection.getCallerClass(); + return c.getClassLoader(); + } +} diff -r 414384c3b3eb -r 779ba708fee3 test/sun/reflect/Reflection/GetCallerClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/reflect/Reflection/GetCallerClass.java Wed Apr 17 01:04:45 2013 -0700 @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package boot; + +public class GetCallerClass { + @sun.reflect.CallerSensitive + public ClassLoader getCallerLoader() { + Class c = sun.reflect.Reflection.getCallerClass(); + return c.getClassLoader(); + } + + public ClassLoader missingCallerSensitiveAnnotation() { + Class c = sun.reflect.Reflection.getCallerClass(); + return c.getClassLoader(); + } +} diff -r 414384c3b3eb -r 779ba708fee3 test/sun/reflect/Reflection/GetCallerClassTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/reflect/Reflection/GetCallerClassTest.java Wed Apr 17 01:04:45 2013 -0700 @@ -0,0 +1,113 @@ +/* + * 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 boot.GetCallerClass; +import java.lang.reflect.*; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; + +public class GetCallerClassTest { + private final GetCallerClass gcc; // boot.GetCallerClass is in bootclasspath + GetCallerClassTest() { + this.gcc = new GetCallerClass(); + } + + public static void main(String[] args) throws Exception { + GetCallerClassTest gcct = new GetCallerClassTest(); + // ensure methods are annotated with @CallerSensitive + ensureAnnotationPresent(boot.GetCallerClass.class, "getCallerLoader", true); + ensureAnnotationPresent(GetCallerClassTest.class, "testNonSystemMethod", false); + // call Reflection.getCallerClass from bootclasspath with and without @CS + gcct.testCallerSensitiveMethods(); + // call Reflection.getCallerClass from classpath with @CS + gcct.testNonSystemMethod(); + } + + private static void ensureAnnotationPresent(Class c, String name, boolean cs) + throws NoSuchMethodException + { + Method m = c.getDeclaredMethod(name); + if (!m.isAnnotationPresent(CallerSensitive.class)) { + throw new RuntimeException("@CallerSensitive not present in method " + m); + } + if (Reflection.isCallerSensitive(m) != cs) { + throw new RuntimeException("Unexpected: isCallerSensitive returns " + + Reflection.isCallerSensitive(m)); + } + } + + private void testCallerSensitiveMethods() { + try { + ClassLoader cl = gcc.getCallerLoader(); + if (cl != GetCallerClassTest.class.getClassLoader()) { + throw new RuntimeException("mismatched class loader"); + } + gcc.missingCallerSensitiveAnnotation(); + throw new RuntimeException("getCallerLoader not marked with @CallerSensitive"); + } catch (InternalError e) { + StackTraceElement[] stackTrace = e.getStackTrace(); + checkStackTrace(stackTrace, e); + if (!stackTrace[1].getClassName().equals(GetCallerClass.class.getName()) || + !stackTrace[1].getMethodName().equals("missingCallerSensitiveAnnotation")) { + throw new RuntimeException("Unexpected error: " + e.getMessage(), e); + } + if (!stackTrace[2].getClassName().equals(GetCallerClassTest.class.getName()) || + !stackTrace[2].getMethodName().equals("testCallerSensitiveMethods")) { + throw new RuntimeException("Unexpected error: " + e.getMessage(), e); + } + System.out.println("Expected error: " + e.getMessage()); + } + } + + @CallerSensitive + private void testNonSystemMethod() { + try { + Class c = Reflection.getCallerClass(); + throw new RuntimeException("@CallerSensitive testNonSystemMethods not supported"); + } catch (InternalError e) { + StackTraceElement[] stackTrace = e.getStackTrace(); + checkStackTrace(stackTrace, e); + if (!stackTrace[1].getClassName().equals(GetCallerClassTest.class.getName()) || + !stackTrace[1].getMethodName().equals("testNonSystemMethod")) { + throw new RuntimeException("Unexpected error: " + e.getMessage(), e); + } + if (!stackTrace[2].getClassName().equals(GetCallerClassTest.class.getName()) || + !stackTrace[2].getMethodName().equals("main")) { + throw new RuntimeException("Unexpected error: " + e.getMessage(), e); + } + System.out.println("Expected error: " + e.getMessage()); + } + } + + private void checkStackTrace(StackTraceElement[] stackTrace, Error e) { + if (stackTrace.length < 3) { + throw new RuntimeException("Unexpected error: " + e.getMessage(), e); + } + + if (!stackTrace[0].getClassName().equals("sun.reflect.Reflection") || + !stackTrace[0].getMethodName().equals("getCallerClass")) { + throw new RuntimeException("Unexpected error: " + e.getMessage(), e); + } + + } +} diff -r 414384c3b3eb -r 779ba708fee3 test/sun/reflect/Reflection/GetCallerClassTest.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/reflect/Reflection/GetCallerClassTest.sh Wed Apr 17 01:04:45 2013 -0700 @@ -0,0 +1,68 @@ +# +# 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. +# + +# @test +# @bug 8010117 +# @summary Test if the VM enforces sun.reflect.Reflection.getCallerClass +# be called by methods annotated with sun.reflect.CallerSensitive +# +# @run shell GetCallerClassTest.sh + +if [ "${TESTSRC}" = "" ] +then + echo "TESTSRC not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTSRC=${TESTSRC}" +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +BCP=${TESTCLASSES}/bcp +rm -rf ${BCP} +mkdir ${BCP} + +# Compile GetCallerClass in bootclasspath +${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} \ + -XDignore.symbol.file \ + -d ${BCP} ${TESTSRC}/GetCallerClass.java || exit 1 + +${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} \ + -XDignore.symbol.file -Xbootclasspath/a:${BCP} \ + -d ${TESTCLASSES} ${TESTSRC}/GetCallerClassTest.java || exit 2 + +${TESTJAVA}/bin/java ${TESTVMOPTS} -Xbootclasspath/a:${BCP} \ + -cp ${TESTCLASSES} GetCallerClassTest || exit 3