Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/lang/invoke/DefineClassTest.java
41149 views
1
/*
2
* Copyright (c) 2017, 2020, 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
* @modules java.base/java.lang:open
26
* java.base/jdk.internal.org.objectweb.asm
27
* @run testng/othervm test.DefineClassTest
28
* @summary Basic test for java.lang.invoke.MethodHandles.Lookup.defineClass
29
*/
30
31
package test;
32
33
import java.lang.invoke.MethodHandles.Lookup;
34
import static java.lang.invoke.MethodHandles.*;
35
import static java.lang.invoke.MethodHandles.Lookup.*;
36
import java.net.URL;
37
import java.net.URLClassLoader;
38
import java.nio.file.Files;
39
import java.nio.file.Path;
40
import java.nio.file.Paths;
41
42
import jdk.internal.org.objectweb.asm.ClassWriter;
43
import jdk.internal.org.objectweb.asm.MethodVisitor;
44
import static jdk.internal.org.objectweb.asm.Opcodes.*;
45
46
import org.testng.annotations.Test;
47
import static org.testng.Assert.*;
48
49
public class DefineClassTest {
50
private static final String THIS_PACKAGE = DefineClassTest.class.getPackageName();
51
52
/**
53
* Test that a class has the same class loader, and is in the same package and
54
* protection domain, as a lookup class.
55
*/
56
void testSameAbode(Class<?> clazz, Class<?> lc) {
57
assertTrue(clazz.getClassLoader() == lc.getClassLoader());
58
assertEquals(clazz.getPackageName(), lc.getPackageName());
59
assertTrue(clazz.getProtectionDomain() == lc.getProtectionDomain());
60
}
61
62
/**
63
* Tests that a class is discoverable by name using Class.forName and
64
* lookup.findClass
65
*/
66
void testDiscoverable(Class<?> clazz, Lookup lookup) throws Exception {
67
String cn = clazz.getName();
68
ClassLoader loader = clazz.getClassLoader();
69
assertTrue(Class.forName(cn, false, loader) == clazz);
70
assertTrue(lookup.findClass(cn) == clazz);
71
}
72
73
/**
74
* Basic test of defineClass to define a class in the same package as test.
75
*/
76
@Test
77
public void testDefineClass() throws Exception {
78
final String CLASS_NAME = THIS_PACKAGE + ".Foo";
79
Lookup lookup = lookup();
80
Class<?> clazz = lookup.defineClass(generateClass(CLASS_NAME));
81
82
// test name
83
assertEquals(clazz.getName(), CLASS_NAME);
84
85
// test loader/package/protection-domain
86
testSameAbode(clazz, lookup.lookupClass());
87
88
// test discoverable
89
testDiscoverable(clazz, lookup);
90
91
// attempt defineClass again
92
try {
93
lookup.defineClass(generateClass(CLASS_NAME));
94
assertTrue(false);
95
} catch (LinkageError expected) { }
96
}
97
98
/**
99
* Test public/package/protected/private access from class defined with defineClass.
100
*/
101
@Test
102
public void testAccess() throws Exception {
103
final String THIS_CLASS = this.getClass().getName();
104
final String CLASS_NAME = THIS_PACKAGE + ".Runner";
105
Lookup lookup = lookup();
106
107
// public
108
byte[] classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method1");
109
testInvoke(lookup.defineClass(classBytes));
110
111
// package
112
classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method2");
113
testInvoke(lookup.defineClass(classBytes));
114
115
// protected (same package)
116
classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method3");
117
testInvoke(lookup.defineClass(classBytes));
118
119
// private
120
classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method4");
121
Class<?> clazz = lookup.defineClass(classBytes);
122
Runnable r = (Runnable) clazz.newInstance();
123
try {
124
r.run();
125
assertTrue(false);
126
} catch (IllegalAccessError expected) { }
127
}
128
129
public static void method1() { }
130
static void method2() { }
131
protected static void method3() { }
132
private static void method4() { }
133
134
void testInvoke(Class<?> clazz) throws Exception {
135
Object obj = clazz.newInstance();
136
((Runnable) obj).run();
137
}
138
139
/**
140
* Test that defineClass does not run the class initializer
141
*/
142
@Test
143
public void testInitializerNotRun() throws Exception {
144
final String THIS_CLASS = this.getClass().getName();
145
final String CLASS_NAME = THIS_PACKAGE + ".ClassWithClinit";
146
147
byte[] classBytes = generateClassWithInitializer(CLASS_NAME, THIS_CLASS, "fail");
148
Class<?> clazz = lookup().defineClass(classBytes);
149
150
// trigger initializer to run
151
try {
152
clazz.newInstance();
153
assertTrue(false);
154
} catch (ExceptionInInitializerError e) {
155
assertTrue(e.getCause() instanceof IllegalCallerException);
156
}
157
}
158
159
static void fail() { throw new IllegalCallerException(); }
160
161
162
/**
163
* Test defineClass to define classes in a package containing classes with
164
* different protection domains.
165
*/
166
@Test
167
public void testTwoProtectionDomains() throws Exception {
168
Path here = Paths.get("");
169
170
// p.C1 in one exploded directory
171
Path dir1 = Files.createTempDirectory(here, "classes");
172
Path p = Files.createDirectory(dir1.resolve("p"));
173
Files.write(p.resolve("C1.class"), generateClass("p.C1"));
174
URL url1 = dir1.toUri().toURL();
175
176
// p.C2 in another exploded directory
177
Path dir2 = Files.createTempDirectory(here, "classes");
178
p = Files.createDirectory(dir2.resolve("p"));
179
Files.write(p.resolve("C2.class"), generateClass("p.C2"));
180
URL url2 = dir2.toUri().toURL();
181
182
// load p.C1 and p.C2
183
ClassLoader loader = new URLClassLoader(new URL[] { url1, url2 });
184
Class<?> target1 = Class.forName("p.C1", false, loader);
185
Class<?> target2 = Class.forName("p.C2", false, loader);
186
assertTrue(target1.getClassLoader() == loader);
187
assertTrue(target1.getClassLoader() == loader);
188
assertNotEquals(target1.getProtectionDomain(), target2.getProtectionDomain());
189
190
// protection domain 1
191
Lookup lookup1 = privateLookupIn(target1, lookup());
192
193
Class<?> clazz = lookup1.defineClass(generateClass("p.Foo"));
194
testSameAbode(clazz, lookup1.lookupClass());
195
testDiscoverable(clazz, lookup1);
196
197
// protection domain 2
198
Lookup lookup2 = privateLookupIn(target2, lookup());
199
200
clazz = lookup2.defineClass(generateClass("p.Bar"));
201
testSameAbode(clazz, lookup2.lookupClass());
202
testDiscoverable(clazz, lookup2);
203
}
204
205
/**
206
* Test defineClass defining a class to the boot loader
207
*/
208
@Test
209
public void testBootLoader() throws Exception {
210
Lookup lookup = privateLookupIn(Thread.class, lookup());
211
assertTrue(lookup.getClass().getClassLoader() == null);
212
213
Class<?> clazz = lookup.defineClass(generateClass("java.lang.Foo"));
214
assertEquals(clazz.getName(), "java.lang.Foo");
215
testSameAbode(clazz, Thread.class);
216
testDiscoverable(clazz, lookup);
217
}
218
219
@Test(expectedExceptions = { IllegalArgumentException.class })
220
public void testWrongPackage() throws Exception {
221
lookup().defineClass(generateClass("other.C"));
222
}
223
224
@Test(expectedExceptions = { IllegalAccessException.class })
225
public void testNoPackageAccess() throws Exception {
226
Lookup lookup = lookup().dropLookupMode(PACKAGE);
227
lookup.defineClass(generateClass(THIS_PACKAGE + ".C"));
228
}
229
230
@Test(expectedExceptions = { ClassFormatError.class })
231
public void testTruncatedClassFile() throws Exception {
232
lookup().defineClass(new byte[0]);
233
}
234
235
@Test(expectedExceptions = { NullPointerException.class })
236
public void testNull() throws Exception {
237
lookup().defineClass(null);
238
}
239
240
@Test(expectedExceptions = { NoClassDefFoundError.class })
241
public void testLinking() throws Exception {
242
lookup().defineClass(generateNonLinkableClass(THIS_PACKAGE + ".NonLinkableClass"));
243
}
244
245
@Test(expectedExceptions = { IllegalArgumentException.class })
246
public void testModuleInfo() throws Exception {
247
lookup().defineClass(generateModuleInfo());
248
}
249
250
/**
251
* Generates a class file with the given class name
252
*/
253
byte[] generateClass(String className) {
254
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
255
+ ClassWriter.COMPUTE_FRAMES);
256
cw.visit(V9,
257
ACC_PUBLIC + ACC_SUPER,
258
className.replace(".", "/"),
259
null,
260
"java/lang/Object",
261
null);
262
263
// <init>
264
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
265
mv.visitVarInsn(ALOAD, 0);
266
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
267
mv.visitInsn(RETURN);
268
mv.visitMaxs(0, 0);
269
mv.visitEnd();
270
271
cw.visitEnd();
272
return cw.toByteArray();
273
}
274
275
/**
276
* Generate a class file with the given class name. The class implements Runnable
277
* with a run method to invokestatic the given targetClass/targetMethod.
278
*/
279
byte[] generateRunner(String className,
280
String targetClass,
281
String targetMethod) throws Exception {
282
283
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
284
+ ClassWriter.COMPUTE_FRAMES);
285
cw.visit(V9,
286
ACC_PUBLIC + ACC_SUPER,
287
className.replace(".", "/"),
288
null,
289
"java/lang/Object",
290
new String[] { "java/lang/Runnable" });
291
292
// <init>
293
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
294
mv.visitVarInsn(ALOAD, 0);
295
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
296
mv.visitInsn(RETURN);
297
mv.visitMaxs(0, 0);
298
mv.visitEnd();
299
300
// run()
301
String tc = targetClass.replace(".", "/");
302
mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null);
303
mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false);
304
mv.visitInsn(RETURN);
305
mv.visitMaxs(0, 0);
306
mv.visitEnd();
307
308
cw.visitEnd();
309
return cw.toByteArray();
310
}
311
312
/**
313
* Generate a class file with the given class name. The class will initializer
314
* to invokestatic the given targetClass/targetMethod.
315
*/
316
byte[] generateClassWithInitializer(String className,
317
String targetClass,
318
String targetMethod) throws Exception {
319
320
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
321
+ ClassWriter.COMPUTE_FRAMES);
322
cw.visit(V9,
323
ACC_PUBLIC + ACC_SUPER,
324
className.replace(".", "/"),
325
null,
326
"java/lang/Object",
327
null);
328
329
// <init>
330
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
331
mv.visitVarInsn(ALOAD, 0);
332
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
333
mv.visitInsn(RETURN);
334
mv.visitMaxs(0, 0);
335
mv.visitEnd();
336
337
// <clinit>
338
String tc = targetClass.replace(".", "/");
339
mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
340
mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false);
341
mv.visitInsn(RETURN);
342
mv.visitMaxs(0, 0);
343
mv.visitEnd();
344
345
cw.visitEnd();
346
return cw.toByteArray();
347
}
348
349
/**
350
* Generates a non-linkable class file with the given class name
351
*/
352
byte[] generateNonLinkableClass(String className) {
353
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
354
+ ClassWriter.COMPUTE_FRAMES);
355
cw.visit(V14,
356
ACC_PUBLIC + ACC_SUPER,
357
className.replace(".", "/"),
358
null,
359
"MissingSuperClass",
360
null);
361
362
// <init>
363
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
364
mv.visitVarInsn(ALOAD, 0);
365
mv.visitMethodInsn(INVOKESPECIAL, "MissingSuperClass", "<init>", "()V", false);
366
mv.visitInsn(RETURN);
367
mv.visitMaxs(0, 0);
368
mv.visitEnd();
369
370
cw.visitEnd();
371
return cw.toByteArray();
372
}
373
374
/**
375
* Generates a class file with the given class name
376
*/
377
byte[] generateModuleInfo() {
378
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
379
+ ClassWriter.COMPUTE_FRAMES);
380
cw.visit(V14,
381
ACC_MODULE,
382
"module-info",
383
null,
384
null,
385
null);
386
387
cw.visitEnd();
388
return cw.toByteArray();
389
}
390
391
private int nextNumber() {
392
return ++nextNumber;
393
}
394
395
private int nextNumber;
396
}
397
398