< prev index next >

test/jdk/java/lang/invoke/callerSensitive/CallerSensitiveAccess.java

Print this page

  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /* @test
 25  * @bug 8196830 8235351 8257874
 26  * @modules java.base/jdk.internal.reflect
 27  * @run junit/othervm CallerSensitiveAccess
 28  * @summary Check Lookup findVirtual, findStatic and unreflect behavior with
 29  *          caller sensitive methods with focus on AccessibleObject.setAccessible
 30  */
 31 
 32 import java.io.IOException;
 33 import java.io.UncheckedIOException;
 34 import java.lang.invoke.MethodHandle;
 35 import java.lang.invoke.MethodHandles;
 36 import java.lang.invoke.MethodHandles.Lookup;
 37 import java.lang.invoke.MethodType;
 38 import java.lang.module.ModuleReader;
 39 import java.lang.module.ModuleReference;
 40 import java.lang.reflect.AccessibleObject;
 41 import java.lang.reflect.Field;
 42 import java.lang.reflect.InaccessibleObjectException;
 43 import java.lang.reflect.Method;
 44 import java.lang.reflect.Modifier;
 45 import java.util.Arrays;
 46 import java.util.List;
 47 import java.util.StringJoiner;
 48 import java.util.stream.Collectors;
 49 import java.util.stream.Stream;
 50 
 51 import jdk.internal.reflect.CallerSensitive;
 52 
 53 import static org.junit.jupiter.api.Assertions.*;

 54 import org.junit.jupiter.api.Test;
 55 import org.junit.jupiter.params.ParameterizedTest;
 56 import org.junit.jupiter.params.provider.MethodSource;
 57 
 58 public class CallerSensitiveAccess {







 59 
 60     /**
 61      * Caller sensitive methods in APIs exported by java.base.
 62      */
 63     static Object[][] callerSensitiveMethods() {
 64         try (Stream<Method> stream = callerSensitiveMethods(Object.class.getModule())) {
 65             return stream.map(m -> new Object[]{m, shortDescription(m)})
 66                     .toArray(Object[][]::new);
 67         }
 68     }
 69 
 70     /**
 71      * Using publicLookup, attempt to use findVirtual or findStatic to obtain a
 72      * method handle to a caller sensitive method.
 73      */
 74     @ParameterizedTest
 75     @MethodSource("callerSensitiveMethods")
 76     public void testPublicLookupFind(Method method, String desc) throws Exception {
 77         Lookup lookup = MethodHandles.publicLookup();
 78         Class<?> refc = method.getDeclaringClass();
 79         String name = method.getName();
 80         MethodType mt = MethodType.methodType(method.getReturnType(), method.getParameterTypes());
 81         assertThrows(IllegalAccessException.class, () -> {
 82             if (Modifier.isStatic(method.getModifiers())) {
 83                 lookup.findStatic(refc, name, mt);
 84             } else {
 85                 lookup.findVirtual(refc, name, mt);
 86             }
 87         });
 88     }
 89 
 90     /**
 91      * Using publicLookup, attempt to use unreflect to obtain a method handle to a
 92      * caller sensitive method.
 93      */
 94     @ParameterizedTest
 95     @MethodSource("callerSensitiveMethods")
 96     public void testPublicLookupUnreflect(Method method, String desc) throws Exception {
 97         assertThrows(IllegalAccessException.class, () -> MethodHandles.publicLookup().unreflect(method));
 98     }
 99 
100     /**
101      * public accessible caller sensitive methods in APIs exported by java.base.
102      */
103     static Object[][] accessibleCallerSensitiveMethods() {
104         try (Stream<Method> stream = callerSensitiveMethods(Object.class.getModule())) {
105             return stream
106                 .filter(m -> Modifier.isPublic(m.getModifiers()))
107                 .map(m -> { m.setAccessible(true); return m; })
108                 .map(m -> new Object[] { m, shortDescription(m) })
109                 .toArray(Object[][]::new);
110         }
111     }
112 
113     /**
114      * Using publicLookup, attempt to use unreflect to obtain a method handle to a
115      * caller sensitive method.
116      */
117     @ParameterizedTest
118     @MethodSource("accessibleCallerSensitiveMethods")
119     public void testLookupUnreflect(Method method, String desc) throws Exception {
120         assertThrows(IllegalAccessException.class, () -> MethodHandles.publicLookup().unreflect(method));
121     }
122 
123     /**
124      * Using a Lookup with no original access that can't lookup caller-sensitive
125      * method
126      */
127     @ParameterizedTest
128     @MethodSource("callerSensitiveMethods")
129     public void testLookupNoOriginalAccessFind(Method method, String desc) throws Exception {
130         Lookup lookup = MethodHandles.lookup().dropLookupMode(Lookup.ORIGINAL);

373     private static class Inner {
374         private static boolean privateField = false;
375     }
376 
377     @Test
378     public void testInnerPrivateField() throws Throwable {
379         Field f = Inner.class.getDeclaredField("privateField");
380         // Field::setInt
381         MethodType mtype = MethodType.methodType(void.class, Object.class, boolean.class);
382         MethodHandle mh = MethodHandles.lookup().findVirtual(Field.class, "setBoolean", mtype);
383         mh.invokeExact(f, (Object)null, true);
384         // Field::getInt
385         mh = MethodHandles.lookup().findVirtual(Field.class, "getBoolean", MethodType.methodType(boolean.class, Object.class));
386         boolean value = (boolean)mh.invokeExact(f, (Object)null);
387         assertTrue(value);
388     }
389 
390     // -- supporting methods --
391 
392     /**
393      * Returns a stream of all caller sensitive methods on public classes in packages
394      * exported by a named module.

395      */
396     static Stream<Method> callerSensitiveMethods(Module module) {
397         assertTrue(module.isNamed());
398         ModuleReference mref = module.getLayer().configuration()
399                 .findModule(module.getName())
400                 .orElseThrow(() -> new RuntimeException())
401                 .reference();
402         // find all ".class" resources in the module
403         // transform the resource name to a class name
404         // load every class in the exported packages
405         // return the caller sensitive methods of the public classes
406         try (ModuleReader reader = mref.open()) {
407             return reader.list()
408                     .filter(rn -> rn.endsWith(".class"))
409                     .map(rn -> rn.substring(0, rn.length() - 6)
410                                  .replace('/', '.'))
411                     .filter(cn -> module.isExported(packageName(cn)))
412                     .map(cn -> Class.forName(module, cn))
413                     .filter(refc -> refc != null
414                                     && Modifier.isPublic(refc.getModifiers()))
415                     .map(refc -> callerSensitiveMethods(refc))
416                     .flatMap(List::stream);
417         } catch (IOException ioe) {
418             throw new UncheckedIOException(ioe);
419         }
420     }
421 
422     static String packageName(String cn) {
423         int last = cn.lastIndexOf('.');
424         if (last > 0) {
425             return cn.substring(0, last);
426         } else {
427             return "";
428         }
429     }
430 
431     /**
432      * Returns a list of the caller sensitive methods directly declared by the given
433      * class.
434      */
435     static List<Method> callerSensitiveMethods(Class<?> refc) {
436         return Arrays.stream(refc.getDeclaredMethods())

  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /* @test
 25  * @bug 8196830 8235351 8257874 8327639
 26  * @modules java.base/jdk.internal.reflect
 27  * @run junit/othervm CallerSensitiveAccess
 28  * @summary Check Lookup findVirtual, findStatic and unreflect behavior with
 29  *          caller sensitive methods with focus on AccessibleObject.setAccessible
 30  */
 31 
 32 import java.io.IOException;
 33 import java.io.UncheckedIOException;
 34 import java.lang.invoke.MethodHandle;
 35 import java.lang.invoke.MethodHandles;
 36 import java.lang.invoke.MethodHandles.Lookup;
 37 import java.lang.invoke.MethodType;
 38 import java.lang.module.ModuleReader;
 39 import java.lang.module.ModuleReference;
 40 import java.lang.reflect.AccessibleObject;
 41 import java.lang.reflect.Field;
 42 import java.lang.reflect.InaccessibleObjectException;
 43 import java.lang.reflect.Method;
 44 import java.lang.reflect.Modifier;
 45 import java.util.Arrays;
 46 import java.util.List;
 47 import java.util.StringJoiner;
 48 import java.util.stream.Collectors;
 49 import java.util.stream.Stream;
 50 
 51 import jdk.internal.reflect.CallerSensitive;
 52 
 53 import static org.junit.jupiter.api.Assertions.*;
 54 import org.junit.jupiter.api.BeforeAll;
 55 import org.junit.jupiter.api.Test;
 56 import org.junit.jupiter.params.ParameterizedTest;
 57 import org.junit.jupiter.params.provider.MethodSource;
 58 
 59 public class CallerSensitiveAccess {
 60     // Cache the list of Caller Sensitive Methods
 61     private static List<Method> CALLER_SENSITIVE_METHODS;
 62 
 63     @BeforeAll
 64     public static void setupCallerSensitiveMethods() {
 65         CALLER_SENSITIVE_METHODS = callerSensitiveMethods(Object.class.getModule());
 66     }
 67 
 68     /**
 69      * Caller sensitive methods in APIs exported by java.base.
 70      */
 71     static Object[][] callerSensitiveMethods() {
 72         return CALLER_SENSITIVE_METHODS.stream()
 73                 .map(m -> new Object[]{m, shortDescription(m)})
 74                 .toArray(Object[][]::new);

 75     }
 76 
 77     /**
 78      * Using publicLookup, attempt to use findVirtual or findStatic to obtain a
 79      * method handle to a caller sensitive method.
 80      */
 81     @ParameterizedTest
 82     @MethodSource("callerSensitiveMethods")
 83     public void testPublicLookupFind(Method method, String desc) throws Exception {
 84         Lookup lookup = MethodHandles.publicLookup();
 85         Class<?> refc = method.getDeclaringClass();
 86         String name = method.getName();
 87         MethodType mt = MethodType.methodType(method.getReturnType(), method.getParameterTypes());
 88         assertThrows(IllegalAccessException.class, () -> {
 89             if (Modifier.isStatic(method.getModifiers())) {
 90                 lookup.findStatic(refc, name, mt);
 91             } else {
 92                 lookup.findVirtual(refc, name, mt);
 93             }
 94         });
 95     }
 96 
 97     /**
 98      * Using publicLookup, attempt to use unreflect to obtain a method handle to a
 99      * caller sensitive method.
100      */
101     @ParameterizedTest
102     @MethodSource("callerSensitiveMethods")
103     public void testPublicLookupUnreflect(Method method, String desc) throws Exception {
104         assertThrows(IllegalAccessException.class, () -> MethodHandles.publicLookup().unreflect(method));
105     }
106 
107     /**
108      * public accessible caller sensitive methods in APIs exported by java.base.
109      */
110     static Object[][] accessibleCallerSensitiveMethods() {
111         return CALLER_SENSITIVE_METHODS.stream()

112                 .filter(m -> Modifier.isPublic(m.getModifiers()))
113                 .map(m -> { m.setAccessible(true); return m; })
114                 .map(m -> new Object[] { m, shortDescription(m) })
115                 .toArray(Object[][]::new);

116     }
117 
118     /**
119      * Using publicLookup, attempt to use unreflect to obtain a method handle to a
120      * caller sensitive method.
121      */
122     @ParameterizedTest
123     @MethodSource("accessibleCallerSensitiveMethods")
124     public void testLookupUnreflect(Method method, String desc) throws Exception {
125         assertThrows(IllegalAccessException.class, () -> MethodHandles.publicLookup().unreflect(method));
126     }
127 
128     /**
129      * Using a Lookup with no original access that can't lookup caller-sensitive
130      * method
131      */
132     @ParameterizedTest
133     @MethodSource("callerSensitiveMethods")
134     public void testLookupNoOriginalAccessFind(Method method, String desc) throws Exception {
135         Lookup lookup = MethodHandles.lookup().dropLookupMode(Lookup.ORIGINAL);

378     private static class Inner {
379         private static boolean privateField = false;
380     }
381 
382     @Test
383     public void testInnerPrivateField() throws Throwable {
384         Field f = Inner.class.getDeclaredField("privateField");
385         // Field::setInt
386         MethodType mtype = MethodType.methodType(void.class, Object.class, boolean.class);
387         MethodHandle mh = MethodHandles.lookup().findVirtual(Field.class, "setBoolean", mtype);
388         mh.invokeExact(f, (Object)null, true);
389         // Field::getInt
390         mh = MethodHandles.lookup().findVirtual(Field.class, "getBoolean", MethodType.methodType(boolean.class, Object.class));
391         boolean value = (boolean)mh.invokeExact(f, (Object)null);
392         assertTrue(value);
393     }
394 
395     // -- supporting methods --
396 
397     /**
398      * Returns a List of all caller sensitive methods on public classes in packages
399      * exported by a named module.
400      * Returns a List instead of a stream so the ModuleReader can be closed before returning.
401      */
402     static List<Method> callerSensitiveMethods(Module module) {
403         assertTrue(module.isNamed());
404         ModuleReference mref = module.getLayer().configuration()
405                 .findModule(module.getName())
406                 .orElseThrow(() -> new RuntimeException())
407                 .reference();
408         // find all ".class" resources in the module
409         // transform the resource name to a class name
410         // load every class in the exported packages
411         // return the caller sensitive methods of the public classes
412         try (ModuleReader reader = mref.open()) {
413             return reader.list()
414                     .filter(rn -> rn.endsWith(".class"))
415                     .map(rn -> rn.substring(0, rn.length() - 6)
416                                  .replace('/', '.'))
417                     .filter(cn -> module.isExported(packageName(cn)))
418                     .map(cn -> Class.forName(module, cn))
419                     .filter(refc -> refc != null
420                                     && Modifier.isPublic(refc.getModifiers()))
421                     .map(refc -> callerSensitiveMethods(refc))
422                     .flatMap(List::stream).toList();
423         } catch (IOException ioe) {
424             throw new UncheckedIOException(ioe);
425         }
426     }
427 
428     static String packageName(String cn) {
429         int last = cn.lastIndexOf('.');
430         if (last > 0) {
431             return cn.substring(0, last);
432         } else {
433             return "";
434         }
435     }
436 
437     /**
438      * Returns a list of the caller sensitive methods directly declared by the given
439      * class.
440      */
441     static List<Method> callerSensitiveMethods(Class<?> refc) {
442         return Arrays.stream(refc.getDeclaredMethods())
< prev index next >