Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/lang/invoke/CallerSensitiveAccess.java
41149 views
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
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
return callerSensitiveMethods(Object.class.getModule())
66
.map(m -> new Object[] { m, shortDescription(m) })
67
.toArray(Object[][]::new);
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
@Test(dataProvider = "callerSensitiveMethods",
75
expectedExceptions = IllegalAccessException.class)
76
public void testPublicLookupFind(@NoInjection 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
if (Modifier.isStatic(method.getModifiers())) {
82
lookup.findStatic(refc, name, mt);
83
} else {
84
lookup.findVirtual(refc, name, mt);
85
}
86
}
87
88
/**
89
* Using publicLookup, attempt to use unreflect to obtain a method handle to a
90
* caller sensitive method.
91
*/
92
@Test(dataProvider = "callerSensitiveMethods",
93
expectedExceptions = IllegalAccessException.class)
94
public void testPublicLookupUnreflect(@NoInjection Method method, String desc) throws Exception {
95
MethodHandles.publicLookup().unreflect(method);
96
}
97
98
/**
99
* public accessible caller sensitive methods in APIs exported by java.base.
100
*/
101
@DataProvider(name = "accessibleCallerSensitiveMethods")
102
static Object[][] accessibleCallerSensitiveMethods() {
103
return callerSensitiveMethods(Object.class.getModule())
104
.filter(m -> Modifier.isPublic(m.getModifiers()))
105
.map(m -> { m.setAccessible(true); return m; })
106
.map(m -> new Object[] { m, shortDescription(m) })
107
.toArray(Object[][]::new);
108
}
109
110
/**
111
* Using publicLookup, attempt to use unreflect to obtain a method handle to a
112
* caller sensitive method.
113
*/
114
@Test(dataProvider = "accessibleCallerSensitiveMethods",
115
expectedExceptions = IllegalAccessException.class)
116
public void testLookupUnreflect(@NoInjection Method method, String desc) throws Exception {
117
MethodHandles.publicLookup().unreflect(method);
118
}
119
120
/**
121
* Using a Lookup with no original access that can't lookup caller-sensitive
122
* method
123
*/
124
@Test(dataProvider = "callerSensitiveMethods",
125
expectedExceptions = IllegalAccessException.class)
126
public void testLookupNoOriginalAccessFind(@NoInjection Method method, String desc) throws Exception {
127
Lookup lookup = MethodHandles.lookup().dropLookupMode(Lookup.ORIGINAL);
128
assertTrue(lookup.hasFullPrivilegeAccess());
129
Class<?> refc = method.getDeclaringClass();
130
String name = method.getName();
131
MethodType mt = MethodType.methodType(method.getReturnType(), method.getParameterTypes());
132
if (Modifier.isStatic(method.getModifiers())) {
133
lookup.findStatic(refc, name, mt);
134
} else {
135
lookup.findVirtual(refc, name, mt);
136
}
137
}
138
139
/**
140
* Using a Lookup with no original access that can't unreflect caller-sensitive
141
* method
142
*/
143
@Test(dataProvider = "callerSensitiveMethods",
144
expectedExceptions = IllegalAccessException.class)
145
public void testLookupNoOriginalAccessUnreflect(@NoInjection Method method, String desc) throws Exception {
146
Lookup lookup = MethodHandles.lookup().dropLookupMode(Lookup.ORIGINAL);
147
assertTrue(lookup.hasFullPrivilegeAccess());
148
lookup.unreflect(method);
149
}
150
151
// -- Test method handles to setAccessible --
152
153
private int aField;
154
155
Field accessibleField() {
156
try {
157
return getClass().getDeclaredField("aField");
158
} catch (NoSuchFieldException e) {
159
fail();
160
return null;
161
}
162
}
163
164
Field inaccessibleField() {
165
try {
166
return String.class.getDeclaredField("hash");
167
} catch (NoSuchFieldException e) {
168
fail();
169
return null;
170
}
171
}
172
173
void findAndInvokeSetAccessible(Class<? extends AccessibleObject> refc, Field f) throws Throwable {
174
MethodType mt = MethodType.methodType(void.class, boolean.class);
175
MethodHandle mh = MethodHandles.lookup().findVirtual(refc, "setAccessible", mt);
176
mh.invoke(f, true); // may throw InaccessibleObjectException
177
assertTrue(f.isAccessible());
178
}
179
180
void unreflectAndInvokeSetAccessible(Method m, Field f) throws Throwable {
181
assertTrue(m.getName().equals("setAccessible"));
182
assertFalse(Modifier.isStatic(m.getModifiers()));
183
MethodHandle mh = MethodHandles.lookup().unreflect(m);
184
mh.invoke(f, true); // may throw InaccessibleObjectException
185
assertTrue(f.isAccessible());
186
}
187
188
/**
189
* Create a method handle to setAccessible and use it to suppress access to an
190
* accessible member.
191
*/
192
@Test
193
public void testSetAccessible1() throws Throwable {
194
findAndInvokeSetAccessible(AccessibleObject.class, accessibleField());
195
}
196
@Test
197
public void testSetAccessible2() throws Throwable {
198
findAndInvokeSetAccessible(Field.class, accessibleField());
199
}
200
@Test
201
public void testSetAccessible3() throws Throwable {
202
Method m = AccessibleObject.class.getMethod("setAccessible", boolean.class);
203
unreflectAndInvokeSetAccessible(m, accessibleField());
204
}
205
@Test
206
public void testSetAccessible4() throws Throwable {
207
Method m = Field.class.getMethod("setAccessible", boolean.class);
208
unreflectAndInvokeSetAccessible(m, accessibleField());
209
}
210
211
/**
212
* Create a method handle to setAccessible and attempt to use it to suppress
213
* access to an inaccessible member.
214
*/
215
@Test(expectedExceptions = InaccessibleObjectException.class)
216
public void testSetAccessible5() throws Throwable {
217
findAndInvokeSetAccessible(AccessibleObject.class, inaccessibleField());
218
}
219
@Test(expectedExceptions = InaccessibleObjectException.class)
220
public void testSetAccessible6() throws Throwable {
221
findAndInvokeSetAccessible(Field.class, inaccessibleField());
222
}
223
@Test(expectedExceptions = InaccessibleObjectException.class)
224
public void testSetAccessible7() throws Throwable {
225
Method m = AccessibleObject.class.getMethod("setAccessible", boolean.class);
226
unreflectAndInvokeSetAccessible(m, inaccessibleField());
227
}
228
@Test(expectedExceptions = InaccessibleObjectException.class)
229
public void testSetAccessible8() throws Throwable {
230
Method m = Field.class.getMethod("setAccessible", boolean.class);
231
unreflectAndInvokeSetAccessible(m, inaccessibleField());
232
}
233
234
235
// -- Test sub-classes of AccessibleObject --
236
237
/**
238
* Custom AccessibleObject objects. One class overrides setAccessible, the other
239
* does not override this method.
240
*/
241
@DataProvider(name = "customAccessibleObjects")
242
static Object[][] customAccessibleObjectClasses() {
243
return new Object[][] { { new S1() }, { new S2() } };
244
}
245
public static class S1 extends AccessibleObject { }
246
public static class S2 extends AccessibleObject {
247
@Override
248
public void setAccessible(boolean flag) {
249
super.setAccessible(flag);
250
}
251
}
252
253
void findAndInvokeSetAccessible(Lookup lookup, AccessibleObject obj) throws Throwable {
254
MethodType mt = MethodType.methodType(void.class, boolean.class);
255
MethodHandle mh = lookup.findVirtual(obj.getClass(), "setAccessible", mt);
256
mh.invoke(obj, true);
257
assertTrue(obj.isAccessible());
258
}
259
260
void unreflectAndInvokeSetAccessible(Lookup lookup, AccessibleObject obj) throws Throwable {
261
Method m = obj.getClass().getMethod("setAccessible", boolean.class);
262
MethodHandle mh = lookup.unreflect(m);
263
mh.invoke(obj, true);
264
assertTrue(obj.isAccessible());
265
}
266
267
/**
268
* Using publicLookup, create a method handle to setAccessible and invoke it
269
* on a custom AccessibleObject object.
270
*/
271
@Test(expectedExceptions = IllegalAccessException.class)
272
public void testPublicLookupSubclass1() throws Throwable {
273
// S1 does not override setAccessible
274
findAndInvokeSetAccessible(MethodHandles.publicLookup(), new S1());
275
}
276
@Test
277
public void testPublicLookupSubclass2() throws Throwable {
278
// S2 overrides setAccessible
279
findAndInvokeSetAccessible(MethodHandles.publicLookup(), new S2());
280
}
281
@Test(expectedExceptions = IllegalAccessException.class)
282
public void testPublicLookupSubclass3() throws Throwable {
283
// S1 does not override setAccessible
284
unreflectAndInvokeSetAccessible(MethodHandles.publicLookup(), new S1());
285
}
286
@Test
287
public void testPublicLookupSubclass4() throws Throwable {
288
// S2 overrides setAccessible
289
unreflectAndInvokeSetAccessible(MethodHandles.publicLookup(), new S2());
290
}
291
292
/**
293
* Using a full power lookup, create a method handle to setAccessible and
294
* invoke it on a custom AccessibleObject object.
295
*/
296
@Test(dataProvider = "customAccessibleObjects")
297
public void testLookupSubclass1(AccessibleObject obj) throws Throwable {
298
findAndInvokeSetAccessible(MethodHandles.lookup(), obj);
299
}
300
@Test(dataProvider = "customAccessibleObjects")
301
public void testLookupSubclass2(AccessibleObject obj) throws Throwable {
302
unreflectAndInvokeSetAccessible(MethodHandles.lookup(), obj);
303
}
304
305
/**
306
* Using a full power lookup, create a method handle to setAccessible on a
307
* sub-class of AccessibleObject and then attempt to invoke it on a Field object.
308
*/
309
@Test(dataProvider = "customAccessibleObjects",
310
expectedExceptions = ClassCastException.class)
311
public void testLookupSubclass3(AccessibleObject obj) throws Throwable {
312
MethodType mt = MethodType.methodType(void.class, boolean.class);
313
Lookup lookup = MethodHandles.lookup();
314
MethodHandle mh = lookup.findVirtual(obj.getClass(), "setAccessible", mt);
315
mh.invoke(accessibleField(), true); // should throw ClassCastException
316
}
317
318
/**
319
* Using a full power lookup, use unreflect to create a method handle to
320
* setAccessible on a sub-class of AccessibleObject, then attempt to invoke
321
* it on a Field object.
322
*/
323
@Test
324
public void testLookupSubclass4() throws Throwable {
325
// S1 does not override setAccessible
326
Method m = S1.class.getMethod("setAccessible", boolean.class);
327
assertTrue(m.getDeclaringClass() == AccessibleObject.class);
328
MethodHandle mh = MethodHandles.lookup().unreflect(m);
329
Field f = accessibleField();
330
mh.invoke(f, true);
331
assertTrue(f.isAccessible());
332
}
333
@Test(expectedExceptions = InaccessibleObjectException.class)
334
public void testLookupSubclass5() throws Throwable {
335
// S1 does not override setAccessible
336
Method m = S1.class.getMethod("setAccessible", boolean.class);
337
assertTrue(m.getDeclaringClass() == AccessibleObject.class);
338
MethodHandle mh = MethodHandles.lookup().unreflect(m);
339
mh.invoke(inaccessibleField(), true); // should throw InaccessibleObjectException
340
}
341
@Test(expectedExceptions = ClassCastException.class)
342
public void testLookupSubclass6() throws Throwable {
343
// S2 overrides setAccessible
344
Method m = S2.class.getMethod("setAccessible", boolean.class);
345
assertTrue(m.getDeclaringClass() == S2.class);
346
MethodHandle mh = MethodHandles.lookup().unreflect(m);
347
mh.invoke(accessibleField(), true); // should throw ClassCastException
348
}
349
@Test(expectedExceptions = ClassCastException.class)
350
public void testLookupSubclass7() throws Throwable {
351
// S2 overrides setAccessible
352
Method m = S2.class.getMethod("setAccessible", boolean.class);
353
assertTrue(m.getDeclaringClass() == S2.class);
354
MethodHandle mh = MethodHandles.lookup().unreflect(m);
355
mh.invoke(inaccessibleField(), true); // should throw ClassCastException
356
}
357
358
359
// -- supporting methods --
360
361
/**
362
* Returns a stream of all caller sensitive methods on public classes in packages
363
* exported by a named module.
364
*/
365
static Stream<Method> callerSensitiveMethods(Module module) {
366
assert module.isNamed();
367
ModuleReference mref = module.getLayer().configuration()
368
.findModule(module.getName())
369
.orElseThrow(() -> new RuntimeException())
370
.reference();
371
// find all ".class" resources in the module
372
// transform the resource name to a class name
373
// load every class in the exported packages
374
// return the caller sensitive methods of the public classes
375
try (ModuleReader reader = mref.open()) {
376
return reader.list()
377
.filter(rn -> rn.endsWith(".class"))
378
.map(rn -> rn.substring(0, rn.length() - 6)
379
.replace('/', '.'))
380
.filter(cn -> module.isExported(packageName(cn)))
381
.map(cn -> Class.forName(module, cn))
382
.filter(refc -> refc != null
383
&& Modifier.isPublic(refc.getModifiers()))
384
.map(refc -> callerSensitiveMethods(refc))
385
.flatMap(List::stream);
386
} catch (IOException ioe) {
387
throw new UncheckedIOException(ioe);
388
}
389
}
390
391
static String packageName(String cn) {
392
int last = cn.lastIndexOf('.');
393
if (last > 0) {
394
return cn.substring(0, last);
395
} else {
396
return "";
397
}
398
}
399
400
/**
401
* Returns a list of the caller sensitive methods directly declared by the given
402
* class.
403
*/
404
static List<Method> callerSensitiveMethods(Class<?> refc) {
405
return Arrays.stream(refc.getDeclaredMethods())
406
.filter(m -> m.isAnnotationPresent(CallerSensitive.class))
407
.collect(Collectors.toList());
408
}
409
410
/**
411
* Returns a short description of the given method for tracing purposes.
412
*/
413
static String shortDescription(Method m) {
414
var sb = new StringBuilder();
415
sb.append(m.getDeclaringClass().getName());
416
sb.append('.');
417
sb.append(m.getName());
418
sb.append('(');
419
StringJoiner sj = new StringJoiner(",");
420
for (Class<?> parameterType : m.getParameterTypes()) {
421
sj.add(parameterType.getTypeName());
422
}
423
sb.append(sj);
424
sb.append(')');
425
return sb.toString();
426
}
427
}
428
429