changeset 20534:da86f7904e6d

8025112: JSR 292 spec updates for security manager and caller sensitivity Summary: align CONSTANT_MethodHandle and Lookup.find* API calls, clarify security manager & @CallerSensitive interactions Reviewed-by: mchung, twisti
author jrose
date Sat, 05 Oct 2013 05:30:39 -0700
parents bee974bc42ac
children cc85c8626435
files jdk/src/share/classes/java/lang/invoke/MethodHandle.java jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java jdk/src/share/classes/java/lang/invoke/MethodHandles.java jdk/test/java/lang/invoke/TestPrivateMember.java
diffstat 6 files changed, 169 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java	Sat Oct 05 05:30:39 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java	Sat Oct 05 05:30:39 2013 -0700
@@ -1331,6 +1331,11 @@
     }
 
     /*non-public*/
+    Class<?> internalCallerClass() {
+        return null;  // caller-bound MH for @CallerSensitive method returns caller
+    }
+
+    /*non-public*/
     MethodHandle withInternalMemberName(MemberName member) {
         if (member != null) {
             return MethodHandleImpl.makeWrappedMember(this, member);
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Sat Oct 05 05:30:39 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Sat Oct 05 05:30:39 2013 -0700
@@ -381,6 +381,10 @@
         MemberName internalMemberName() {
             return asFixedArity().internalMemberName();
         }
+        @Override
+        Class<?> internalCallerClass() {
+            return asFixedArity().internalCallerClass();
+        }
 
         /*non-public*/
         @Override
@@ -831,7 +835,7 @@
             MethodHandle vamh = prepareForInvoker(mh);
             // Cache the result of makeInjectedInvoker once per argument class.
             MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
-            return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName());
+            return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass);
         }
 
         private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
@@ -886,10 +890,12 @@
         }
 
         // Undo the adapter effect of prepareForInvoker:
-        private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, MemberName member) {
+        private static MethodHandle restoreToType(MethodHandle vamh, MethodType type,
+                                                  MemberName member,
+                                                  Class<?> hostClass) {
             MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
             mh = mh.asType(type);
-            mh = mh.withInternalMemberName(member);
+            mh = new WrappedMember(mh, type, member, hostClass);
             return mh;
         }
 
@@ -958,11 +964,13 @@
     static class WrappedMember extends MethodHandle {
         private final MethodHandle target;
         private final MemberName member;
+        private final Class<?> callerClass;
 
-        private WrappedMember(MethodHandle target, MethodType type, MemberName member) {
+        private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class<?> callerClass) {
             super(type, reinvokerForm(target));
             this.target = target;
             this.member = member;
+            this.callerClass = callerClass;
         }
 
         @Override
@@ -980,19 +988,23 @@
             return member;
         }
         @Override
+        Class<?> internalCallerClass() {
+            return callerClass;
+        }
+        @Override
         boolean isInvokeSpecial() {
             return target.isInvokeSpecial();
         }
         @Override
         MethodHandle viewAsType(MethodType newType) {
-            return new WrappedMember(target, newType, member);
+            return new WrappedMember(target, newType, member, callerClass);
         }
     }
 
     static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
         if (member.equals(target.internalMemberName()))
             return target;
-        return new WrappedMember(target, target.type(), member);
+        return new WrappedMember(target, target.type(), member, null);
     }
 
 }
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java	Sat Oct 05 05:30:39 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java	Sat Oct 05 05:30:39 2013 -0700
@@ -61,6 +61,18 @@
  * Cracking must be done via a {@code Lookup} object equivalent to that which created
  * the target method handle, or which has enough access permissions to recreate
  * an equivalent method handle.
+ * <p>
+ * If the underlying method is <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a>,
+ * the direct method handle will have been "bound" to a particular caller class, the
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#lookupClass() lookup class}
+ * of the lookup object used to create it.
+ * Cracking this method handle with a different lookup class will fail
+ * even if the underlying method is public (like {@code Class.forName}).
+ * <p>
+ * The requirement of lookup object matching provides a "fast fail" behavior
+ * for programs which may otherwise trust erroneous revelation of a method
+ * handle with symbolic information (or caller binding) from an unexpected scope.
+ * Use {@link java.lang.invoke.MethodHandles#reflectAs} to override this limitation.
  *
  * <h1><a name="refkinds"></a>Reference kinds</h1>
  * The <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java	Sat Oct 05 05:30:39 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java	Sat Oct 05 05:30:39 2013 -0700
@@ -107,6 +107,11 @@
      * such as abstract classes with single abstract methods.
      * Future versions of this API may also equip wrapper instances
      * with one or more additional public "marker" interfaces.
+     * <p>
+     * If a security manager is installed, this method is caller sensitive.
+     * During any invocation of the target method handle via the returned wrapper,
+     * the original creator of the wrapper (the caller) will be visible
+     * to context checks requested by the security manager.
      *
      * @param <T> the desired type of the wrapper, a single-method interface
      * @param intfc a class object representing {@code T}
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Sat Oct 05 05:30:39 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Sat Oct 05 05:30:39 2013 -0700
@@ -90,6 +90,10 @@
      * {@linkplain Lookup#in <code>publicLookup().in(C.class)</code>}.
      * Since all classes have equal access to public names,
      * such a change would confer no new access rights.
+     * A public lookup object is always subject to
+     * <a href="MethodHandles.Lookup.html#secmgr">security manager checks</a>.
+     * Also, it cannot access
+     * <a href="MethodHandles.Lookup.html#callsens">caller sensitive methods</a>.
      * @return a lookup object which is trusted minimally
      */
     public static Lookup publicLookup() {
@@ -242,9 +246,9 @@
      * For example, lookups for {@code MethodHandle.invokeExact} and
      * {@code MethodHandle.invoke} will always succeed, regardless of requested type.
      * <li>If there is a security manager installed, it can forbid the lookup
-     * on various grounds (<a href="#secmgr">see below</a>).
-     * By contrast, the {@code ldc} instruction is not subject to
-     * security manager checks.
+     * on various grounds (<a href="MethodHandles.Lookup.html#secmgr">see below</a>).
+     * By contrast, the {@code ldc} instruction on a {@code CONSTANT_MethodHandle}
+     * constant is not subject to security manager checks.
      * <li>If the looked-up method has a
      * <a href="MethodHandle.html#maxarity">very large arity</a>,
      * the method handle creation may fail, due to the method handle
@@ -374,13 +378,42 @@
      *     {@link SecurityManager#checkPermission smgr.checkPermission}
      *     with {@code RuntimePermission("accessDeclaredMembers")} is called.
      * <li>If the retrieved member is not public,
+     *     and if {@code lookc} is not present,
      *     and if {@code defc} and {@code refc} are different,
      *     then {@link SecurityManager#checkPackageAccess
      *     smgr.checkPackageAccess(defcPkg)} is called,
      *     where {@code defcPkg} is the package of {@code defc}.
      * </ul>
+     * Security checks are performed after other access checks have passed.
+     * Therefore, the above rules presuppose a member that is public,
+     * or else that is being accessed from a lookup class that has
+     * rights to access the member.
+     *
+     * <h1><a name="callsens"></a>Caller sensitive methods</h1>
+     * A small number of Java methods have a special property called caller sensitivity.
+     * A <em>caller-sensitive</em> method can behave differently depending on the
+     * identity of its immediate caller.
+     * <p>
+     * If a method handle for a caller-sensitive method is requested,
+     * the general rules for <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> apply,
+     * but they take account of the lookup class in a special way.
+     * The resulting method handle behaves as if it were called
+     * from an instruction contained in the lookup class,
+     * so that the caller-sensitive method detects the lookup class.
+     * (By contrast, the invoker of the method handle is disregarded.)
+     * Thus, in the case of caller-sensitive methods,
+     * different lookup classes may give rise to
+     * differently behaving method handles.
+     * <p>
+     * In cases where the lookup object is
+     * {@link MethodHandles#publicLookup() publicLookup()},
+     * or some other lookup object without
+     * {@linkplain java.lang.invoke.MethodHandles.Lookup#PRIVATE private access},
+     * the lookup class is disregarded.
+     * In such cases, no caller-sensitive method handle can be created,
+     * access is forbidden, and the lookup fails with an
+     * {@code IllegalAccessException}.
      */
-    // FIXME in MR1: clarify that the bytecode behavior of a caller-ID method (like Class.forName) is relative to the lookupClass used to create the method handle, not the dynamic caller of the method handle
     public static final
     class Lookup {
         /** The class on behalf of whom the lookup is being performed. */
@@ -639,7 +672,6 @@
         public
         MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
-            checkSecurityManager(refc, method);
             return getDirectMethod(REF_invokeStatic, refc, method, findBoundCallerClass(method));
         }
 
@@ -721,7 +753,6 @@
             }
             byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
             MemberName method = resolveOrFail(refKind, refc, name, type);
-            checkSecurityManager(refc, method);
             return getDirectMethod(refKind, refc, method, findBoundCallerClass(method));
         }
         private MethodHandle findVirtualForMH(String name, MethodType type) {
@@ -782,7 +813,6 @@
         public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             String name = "<init>";
             MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
-            checkSecurityManager(refc, ctor);
             return getDirectConstructor(refc, ctor);
         }
 
@@ -864,7 +894,6 @@
             checkSpecialCaller(specialCaller);
             Lookup specialLookup = this.in(specialCaller);
             MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
-            checkSecurityManager(refc, method);
             return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
         }
 
@@ -887,7 +916,6 @@
          */
         public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             MemberName field = resolveOrFail(REF_getField, refc, name, type);
-            checkSecurityManager(refc, field);
             return getDirectField(REF_getField, refc, field);
         }
 
@@ -910,7 +938,6 @@
          */
         public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             MemberName field = resolveOrFail(REF_putField, refc, name, type);
-            checkSecurityManager(refc, field);
             return getDirectField(REF_putField, refc, field);
         }
 
@@ -935,7 +962,6 @@
          */
         public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             MemberName field = resolveOrFail(REF_getStatic, refc, name, type);
-            checkSecurityManager(refc, field);
             return getDirectField(REF_getStatic, refc, field);
         }
 
@@ -960,7 +986,6 @@
          */
         public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             MemberName field = resolveOrFail(REF_putStatic, refc, name, type);
-            checkSecurityManager(refc, field);
             return getDirectField(REF_putStatic, refc, field);
         }
 
@@ -1013,7 +1038,6 @@
         public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             Class<? extends Object> refc = receiver.getClass(); // may get NPE
             MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
-            checkSecurityManager(refc, method);
             MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
             return mh.bindReceiver(receiver).setVarargs(method);
         }
@@ -1054,7 +1078,7 @@
                 refKind = REF_invokeVirtual;
             assert(method.isMethod());
             Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
-            return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
+            return lookup.getDirectMethodNoSecurityManager(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
         }
         private MethodHandle unreflectForMH(Method m) {
             // these names require special lookups because they throw UnsupportedOperationException
@@ -1090,7 +1114,7 @@
             MemberName method = new MemberName(m, true);
             assert(method.isMethod());
             // ignore m.isAccessible:  this is a new kind of access
-            return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, findBoundCallerClass(method));
+            return specialLookup.getDirectMethodNoSecurityManager(REF_invokeSpecial, method.getDeclaringClass(), method, findBoundCallerClass(method));
         }
 
         /**
@@ -1122,7 +1146,7 @@
             MemberName ctor = new MemberName(c);
             assert(ctor.isConstructor());
             Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
-            return lookup.getDirectConstructor(ctor.getDeclaringClass(), ctor);
+            return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor);
         }
 
         /**
@@ -1152,7 +1176,7 @@
                     ? MethodHandleNatives.refKindIsSetter(field.getReferenceKind())
                     : MethodHandleNatives.refKindIsGetter(field.getReferenceKind()));
             Lookup lookup = f.isAccessible() ? IMPL_LOOKUP : this;
-            return lookup.getDirectField(field.getReferenceKind(), f.getDeclaringClass(), field);
+            return lookup.getDirectFieldNoSecurityManager(field.getReferenceKind(), f.getDeclaringClass(), field);
         }
 
         /**
@@ -1183,6 +1207,8 @@
          * is capable of reproducing the target method handle.
          * This means that the cracking may fail if target is a direct method handle
          * but was created by an unrelated lookup object.
+         * This can happen if the method handle is <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a>
+         * and was created by a lookup object for a different class.
          * @param target a direct method handle to crack into symbolic reference components
          * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
          * @exception SecurityException if a security manager is present and it
@@ -1208,11 +1234,16 @@
                 refKind = REF_invokeInterface;
             // Check SM permissions and member access before cracking.
             try {
+                checkAccess(refKind, defc, member);
                 checkSecurityManager(defc, member);
-                checkAccess(refKind, defc, member);
             } catch (IllegalAccessException ex) {
                 throw new IllegalArgumentException(ex);
             }
+            if (allowedModes != TRUSTED && member.isCallerSensitive()) {
+                Class<?> callerClass = target.internalCallerClass();
+                if (!hasPrivateAccess() || callerClass != lookupClass())
+                    throw new IllegalArgumentException("method handle is caller sensitive: "+callerClass);
+            }
             // Produce the handle to the results.
             return new InfoFromMemberName(this, member, refKind);
         }
@@ -1266,8 +1297,8 @@
         Class<?> findBoundCallerClass(MemberName m) throws IllegalAccessException {
             Class<?> callerClass = null;
             if (MethodHandleNatives.isCallerSensitive(m)) {
-                // Only full-power lookup is allowed to resolve caller-sensitive methods
-                if (isFullPowerLookup()) {
+                // Only lookups with private access are allowed to resolve caller-sensitive methods
+                if (hasPrivateAccess()) {
                     callerClass = lookupClass;
                 } else {
                     throw new IllegalAccessException("Attempt to lookup caller-sensitive method using restricted lookup object");
@@ -1276,7 +1307,7 @@
             return callerClass;
         }
 
-        private boolean isFullPowerLookup() {
+        private boolean hasPrivateAccess() {
             return (allowedModes & PRIVATE) != 0;
         }
 
@@ -1291,22 +1322,21 @@
             if (allowedModes == TRUSTED)  return;
 
             // Step 1:
-            if (!isFullPowerLookup() ||
+            boolean fullPowerLookup = hasPrivateAccess();
+            if (!fullPowerLookup ||
                 !VerifyAccess.classLoaderIsAncestor(lookupClass, refc)) {
                 ReflectUtil.checkPackageAccess(refc);
             }
 
             // Step 2:
             if (m.isPublic()) return;
-            Class<?> defc = m.getDeclaringClass();
-            {
-                if (!isFullPowerLookup()) {
-                    smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
-                }
+            if (!fullPowerLookup) {
+                smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
             }
 
             // Step 3:
-            if (defc != refc) {
+            Class<?> defc = m.getDeclaringClass();
+            if (!fullPowerLookup && defc != refc) {
                 ReflectUtil.checkPackageAccess(defc);
             }
         }
@@ -1335,6 +1365,7 @@
             throw m.makeAccessException(message, this);
         }
 
+        /** Check public/protected/private bits on the symbolic reference class and its member. */
         void checkAccess(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
             assert(m.referenceKindIsConsistentWith(refKind) &&
                    MethodHandleNatives.refKindIsValid(refKind) &&
@@ -1409,7 +1440,7 @@
         private void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException {
             int allowedModes = this.allowedModes;
             if (allowedModes == TRUSTED)  return;
-            if ((allowedModes & PRIVATE) == 0
+            if (!hasPrivateAccess()
                 || (specialCaller != lookupClass()
                     && !(ALLOW_NESTMATE_ACCESS &&
                          VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))))
@@ -1441,18 +1472,32 @@
             return mh.viewAsType(narrowType);
         }
 
+        /** Check access and get the requested method. */
         private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
-            return getDirectMethodCommon(refKind, refc, method,
-                    (refKind == REF_invokeSpecial ||
-                        (MethodHandleNatives.refKindHasReceiver(refKind) &&
-                            restrictProtectedReceiver(method))), callerClass);
+            final boolean doRestrict    = true;
+            final boolean checkSecurity = true;
+            return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
         }
+        /** Check access and get the requested method, eliding receiver narrowing rules. */
         private MethodHandle getDirectMethodNoRestrict(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
-            return getDirectMethodCommon(refKind, refc, method, false, callerClass);
+            final boolean doRestrict    = false;
+            final boolean checkSecurity = true;
+            return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
         }
+        /** Check access and get the requested method, eliding security manager checks. */
+        private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
+            final boolean doRestrict    = true;
+            final boolean checkSecurity = false;  // not needed for reflection or for linking CONSTANT_MH constants
+            return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
+        }
+        /** Common code for all methods; do not call directly except from immediately above. */
         private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
+                                                   boolean checkSecurity,
                                                    boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
             checkMethod(refKind, refc, method);
+            // Optionally check with the security manager; this isn't needed for unreflect* calls.
+            if (checkSecurity)
+                checkSecurityManager(refc, method);
             assert(!method.isMethodHandleInvoke());
 
             Class<?> refcAsSuper;
@@ -1482,7 +1527,11 @@
             MethodHandle mh = DirectMethodHandle.make(refKind, refc, method);
             mh = maybeBindCaller(method, mh, callerClass);
             mh = mh.setVarargs(method);
-            if (doRestrict)
+            // Optionally narrow the receiver argument to refc using restrictReceiver.
+            if (doRestrict &&
+                   (refKind == REF_invokeSpecial ||
+                       (MethodHandleNatives.refKindHasReceiver(refKind) &&
+                           restrictProtectedReceiver(method))))
                 mh = restrictReceiver(method, mh, lookupClass());
             return mh;
         }
@@ -1492,14 +1541,29 @@
             if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
                 return mh;
             Class<?> hostClass = lookupClass;
-            if ((allowedModes & PRIVATE) == 0)  // caller must use full-power lookup
+            if (!hasPrivateAccess())  // caller must have private access
                 hostClass = callerClass;  // callerClass came from a security manager style stack walk
             MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass);
             // Note: caller will apply varargs after this step happens.
             return cbmh;
         }
+        /** Check access and get the requested field. */
         private MethodHandle getDirectField(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
+            final boolean checkSecurity = true;
+            return getDirectFieldCommon(refKind, refc, field, checkSecurity);
+        }
+        /** Check access and get the requested field, eliding security manager checks. */
+        private MethodHandle getDirectFieldNoSecurityManager(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
+            final boolean checkSecurity = false;  // not needed for reflection or for linking CONSTANT_MH constants
+            return getDirectFieldCommon(refKind, refc, field, checkSecurity);
+        }
+        /** Common code for all fields; do not call directly except from immediately above. */
+        private MethodHandle getDirectFieldCommon(byte refKind, Class<?> refc, MemberName field,
+                                                  boolean checkSecurity) throws IllegalAccessException {
             checkField(refKind, refc, field);
+            // Optionally check with the security manager; this isn't needed for unreflect* calls.
+            if (checkSecurity)
+                checkSecurityManager(refc, field);
             MethodHandle mh = DirectMethodHandle.make(refc, field);
             boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) &&
                                     restrictProtectedReceiver(field));
@@ -1507,9 +1571,24 @@
                 mh = restrictReceiver(field, mh, lookupClass());
             return mh;
         }
+        /** Check access and get the requested constructor. */
         private MethodHandle getDirectConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException {
+            final boolean checkSecurity = true;
+            return getDirectConstructorCommon(refc, ctor, checkSecurity);
+        }
+        /** Check access and get the requested constructor, eliding security manager checks. */
+        private MethodHandle getDirectConstructorNoSecurityManager(Class<?> refc, MemberName ctor) throws IllegalAccessException {
+            final boolean checkSecurity = false;  // not needed for reflection or for linking CONSTANT_MH constants
+            return getDirectConstructorCommon(refc, ctor, checkSecurity);
+        }
+        /** Common code for all constructors; do not call directly except from immediately above. */
+        private MethodHandle getDirectConstructorCommon(Class<?> refc, MemberName ctor,
+                                                  boolean checkSecurity) throws IllegalAccessException {
             assert(ctor.isConstructor());
             checkAccess(REF_newInvokeSpecial, refc, ctor);
+            // Optionally check with the security manager; this isn't needed for unreflect* calls.
+            if (checkSecurity)
+                checkSecurityManager(refc, ctor);
             assert(!MethodHandleNatives.isCallerSensitive(ctor));  // maybeBindCaller not relevant here
             return DirectMethodHandle.make(ctor).setVarargs(ctor);
         }
@@ -1527,7 +1606,7 @@
                 return mh;
             }
             MemberName resolved = resolveOrFail(refKind, member);
-            mh = getDirectMethodHandle(refKind, defc, resolved);
+            mh = getDirectMethodForConstant(refKind, defc, resolved);
             if (mh instanceof DirectMethodHandle
                     && canBeCached(refKind, defc, resolved)) {
                 MemberName key = mh.internalMemberName();
@@ -1573,13 +1652,14 @@
             return true;
         }
         private
-        MethodHandle getDirectMethodHandle(byte refKind, Class<?> defc, MemberName member) throws ReflectiveOperationException {
+        MethodHandle getDirectMethodForConstant(byte refKind, Class<?> defc, MemberName member)
+                throws ReflectiveOperationException {
             if (MethodHandleNatives.refKindIsField(refKind)) {
-                return getDirectField(refKind, defc, member);
+                return getDirectFieldNoSecurityManager(refKind, defc, member);
             } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
-                return getDirectMethod(refKind, defc, member, lookupClass);
+                return getDirectMethodNoSecurityManager(refKind, defc, member, lookupClass);
             } else if (refKind == REF_newInvokeSpecial) {
-                return getDirectConstructor(defc, member);
+                return getDirectConstructorNoSecurityManager(defc, member);
             }
             // oops
             throw newIllegalArgumentException("bad MethodHandle constant #"+member);
--- a/jdk/test/java/lang/invoke/TestPrivateMember.java	Sat Oct 05 05:30:39 2013 -0700
+++ b/jdk/test/java/lang/invoke/TestPrivateMember.java	Sat Oct 05 05:30:39 2013 -0700
@@ -47,7 +47,10 @@
         MethodHandles.Lookup lookup = MethodHandles.lookup();
         MethodType mt = MethodType.methodType(void.class);
         try {
-            MethodHandle mh = lookup.findStatic(Class.class, "checkInitted", mt);
+            Class<?> checkInittedHolder = TestPrivateMemberPackageSibling.class;
+            // Original model:  checkInittedHolder = Class.class;
+            // Not using Class.checkInitted because it could change without notice.
+            MethodHandle mh = lookup.findStatic(checkInittedHolder, "checkInitted", mt);
             throw new RuntimeException("IllegalAccessException not thrown");
         } catch (IllegalAccessException e) {
             // okay
@@ -55,3 +58,7 @@
         }
     }
 }
+
+class TestPrivateMemberPackageSibling {
+    private static void checkInitted() { }
+}