Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/bcverify/classrelationships.c
5986 views
1
/*******************************************************************************
2
* Copyright (c) 2019, 2019 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of thse 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 "j9protos.h"
24
#include "j9consts.h"
25
#include "ut_j9bcverify.h"
26
#include "omrlinkedlist.h"
27
28
static VMINLINE J9ClassRelationshipNode *allocateParentNode(J9VMThread *vmThread, U_8 *className, UDATA classNameLength);
29
static VMINLINE J9ClassRelationship *findClassRelationship(J9VMThread *vmThread, J9ClassLoader *classLoader, U_8 *className, UDATA classNameLength);
30
static void freeClassRelationshipParentNodes(J9VMThread *vmThread, J9ClassLoader *classLoader, J9ClassRelationship *relationship);
31
static UDATA relationshipHashFn(void *key, void *userData);
32
static UDATA relationshipHashEqualFn(void *leftKey, void *rightKey, void *userData);
33
34
/**
35
* Record a class relationship in the class relationships table.
36
*
37
* Returns TRUE if successful and FALSE if an out of memory error occurs.
38
*/
39
IDATA
40
j9bcv_recordClassRelationship(J9VMThread *vmThread, J9ClassLoader *classLoader, U_8 *childName, UDATA childNameLength, U_8 *parentName, UDATA parentNameLength, IDATA *reasonCode)
41
{
42
PORT_ACCESS_FROM_VMC(vmThread);
43
J9JavaVM *vm = vmThread->javaVM;
44
J9ClassRelationship *childEntry = NULL;
45
J9ClassRelationshipNode *parentNode = NULL;
46
J9ClassRelationship child = {0};
47
IDATA recordResult = FALSE;
48
*reasonCode = BCV_ERR_INSUFFICIENT_MEMORY;
49
50
Trc_RTV_recordClassRelationship_Entry(vmThread, childNameLength, childName, parentNameLength, parentName);
51
52
Assert_RTV_true((NULL != childName) && (NULL != parentName));
53
54
/* Locate existing childEntry or add new entry to the hashtable */
55
childEntry = findClassRelationship(vmThread, classLoader, childName, childNameLength);
56
57
if (NULL == childEntry) {
58
child.className = (U_8 *) j9mem_allocate_memory(childNameLength + 1, J9MEM_CATEGORY_CLASSES);
59
60
/* className for child successfully allocated, continue initialization of child entry */
61
if (NULL != child.className) {
62
memcpy(child.className, childName, childNameLength);
63
child.className[childNameLength] = '\0';
64
child.classNameLength = childNameLength;
65
child.flags = 0;
66
67
childEntry = hashTableAdd(classLoader->classRelationshipsHashTable, &child);
68
69
if (NULL == childEntry) {
70
Trc_RTV_recordClassRelationship_EntryAllocationFailedChild(vmThread);
71
j9mem_free_memory(child.className);
72
goto recordDone;
73
}
74
} else {
75
Trc_RTV_recordClassRelationship_EntryAllocationFailedChild(vmThread);
76
goto recordDone;
77
}
78
}
79
80
/* If the parent is java/lang/Throwable, set a flag instead of allocating a node */
81
if (J9UTF8_DATA_EQUALS(J9RELATIONSHIP_JAVA_LANG_THROWABLE_STRING, J9RELATIONSHIP_JAVA_LANG_THROWABLE_STRING_LENGTH, parentName, parentNameLength)) {
82
if (!J9_ARE_ANY_BITS_SET(childEntry->flags, J9RELATIONSHIP_PARENT_IS_THROWABLE)) {
83
childEntry->flags |= J9RELATIONSHIP_PARENT_IS_THROWABLE;
84
}
85
} else {
86
/* Add a parentNode to the child's linked list of parents */
87
if (J9_LINKED_LIST_IS_EMPTY(childEntry->root)) {
88
parentNode = allocateParentNode(vmThread, parentName, parentNameLength);
89
if (parentNode == NULL) {
90
/* Allocation failure */
91
Trc_RTV_classRelationships_AllocationFailedParent(vmThread);
92
goto recordDone;
93
}
94
Trc_RTV_recordClassRelationship_AllocatedEntry(vmThread, childEntry->classNameLength, childEntry->className, childEntry, parentNode->classNameLength, parentNode->className, parentNode);
95
J9_LINKED_LIST_ADD_LAST(childEntry->root, parentNode);
96
} else {
97
BOOLEAN alreadyPresent = FALSE;
98
BOOLEAN addBefore = FALSE;
99
J9ClassRelationshipNode *walk = J9_LINKED_LIST_START_DO(childEntry->root);
100
/**
101
* Keep the list of parent nodes ordered by class name length so it's a faster traversal
102
* and duplicates can be avoided
103
*/
104
while (NULL != walk) {
105
if (walk->classNameLength > parentNameLength) {
106
addBefore = TRUE;
107
break;
108
} else if (J9UTF8_DATA_EQUALS(walk->className, walk->classNameLength, parentName, parentNameLength)) {
109
/* Already present, skip */
110
alreadyPresent = TRUE;
111
break;
112
} else {
113
/* walk->className is shorter or equal length but different data; keep looking */
114
}
115
walk = J9_LINKED_LIST_NEXT_DO(childEntry->root, walk);
116
}
117
if (!alreadyPresent) {
118
parentNode = allocateParentNode(vmThread, parentName, parentNameLength);
119
if (parentNode == NULL) {
120
/* Allocation failure */
121
Trc_RTV_classRelationships_AllocationFailedParent(vmThread);
122
goto recordDone;
123
}
124
Trc_RTV_recordClassRelationship_AllocatedEntry(vmThread, childEntry->classNameLength, childEntry->className, childEntry, parentNode->classNameLength, parentNode->className, parentNode);
125
if (addBefore) {
126
J9_LINKED_LIST_ADD_BEFORE(childEntry->root, walk, parentNode);
127
} else {
128
/* If got through the whole list of shorter or equal length names, add it here */
129
J9_LINKED_LIST_ADD_LAST(childEntry->root, parentNode);
130
}
131
}
132
}
133
}
134
135
recordResult = TRUE;
136
*reasonCode = 0;
137
138
recordDone:
139
Trc_RTV_recordClassRelationship_Exit(vmThread, recordResult);
140
return recordResult;
141
}
142
143
/**
144
* Validate each recorded relationship for a class.
145
*
146
* Returns failedClass, which is NULL if successful, or the class that fails validation if unsuccessful.
147
*/
148
J9Class *
149
j9bcv_validateClassRelationships(J9VMThread *vmThread, J9ClassLoader *classLoader, U_8 *childName, UDATA childNameLength, J9Class *childClass)
150
{
151
PORT_ACCESS_FROM_VMC(vmThread);
152
J9Class *parentClass = NULL;
153
J9Class *failedClass = NULL;
154
J9ClassRelationship *childEntry = NULL;
155
J9ClassRelationshipNode *parentNode = NULL;
156
157
Trc_RTV_validateClassRelationships_Entry(vmThread, childNameLength, childName);
158
Assert_RTV_true(NULL != childName);
159
childEntry = findClassRelationship(vmThread, classLoader, childName, childNameLength);
160
161
/* No relationships were recorded for the class (in this class loader), or its relationships have already been verified */
162
if (NULL == childEntry) {
163
goto validateDone;
164
}
165
166
/* The class is invalid if it has been marked as an interface, but it actually isn't */
167
if (J9_ARE_ANY_BITS_SET(childEntry->flags, J9RELATIONSHIP_MUST_BE_INTERFACE)) {
168
Trc_RTV_validateClassRelationships_FlaggedAsInterface(vmThread, childNameLength, childName);
169
if (!J9ROMCLASS_IS_INTERFACE(childClass->romClass)) {
170
Trc_RTV_validateClassRelationships_ShouldBeInterface(vmThread, childNameLength, childName);
171
failedClass = childClass;
172
goto validateDone;
173
}
174
}
175
176
/* If J9RELATIONSHIP_PARENT_IS_THROWABLE is set, check that the relationship holds */
177
if (J9_ARE_ANY_BITS_SET(childEntry->flags, J9RELATIONSHIP_PARENT_IS_THROWABLE)) {
178
/* Throwable will already be loaded since it is a required class J9VMCONSTANTPOOL_JAVALANGTHROWABLE */
179
parentClass = J9VMJAVALANGTHROWABLE_OR_NULL(vmThread->javaVM);
180
Assert_RTV_true(NULL != parentClass);
181
if (isSameOrSuperClassOf(parentClass, childClass)) {
182
Trc_RTV_validateClassRelationships_ParentIsSuperClass(vmThread, J9RELATIONSHIP_JAVA_LANG_THROWABLE_STRING_LENGTH, J9RELATIONSHIP_JAVA_LANG_THROWABLE_STRING, NULL);
183
} else {
184
/* The class is invalid since it doesn't hold the expected relationship with java/lang/Throwable */
185
Trc_RTV_validateClassRelationships_InvalidRelationship(vmThread, J9RELATIONSHIP_JAVA_LANG_THROWABLE_STRING_LENGTH, J9RELATIONSHIP_JAVA_LANG_THROWABLE_STRING);
186
failedClass = parentClass;
187
goto validateDone;
188
}
189
}
190
191
parentNode = J9_LINKED_LIST_START_DO(childEntry->root);
192
193
while (NULL != parentNode) {
194
/* Find the parent class in the loaded classes table */
195
parentClass = J9_VM_FUNCTION(vmThread, hashClassTableAt)(classLoader, parentNode->className, parentNode->classNameLength);
196
197
/* If the parent class has not been loaded, then it has to be an interface since the child is already loaded */
198
if (NULL == parentClass) {
199
/* Add a new relationship to the table if one doesn't already exist and flag the parentClass as J9RELATIONSHIP_MUST_BE_INTERFACE */
200
J9ClassRelationship *parentEntry = findClassRelationship(vmThread, classLoader, parentNode->className, parentNode->classNameLength);
201
202
Trc_RTV_validateClassRelationships_ParentNotLoaded(vmThread, parentNode->classNameLength, parentNode->className, parentNode);
203
204
if (NULL == parentEntry) {
205
J9ClassRelationship parent = {0};
206
PORT_ACCESS_FROM_VMC(vmThread);
207
parent.className = (U_8 *) j9mem_allocate_memory(parentNode->classNameLength + 1, J9MEM_CATEGORY_CLASSES);
208
209
/* className for parent successfully allocated, continue initialization of parent entry */
210
if (NULL != parent.className) {
211
Trc_RTV_validateClassRelationships_AllocatingParent(vmThread);
212
memcpy(parent.className, parentNode->className, parentNode->classNameLength);
213
parent.className[parentNode->classNameLength] = '\0';
214
parent.classNameLength = parentNode->classNameLength;
215
parent.flags = J9RELATIONSHIP_MUST_BE_INTERFACE;
216
217
parentEntry = hashTableAdd(classLoader->classRelationshipsHashTable, &parent);
218
219
if (NULL == parentEntry) {
220
Trc_RTV_classRelationships_AllocationFailedParent(vmThread);
221
j9mem_free_memory(parent.className);
222
failedClass = childClass;
223
goto validateDone;
224
}
225
Trc_RTV_validateClassRelationships_AllocatedParentEntry(vmThread);
226
} else {
227
Trc_RTV_classRelationships_AllocationFailedParent(vmThread);
228
failedClass = childClass;
229
goto validateDone;
230
}
231
} else {
232
parentEntry->flags |= J9RELATIONSHIP_MUST_BE_INTERFACE;
233
}
234
} else {
235
/* The already loaded parentClass should either be an interface, or is the same or superclass of the childClass */
236
if (J9ROMCLASS_IS_INTERFACE(parentClass->romClass)) {
237
/* If the target is an interface, be permissive as per the verifier type checking rules */
238
Trc_RTV_validateClassRelationships_ParentIsInterface(vmThread, parentNode->classNameLength, parentNode->className, parentNode);
239
} else if (isSameOrSuperClassOf(parentClass, childClass)) {
240
Trc_RTV_validateClassRelationships_ParentIsSuperClass(vmThread, parentNode->classNameLength, parentNode->className, parentNode);
241
} else {
242
/* The child and parent have an invalid relationship */
243
Trc_RTV_validateClassRelationships_InvalidRelationship(vmThread, parentNode->classNameLength, parentNode->className);
244
failedClass = parentClass;
245
goto validateDone;
246
}
247
}
248
parentNode = J9_LINKED_LIST_NEXT_DO(childEntry->root, parentNode);
249
}
250
251
/* Successful validation; free memory for childEntry */
252
freeClassRelationshipParentNodes(vmThread, classLoader, childEntry);
253
j9mem_free_memory(childEntry->className);
254
hashTableRemove(classLoader->classRelationshipsHashTable, childEntry);
255
256
validateDone:
257
Trc_RTV_validateClassRelationships_Exit(vmThread, failedClass);
258
return failedClass;
259
}
260
261
/**
262
* Add a parentNode to a child entry's linked list of parents.
263
*
264
* Return the allocated J9ClassRelationshipNode.
265
*/
266
static VMINLINE J9ClassRelationshipNode *
267
allocateParentNode(J9VMThread *vmThread, U_8 *className, UDATA classNameLength)
268
{
269
PORT_ACCESS_FROM_VMC(vmThread);
270
J9ClassRelationshipNode *parentNode = (J9ClassRelationshipNode *) j9mem_allocate_memory(sizeof(J9ClassRelationshipNode), J9MEM_CATEGORY_CLASSES);
271
272
if (NULL != parentNode) {
273
parentNode->className = (U_8 *) j9mem_allocate_memory(classNameLength + 1, J9MEM_CATEGORY_CLASSES);
274
275
if (NULL != parentNode->className) {
276
memcpy(parentNode->className, className, classNameLength);
277
parentNode->className[classNameLength] = '\0';
278
parentNode->classNameLength = classNameLength;
279
} else {
280
j9mem_free_memory(parentNode);
281
parentNode = NULL;
282
}
283
}
284
285
return parentNode;
286
}
287
288
/**
289
* Find the class relationship table entry for a particular class.
290
*
291
* Returns the found J9ClassRelationship, or NULL if it is not found.
292
*/
293
static VMINLINE J9ClassRelationship *
294
findClassRelationship(J9VMThread *vmThread, J9ClassLoader *classLoader, U_8 *className, UDATA classNameLength)
295
{
296
J9ClassRelationship *classEntry = NULL;
297
J9JavaVM *vm = vmThread->javaVM;
298
299
Trc_RTV_findClassRelationship_Entry(vmThread, classNameLength, className);
300
301
if (NULL != classLoader->classRelationshipsHashTable) {
302
J9ClassRelationship exemplar = {0};
303
exemplar.className = className;
304
exemplar.classNameLength = classNameLength;
305
classEntry = hashTableFind(classLoader->classRelationshipsHashTable, &exemplar);
306
}
307
308
Trc_RTV_findClassRelationship_Exit(vmThread, classEntry);
309
return classEntry;
310
}
311
312
/**
313
* Free allocated memory for each parent class node of a class relationship table entry.
314
*/
315
static void
316
freeClassRelationshipParentNodes(J9VMThread *vmThread, J9ClassLoader *classLoader, J9ClassRelationship *relationship)
317
{
318
PORT_ACCESS_FROM_VMC(vmThread);
319
J9ClassRelationshipNode *parentNode = NULL;
320
321
Trc_RTV_freeClassRelationshipParentNodes_Entry(vmThread, relationship->classNameLength, relationship->className);
322
323
while (NULL != relationship->root) {
324
parentNode = relationship->root;
325
Trc_RTV_freeClassRelationshipParentNodes_Parent(vmThread, parentNode->classNameLength, parentNode->className);
326
J9_LINKED_LIST_REMOVE(relationship->root, parentNode);
327
j9mem_free_memory(parentNode->className);
328
j9mem_free_memory(parentNode);
329
}
330
331
Trc_RTV_freeClassRelationshipParentNodes_Exit(vmThread);
332
return;
333
}
334
335
/**
336
* Allocates new hash table to store class relationship entries.
337
*
338
* Returns 0 if successful, and 1 otherwise.
339
*/
340
UDATA
341
j9bcv_hashClassRelationshipTableNew(J9ClassLoader *classLoader, J9JavaVM *vm)
342
{
343
UDATA result = 0;
344
345
/* Allocate classRelationshipsHashTable if -XX:+ClassRelationshipVerifier is used */
346
if (J9_ARE_ANY_BITS_SET(vm->extendedRuntimeFlags2, J9_EXTENDED_RUNTIME2_ENABLE_CLASS_RELATIONSHIP_VERIFIER)) {
347
classLoader->classRelationshipsHashTable = hashTableNew(OMRPORT_FROM_J9PORT(vm->portLibrary), J9_GET_CALLSITE(), 256, sizeof(J9ClassRelationship), sizeof(char *), 0, J9MEM_CATEGORY_CLASSES, relationshipHashFn, relationshipHashEqualFn, NULL, vm);
348
349
if (NULL == classLoader->classRelationshipsHashTable) {
350
result = 1;
351
}
352
}
353
354
return result;
355
}
356
357
/**
358
* Frees memory for each J9ClassRelationship table entry, J9ClassRelationshipNode,
359
* and the classRelationships hash table itself.
360
*/
361
void
362
j9bcv_hashClassRelationshipTableFree(J9VMThread *vmThread, J9ClassLoader *classLoader, J9JavaVM *vm)
363
{
364
/* Free the class relationships hash table if -XX:+ClassRelationshipVerifier is used */
365
if (J9_ARE_ANY_BITS_SET(vm->extendedRuntimeFlags2, J9_EXTENDED_RUNTIME2_ENABLE_CLASS_RELATIONSHIP_VERIFIER)) {
366
PORT_ACCESS_FROM_VMC(vmThread);
367
J9HashTableState hashTableState = {0};
368
J9HashTable *classRelationshipsHashTable = classLoader->classRelationshipsHashTable;
369
J9ClassRelationship *relationshipEntryStart = (J9ClassRelationship *) hashTableStartDo(classRelationshipsHashTable, &hashTableState);
370
J9ClassRelationship *relationshipEntry = relationshipEntryStart;
371
372
/* Free all parent nodes of a relationship entry and then the entry itself */
373
while (NULL != relationshipEntry) {
374
UDATA result = 0;
375
freeClassRelationshipParentNodes(vmThread, classLoader, relationshipEntry);
376
j9mem_free_memory(relationshipEntry->className);
377
result = hashTableDoRemove(&hashTableState);
378
Assert_RTV_true(0 == result);
379
relationshipEntry = (J9ClassRelationship *) hashTableNextDo(&hashTableState);
380
}
381
}
382
383
return;
384
}
385
386
static UDATA
387
relationshipHashFn(void *key, void *userData)
388
{
389
J9ClassRelationship *relationshipKey = key;
390
J9JavaVM *vm = userData;
391
392
UDATA utf8HashClass = J9_VM_FUNCTION_VIA_JAVAVM(vm, computeHashForUTF8)(relationshipKey->className, relationshipKey->classNameLength);
393
394
return utf8HashClass;
395
}
396
397
static UDATA
398
relationshipHashEqualFn(void *leftKey, void *rightKey, void *userData)
399
{
400
J9ClassRelationship *left_relationshipKey = leftKey;
401
J9ClassRelationship *right_relationshipKey = rightKey;
402
403
UDATA classNameEqual = J9UTF8_DATA_EQUALS(left_relationshipKey->className, left_relationshipKey->classNameLength, right_relationshipKey->className, right_relationshipKey->classNameLength);
404
405
return classNameEqual;
406
}
407
408