< prev index next >

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

Print this page

  1 /*
  2  * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  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 testng/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 org.testng.annotations.DataProvider;
 54 import org.testng.annotations.NoInjection;
 55 import org.testng.annotations.Test;
 56 import static org.testng.Assert.*;
 57 
 58 public class CallerSensitiveAccess {







 59 
 60     /**
 61      * Caller sensitive methods in APIs exported by java.base.
 62      */
 63     @DataProvider(name = "callerSensitiveMethods")
 64     static Object[][] callerSensitiveMethods() {
 65         try (Stream<Method> stream = callerSensitiveMethods(Object.class.getModule())) {
 66             return stream.map(m -> new Object[]{m, shortDescription(m)})
 67                     .toArray(Object[][]::new);
 68         }
 69     }
 70 
 71     /**
 72      * Using publicLookup, attempt to use findVirtual or findStatic to obtain a
 73      * method handle to a caller sensitive method.
 74      */
 75     @Test(dataProvider = "callerSensitiveMethods",
 76             expectedExceptions = IllegalAccessException.class)
 77     public void testPublicLookupFind(@NoInjection Method method, String desc) throws Exception {
 78         Lookup lookup = MethodHandles.publicLookup();
 79         Class<?> refc = method.getDeclaringClass();
 80         String name = method.getName();
 81         MethodType mt = MethodType.methodType(method.getReturnType(), method.getParameterTypes());
 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      * Using publicLookup, attempt to use unreflect to obtain a method handle to a
 91      * caller sensitive method.
 92      */
 93     @Test(dataProvider = "callerSensitiveMethods",
 94             expectedExceptions = IllegalAccessException.class)
 95     public void testPublicLookupUnreflect(@NoInjection Method method, String desc) throws Exception {
 96         MethodHandles.publicLookup().unreflect(method);
 97     }
 98 
 99     /**
100      * public accessible caller sensitive methods in APIs exported by java.base.
101      */
102     @DataProvider(name = "accessibleCallerSensitiveMethods")
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     @Test(dataProvider = "accessibleCallerSensitiveMethods",
118             expectedExceptions = IllegalAccessException.class)
119     public void testLookupUnreflect(@NoInjection Method method, String desc) throws Exception {
120         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     @Test(dataProvider = "callerSensitiveMethods",
128             expectedExceptions = IllegalAccessException.class)
129     public void testLookupNoOriginalAccessFind(@NoInjection Method method, String desc) throws Exception {
130         Lookup lookup = MethodHandles.lookup().dropLookupMode(Lookup.ORIGINAL);

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

401      */
402     static Stream<Method> callerSensitiveMethods(Module module) {
403         assert 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);
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())

  1 /*
  2  * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  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 testng/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 org.testng.annotations.BeforeClass;
 54 import org.testng.annotations.DataProvider;
 55 import org.testng.annotations.NoInjection;
 56 import org.testng.annotations.Test;
 57 import static org.testng.Assert.*;
 58 
 59 public class CallerSensitiveAccess {
 60     // Cache the list of Caller Sensitive Methods
 61     private static List<Method> CALLER_SENSITIVE_METHODS;
 62 
 63     @BeforeClass
 64     private 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     @DataProvider(name = "callerSensitiveMethods")
 72     static Object[][] callerSensitiveMethods() {
 73         return CALLER_SENSITIVE_METHODS.stream()
 74                 .map(m -> new Object[]{m, shortDescription(m)})
 75                 .toArray(Object[][]::new);

 76     }
 77 
 78     /**
 79      * Using publicLookup, attempt to use findVirtual or findStatic to obtain a
 80      * method handle to a caller sensitive method.
 81      */
 82     @Test(dataProvider = "callerSensitiveMethods",
 83             expectedExceptions = IllegalAccessException.class)
 84     public void testPublicLookupFind(@NoInjection Method method, String desc) throws Exception {
 85         Lookup lookup = MethodHandles.publicLookup();
 86         Class<?> refc = method.getDeclaringClass();
 87         String name = method.getName();
 88         MethodType mt = MethodType.methodType(method.getReturnType(), method.getParameterTypes());
 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      * Using publicLookup, attempt to use unreflect to obtain a method handle to a
 98      * caller sensitive method.
 99      */
100     @Test(dataProvider = "callerSensitiveMethods",
101             expectedExceptions = IllegalAccessException.class)
102     public void testPublicLookupUnreflect(@NoInjection Method method, String desc) throws Exception {
103         MethodHandles.publicLookup().unreflect(method);
104     }
105 
106     /**
107      * public accessible caller sensitive methods in APIs exported by java.base.
108      */
109     @DataProvider(name = "accessibleCallerSensitiveMethods")
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     @Test(dataProvider = "accessibleCallerSensitiveMethods",
123             expectedExceptions = IllegalAccessException.class)
124     public void testLookupUnreflect(@NoInjection Method method, String desc) throws Exception {
125         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     @Test(dataProvider = "callerSensitiveMethods",
133             expectedExceptions = IllegalAccessException.class)
134     public void testLookupNoOriginalAccessFind(@NoInjection Method method, String desc) throws Exception {
135         Lookup lookup = MethodHandles.lookup().dropLookupMode(Lookup.ORIGINAL);

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