Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/bcverify/clconstraints.c
5986 views
1
/*******************************************************************************
2
* Copyright (c) 1991, 2021 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
#include <string.h>
24
25
#include "j9cfg.h"
26
#include "j9protos.h"
27
#include "j9consts.h"
28
#include "rommeth.h"
29
#include "j9cp.h"
30
#include "j9modron.h"
31
#include "ut_j9bcverify.h"
32
#include "omrlinkedlist.h"
33
34
static J9ClassLoadingConstraint* findClassLoadingConstraint (J9VMThread* vmThread, J9ClassLoader* loader, U_8* name, UDATA length);
35
static J9ClassLoadingConstraint* registerClassLoadingConstraint (J9VMThread* vmThread, J9ClassLoader* loader, U_8* name, UDATA length, UDATA copyName);
36
static void validateArgs (J9VMThread* vmThread, J9ClassLoader* loader1, J9ClassLoader* loader2, U_8* name1, U_8* name2, UDATA length);
37
static void constrainList (J9ClassLoadingConstraint* constraint, J9Class* clazz);
38
static UDATA constraintHashFn(void *key, void *userData);
39
static UDATA constraintHashEqualFn(void *leftKey, void *rightKey, void *userData);
40
41
42
/* This is a helper function used by Assert_RTV_validateClassLoadingConstraints */
43
static void
44
validateArgs (J9VMThread* vmThread, J9ClassLoader* loader1, J9ClassLoader* loader2, U_8* name1, U_8* name2, UDATA length)
45
{
46
J9MemorySegment *seg;
47
48
Assert_RTV_notEqual(loader1, loader2);
49
Assert_RTV_true(0 == memcmp(name1, name2, length));
50
51
/* verify that the name is actually in the correct segment. If it's not, the name could get
52
* garbage collected while the constraint object is still alive
53
*/
54
seg = vmThread->javaVM->classMemorySegments->nextSegment;
55
while (seg) {
56
if (seg->heapBase <= name1 && seg->heapTop >= name1) {
57
Assert_RTV_true( (seg->classLoader == loader1) || (seg->classLoader->flags & J9CLASSLOADER_INVARIANTS_SHARABLE) );
58
}
59
if (seg->heapBase <= name2 && seg->heapTop >= name2) {
60
Assert_RTV_true( (seg->classLoader == loader2) || (seg->classLoader->flags & J9CLASSLOADER_INVARIANTS_SHARABLE) );
61
}
62
seg = seg->nextSegment;
63
}
64
}
65
66
67
/*
68
* sig1 must come from a ROMSegment in loader1.
69
* sig2 must come from a ROMSegment in loader2.
70
* sig1 and sig2 must contain identical bytes. The signatures may be method or field signatures.
71
* return 0 if no class loading constraints have been violated, or non-zero if they have been.
72
*/
73
UDATA
74
j9bcv_checkClassLoadingConstraintsForSignature (J9VMThread* vmThread, J9ClassLoader* loader1, J9ClassLoader* loader2, J9UTF8* sig1, J9UTF8* sig2)
75
{
76
U_32 index = 0, endIndex;
77
U_32 length = J9UTF8_LENGTH(sig1);
78
UDATA rc = 0;
79
J9JavaVM *javaVM = vmThread->javaVM;
80
JavaVM* jniVM = (JavaVM*)javaVM;
81
82
Trc_RTV_checkClassLoadingConstraintsForSignature_Entry(vmThread, loader1, loader2, sig1, sig2, J9UTF8_LENGTH(sig1), J9UTF8_DATA(sig1));
83
Assert_RTV_true(J9UTF8_LENGTH(sig1) == J9UTF8_LENGTH(sig2));
84
Assert_RTV_validateClassLoadingConstraints(vmThread, loader1, loader2, J9UTF8_DATA(sig1), J9UTF8_DATA(sig2), J9UTF8_LENGTH(sig1));
85
86
omrthread_monitor_enter(javaVM->classTableMutex);
87
for (;;) {
88
/* find a 'L', indicating the beginning of a class name */
89
while (index < length && J9UTF8_DATA(sig1)[index] != 'L') {
90
index++;
91
}
92
if (index >= length) {
93
break;
94
}
95
96
/* skip the 'L'; */
97
index++;
98
99
/* find the ';' marking the end of the class name */
100
endIndex = index;
101
while (J9UTF8_DATA(sig1)[endIndex] != ';') {
102
endIndex++;
103
}
104
105
rc = j9bcv_checkClassLoadingConstraintForName (vmThread, loader1, loader2, &J9UTF8_DATA(sig1)[index], &J9UTF8_DATA(sig2)[index], endIndex - index, FALSE);
106
if (rc) {
107
break;
108
}
109
110
index = endIndex;
111
}
112
omrthread_monitor_exit(javaVM->classTableMutex);
113
114
Trc_RTV_checkClassLoadingConstraintsForSignature_Exit(vmThread, rc);
115
116
return rc;
117
}
118
119
120
/* NOTE: the current thread must own the class table mutex */
121
122
UDATA
123
j9bcv_checkClassLoadingConstraintForName (J9VMThread* vmThread, J9ClassLoader* loader1, J9ClassLoader* loader2, U_8* name1, U_8* name2, UDATA length, UDATA copyUTFs)
124
{
125
J9Class *class1;
126
J9Class *class2;
127
J9ClassLoadingConstraint *const1 = NULL;
128
J9ClassLoadingConstraint *const2 = NULL;
129
J9InternalVMFunctions const *vmFuncs = vmThread->javaVM->internalVMFunctions;
130
131
Trc_RTV_checkClassLoadingConstraintForName(vmThread, loader1, loader2, length, name1);
132
Assert_RTV_validateClassLoadingConstraints(vmThread, loader1, loader2, name1, name2, length);
133
134
/* peek at the class tables to see if the class has been loaded yet */
135
class1 = vmFuncs->hashClassTableAt (loader1, name1, length);
136
class2 = vmFuncs->hashClassTableAt (loader2, name2, length);
137
138
if (class1 && class2) {
139
if (class1 != class2) {
140
return 1;
141
}
142
} else if (class1 == NULL && class2 != NULL) {
143
const1 = registerClassLoadingConstraint (vmThread, loader1, name1, length, copyUTFs);
144
if (const1 == NULL) return 1;
145
if (const1->clazz != NULL) {
146
if (const1->clazz != class2) {
147
return 1;
148
}
149
} else {
150
Assert_RTV_true(J9_ARE_NO_BITS_SET(class2->classFlags, J9ClassIsAnonymous));
151
const1->clazz = class2;
152
}
153
} else if (class2 == NULL && class1 != NULL) {
154
const2 = registerClassLoadingConstraint (vmThread, loader2, name2, length, copyUTFs);
155
if (const2->clazz != NULL) {
156
if (const2->clazz != class1) {
157
return 1;
158
}
159
} else {
160
const2->clazz = class1;
161
Assert_RTV_true(J9_ARE_NO_BITS_SET(class1->classFlags, J9ClassIsAnonymous));
162
}
163
} else { /* class1 == NULL && class2 == NULL */
164
J9ClassLoadingConstraint *tempNext;
165
J9ClassLoadingConstraint *tempPrevious;
166
167
const1 = registerClassLoadingConstraint (vmThread, loader1, name1, length, copyUTFs);
168
if (const1 == NULL) {
169
return 1;
170
}
171
const2 = registerClassLoadingConstraint (vmThread, loader2, name2, length, copyUTFs);
172
if (const2 == NULL) {
173
return 1;
174
}
175
176
if (const1->clazz != const2->clazz) {
177
/* need to merge two constraint chains with different constraints.
178
* This is only solvable if one of them is NULL
179
*/
180
if (const1->clazz == NULL) {
181
constrainList(const1, const2->clazz);
182
} else if (const2->clazz == NULL) {
183
constrainList(const2, const1->clazz);
184
} else {
185
/* both constraints are satisfied, but in an incompatible manner */
186
return 1;
187
}
188
}
189
190
/* now link them up, keeping in mind that one or either of them might have already been in a list */
191
tempNext = const1->linkNext;
192
tempPrevious = const2->linkPrevious;
193
const1->linkNext = const2;
194
const2->linkPrevious = const1;
195
tempNext->linkPrevious = tempPrevious;
196
tempPrevious->linkNext = tempNext;
197
}
198
199
return 0;
200
}
201
202
203
/* NOTE: the current thread must own the class table mutex */
204
205
static J9ClassLoadingConstraint*
206
registerClassLoadingConstraint (J9VMThread* vmThread, J9ClassLoader* loader, U_8* name, UDATA length, UDATA copyName)
207
{
208
PORT_ACCESS_FROM_VMC (vmThread);
209
J9JavaVM* vm = vmThread->javaVM;
210
J9ClassLoadingConstraint* constraint;
211
J9ClassLoadingConstraint exemplar;
212
213
Trc_RTV_registerClassLoadingConstraint_Entry(vmThread, length, name, loader);
214
215
if (vm->classLoadingConstraints == NULL) {
216
Trc_RTV_registerClassLoadingConstraint_AllocatingTable(vmThread);
217
vm->classLoadingConstraints = hashTableNew(OMRPORT_FROM_J9PORT(PORTLIB), J9_GET_CALLSITE(), 256, sizeof(J9ClassLoadingConstraint), sizeof(char *), 0, J9MEM_CATEGORY_CLASSES, constraintHashFn, constraintHashEqualFn, NULL, vm);
218
if (vm->classLoadingConstraints == NULL) {
219
Trc_RTV_registerClassLoadingConstraint_TableAllocationFailed(vmThread);
220
Trc_RTV_registerClassLoadingConstraint_Exit(vmThread, NULL);
221
return NULL;
222
}
223
}
224
225
exemplar.classLoader = loader;
226
exemplar.name = name;
227
exemplar.nameLength = length;
228
exemplar.clazz = NULL;
229
exemplar.linkNext = NULL;
230
exemplar.linkPrevious = NULL;
231
exemplar.freeName = FALSE;
232
233
constraint = hashTableAdd(vm->classLoadingConstraints, &exemplar);
234
if (constraint == NULL) {
235
oom:
236
Trc_RTV_registerClassLoadingConstraint_EntryAllocationFailed(vmThread);
237
} else if (constraint->linkNext == NULL) {
238
/* this must be a newly added constraint. Link it up to itself */
239
constraint->linkNext = constraint->linkPrevious = constraint;
240
if (copyName) {
241
U_8 *nameCopy = j9mem_allocate_memory(length, J9MEM_CATEGORY_CLASSES);
242
if (NULL == nameCopy) {
243
hashTableRemove(vm->classLoadingConstraints, constraint);
244
constraint = NULL;
245
goto oom;
246
}
247
memcpy(nameCopy, name, length);
248
constraint->name = nameCopy;
249
constraint->freeName = TRUE;
250
}
251
Trc_RTV_registerClassLoadingConstraint_AllocatedEntry(vmThread, constraint, length, name, loader);
252
}
253
254
Trc_RTV_registerClassLoadingConstraint_Exit(vmThread, constraint);
255
return constraint;
256
}
257
258
259
/* NOTE: the current thread must own the class table mutex */
260
261
static J9ClassLoadingConstraint*
262
findClassLoadingConstraint (J9VMThread* vmThread, J9ClassLoader* loader, U_8* name, UDATA length)
263
{
264
J9ClassLoadingConstraint *constraint = NULL;
265
J9JavaVM* vm = vmThread->javaVM;
266
267
Trc_RTV_findClassLoadingConstraint_Entry(vmThread, length, name, loader);
268
269
if (vm->classLoadingConstraints != NULL) {
270
J9ClassLoadingConstraint exemplar;
271
272
exemplar.classLoader = loader;
273
exemplar.name = name;
274
exemplar.nameLength = length;
275
exemplar.clazz = NULL;
276
exemplar.linkNext = NULL;
277
exemplar.linkPrevious = NULL;
278
279
constraint = hashTableFind(vm->classLoadingConstraints, &exemplar);
280
}
281
282
Trc_RTV_findClassLoadingConstraint_Exit(vmThread, constraint);
283
284
return constraint;
285
}
286
287
288
/* NOTE: this function must only be called while the current thread owns the class table mutex */
289
290
J9Class *
291
j9bcv_satisfyClassLoadingConstraint (J9VMThread* vmThread, J9ClassLoader* loader, J9Class* clazz)
292
{
293
J9ROMClass* romClass = clazz->romClass;
294
J9UTF8* name = J9ROMCLASS_CLASSNAME (romClass);
295
J9ClassLoadingConstraint* constraint = findClassLoadingConstraint (vmThread, loader, J9UTF8_DATA(name), J9UTF8_LENGTH(name));
296
297
if (constraint) {
298
if ((NULL != constraint->clazz) && (constraint->clazz != clazz)) {
299
return constraint->clazz;
300
} else {
301
J9ClassLoadingConstraint* root = constraint;
302
U_8 *nameToFree = constraint->freeName ? constraint->name : NULL;
303
constrainList (constraint, clazz);
304
J9_LINKED_LIST_REMOVE(root, constraint);
305
hashTableRemove (vmThread->javaVM->classLoadingConstraints, constraint);
306
if (NULL != nameToFree) {
307
PORT_ACCESS_FROM_VMC(vmThread);
308
j9mem_free_memory(nameToFree);
309
}
310
}
311
}
312
return NULL;
313
}
314
315
316
/*
317
* Called when class loaders are being unloaded. This function removes all of the dying loaders'
318
* constraints from linked lists of constraints, and removes references to classes defined by
319
* the dying loaders.
320
* The current thread should have exclusive VM access
321
*/
322
323
void
324
unlinkClassLoadingConstraints (J9JavaVM* jvm)
325
{
326
J9HashTableState walkState;
327
J9ClassLoadingConstraint* constraint;
328
329
Trc_RTV_unlinkClassLoadingConstraints_Entry();
330
331
if (jvm->classLoadingConstraints != NULL) {
332
PORT_ACCESS_FROM_JAVAVM(jvm);
333
constraint = hashTableStartDo(jvm->classLoadingConstraints, &walkState);
334
while (constraint != NULL) {
335
U_8 *nameToFree = constraint->freeName ? constraint->name : NULL;
336
if ((NULL == constraint->clazz) && (constraint->linkNext == constraint)) { /* no point in having a single empty element */
337
hashTableDoRemove(&walkState);
338
if (NULL != nameToFree) {
339
j9mem_free_memory(nameToFree);
340
}
341
} else if (J9_GC_CLASS_LOADER_DEAD == (constraint->classLoader->gcFlags & J9_GC_CLASS_LOADER_DEAD) ) {
342
/* this class loader is being unloaded. Remove the constraint from the linked list */
343
J9ClassLoadingConstraint* root = constraint;
344
J9_LINKED_LIST_REMOVE(root, constraint);
345
hashTableDoRemove(&walkState);
346
if (NULL != nameToFree) {
347
j9mem_free_memory(nameToFree);
348
}
349
} else {
350
/* mark the constraint as unsatisfied if it refers to a dying loader */
351
J9Class* clazz = constraint->clazz;
352
353
if ((NULL != clazz) && (J9AccClassDying == (J9CLASS_FLAGS(clazz) & J9AccClassDying))) {
354
constraint->clazz = NULL;
355
}
356
}
357
358
constraint = hashTableNextDo(&walkState);
359
}
360
}
361
362
Trc_RTV_unlinkClassLoadingConstraints_Exit();
363
}
364
365
366
/*
367
* Set the 'clazz' field of every J9ClassLoadingConstraint in the circular list to be clazz.
368
*/
369
static void
370
constrainList (J9ClassLoadingConstraint* constraint, J9Class* clazz)
371
{
372
J9ClassLoadingConstraint* cursor = constraint;
373
374
Assert_RTV_true(J9_ARE_NO_BITS_SET(clazz->classFlags, J9ClassIsAnonymous));
375
while (NULL != cursor) {
376
cursor->clazz = clazz;
377
cursor = J9_LINKED_LIST_NEXT_DO(constraint, cursor);
378
}
379
}
380
381
static UDATA
382
constraintHashFn(void *key, void *userData)
383
{
384
J9ClassLoadingConstraint *k = key;
385
J9JavaVM *vm = userData;
386
UDATA utf8Hash = J9_VM_FUNCTION_VIA_JAVAVM(vm, computeHashForUTF8)(k->name, k->nameLength);
387
388
return (UDATA)k->classLoader ^ utf8Hash;
389
}
390
391
392
static UDATA
393
constraintHashEqualFn(void *leftKey, void *rightKey, void *userData)
394
{
395
J9ClassLoadingConstraint *left_k = leftKey;
396
J9ClassLoadingConstraint *right_k = rightKey;
397
J9JavaVM *vm = userData;
398
399
return
400
(left_k->classLoader == right_k->classLoader)
401
&& (J9UTF8_DATA_EQUALS(left_k->name, left_k->nameLength, right_k->name, right_k->nameLength));
402
}
403
404
405