Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.instrument/share/native/libinstrument/JavaExceptions.c
41149 views
1
/*
2
* Copyright (c) 2003, 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. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
/*
27
* Copyright 2003 Wily Technology, Inc.
28
*/
29
30
#include <jni.h>
31
#include <jvmti.h>
32
33
#include "JPLISAssert.h"
34
#include "Utilities.h"
35
#include "JavaExceptions.h"
36
37
/**
38
* This module contains utility routines for manipulating Java throwables
39
* and JNIEnv throwable state from native code.
40
*/
41
42
static jthrowable sFallbackInternalError = NULL;
43
44
/*
45
* Local forward declarations.
46
*/
47
48
/* insist on having a throwable. If we already have one, return it.
49
* If not, map to fallback
50
*/
51
jthrowable
52
forceFallback(jthrowable potentialException);
53
54
55
jthrowable
56
forceFallback(jthrowable potentialException) {
57
if ( potentialException == NULL ) {
58
return sFallbackInternalError;
59
}
60
else {
61
return potentialException;
62
}
63
}
64
65
/**
66
* Returns true if it properly sets up a fallback exception
67
*/
68
jboolean
69
initializeFallbackError(JNIEnv* jnienv) {
70
jplis_assert(isSafeForJNICalls(jnienv));
71
sFallbackInternalError = createInternalError(jnienv, NULL);
72
jplis_assert(isSafeForJNICalls(jnienv));
73
return (sFallbackInternalError != NULL);
74
}
75
76
77
/*
78
* Map everything to InternalError.
79
*/
80
jthrowable
81
mapAllCheckedToInternalErrorMapper( JNIEnv * jnienv,
82
jthrowable throwableToMap) {
83
jthrowable mappedThrowable = NULL;
84
jstring message = NULL;
85
86
jplis_assert(throwableToMap != NULL);
87
jplis_assert(isSafeForJNICalls(jnienv));
88
jplis_assert(!isUnchecked(jnienv, throwableToMap));
89
90
message = getMessageFromThrowable(jnienv, throwableToMap);
91
mappedThrowable = createInternalError(jnienv, message);
92
93
jplis_assert(isSafeForJNICalls(jnienv));
94
return mappedThrowable;
95
}
96
97
98
jboolean
99
checkForThrowable( JNIEnv* jnienv) {
100
return (*jnienv)->ExceptionCheck(jnienv);
101
}
102
103
jboolean
104
isSafeForJNICalls( JNIEnv * jnienv) {
105
return !(*jnienv)->ExceptionCheck(jnienv);
106
}
107
108
109
void
110
logThrowable( JNIEnv * jnienv) {
111
if ( checkForThrowable(jnienv) ) {
112
(*jnienv)->ExceptionDescribe(jnienv);
113
}
114
}
115
116
117
118
/**
119
* Creates an exception or error with the fully qualified classname (ie java/lang/Error)
120
* and message passed to its constructor
121
*/
122
jthrowable
123
createThrowable( JNIEnv * jnienv,
124
const char * className,
125
jstring message) {
126
jthrowable exception = NULL;
127
jmethodID constructor = NULL;
128
jclass exceptionClass = NULL;
129
jboolean errorOutstanding = JNI_FALSE;
130
131
jplis_assert(className != NULL);
132
jplis_assert(isSafeForJNICalls(jnienv));
133
134
/* create new VMError with message from exception */
135
exceptionClass = (*jnienv)->FindClass(jnienv, className);
136
errorOutstanding = checkForAndClearThrowable(jnienv);
137
jplis_assert(!errorOutstanding);
138
139
if (!errorOutstanding) {
140
constructor = (*jnienv)->GetMethodID( jnienv,
141
exceptionClass,
142
"<init>",
143
"(Ljava/lang/String;)V");
144
errorOutstanding = checkForAndClearThrowable(jnienv);
145
jplis_assert(!errorOutstanding);
146
}
147
148
if (!errorOutstanding) {
149
exception = (*jnienv)->NewObject(jnienv, exceptionClass, constructor, message);
150
errorOutstanding = checkForAndClearThrowable(jnienv);
151
jplis_assert(!errorOutstanding);
152
}
153
154
jplis_assert(isSafeForJNICalls(jnienv));
155
return exception;
156
}
157
158
jthrowable
159
createInternalError(JNIEnv * jnienv, jstring message) {
160
return createThrowable( jnienv,
161
"java/lang/InternalError",
162
message);
163
}
164
165
jthrowable
166
createThrowableFromJVMTIErrorCode(JNIEnv * jnienv, jvmtiError errorCode) {
167
const char * throwableClassName = NULL;
168
const char * message = NULL;
169
jstring messageString = NULL;
170
171
switch ( errorCode ) {
172
case JVMTI_ERROR_NULL_POINTER:
173
throwableClassName = "java/lang/NullPointerException";
174
break;
175
176
case JVMTI_ERROR_ILLEGAL_ARGUMENT:
177
throwableClassName = "java/lang/IllegalArgumentException";
178
break;
179
180
case JVMTI_ERROR_OUT_OF_MEMORY:
181
throwableClassName = "java/lang/OutOfMemoryError";
182
break;
183
184
case JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION:
185
throwableClassName = "java/lang/ClassCircularityError";
186
break;
187
188
case JVMTI_ERROR_FAILS_VERIFICATION:
189
throwableClassName = "java/lang/VerifyError";
190
break;
191
192
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED:
193
throwableClassName = "java/lang/UnsupportedOperationException";
194
message = "class redefinition failed: attempted to add a method";
195
break;
196
197
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED:
198
throwableClassName = "java/lang/UnsupportedOperationException";
199
message = "class redefinition failed: attempted to change the schema (add/remove fields)";
200
break;
201
202
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED:
203
throwableClassName = "java/lang/UnsupportedOperationException";
204
message = "class redefinition failed: attempted to change superclass or interfaces";
205
break;
206
207
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED:
208
throwableClassName = "java/lang/UnsupportedOperationException";
209
message = "class redefinition failed: attempted to delete a method";
210
break;
211
212
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED:
213
throwableClassName = "java/lang/UnsupportedOperationException";
214
message = "class redefinition failed: attempted to change the class modifiers";
215
break;
216
217
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED:
218
throwableClassName = "java/lang/UnsupportedOperationException";
219
message = "class redefinition failed: attempted to change the class NestHost, NestMembers, Record, or PermittedSubclasses attribute";
220
break;
221
222
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:
223
throwableClassName = "java/lang/UnsupportedOperationException";
224
message = "class redefinition failed: attempted to change method modifiers";
225
break;
226
227
case JVMTI_ERROR_UNSUPPORTED_VERSION:
228
throwableClassName = "java/lang/UnsupportedClassVersionError";
229
break;
230
231
case JVMTI_ERROR_NAMES_DONT_MATCH:
232
throwableClassName = "java/lang/NoClassDefFoundError";
233
message = "class names don't match";
234
break;
235
236
case JVMTI_ERROR_INVALID_CLASS_FORMAT:
237
throwableClassName = "java/lang/ClassFormatError";
238
break;
239
240
case JVMTI_ERROR_UNMODIFIABLE_CLASS:
241
throwableClassName = "java/lang/instrument/UnmodifiableClassException";
242
break;
243
244
case JVMTI_ERROR_INVALID_CLASS:
245
throwableClassName = "java/lang/InternalError";
246
message = "class redefinition failed: invalid class";
247
break;
248
249
case JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED:
250
throwableClassName = "java/lang/UnsupportedOperationException";
251
message = "unsupported operation";
252
break;
253
254
case JVMTI_ERROR_INTERNAL:
255
default:
256
throwableClassName = "java/lang/InternalError";
257
break;
258
}
259
260
if ( message != NULL ) {
261
jboolean errorOutstanding;
262
263
messageString = (*jnienv)->NewStringUTF(jnienv, message);
264
errorOutstanding = checkForAndClearThrowable(jnienv);
265
jplis_assert_msg(!errorOutstanding, "can't create exception java string");
266
}
267
return createThrowable( jnienv,
268
throwableClassName,
269
messageString);
270
271
}
272
273
274
/**
275
* Calls toString() on the given message which is the same call made by
276
* Exception when passed a throwable to its constructor
277
*/
278
jstring
279
getMessageFromThrowable( JNIEnv* jnienv,
280
jthrowable exception) {
281
jclass exceptionClass = NULL;
282
jmethodID method = NULL;
283
jstring message = NULL;
284
jboolean errorOutstanding = JNI_FALSE;
285
286
jplis_assert(isSafeForJNICalls(jnienv));
287
288
/* call getMessage on exception */
289
exceptionClass = (*jnienv)->GetObjectClass(jnienv, exception);
290
errorOutstanding = checkForAndClearThrowable(jnienv);
291
jplis_assert(!errorOutstanding);
292
293
if (!errorOutstanding) {
294
method = (*jnienv)->GetMethodID(jnienv,
295
exceptionClass,
296
"toString",
297
"()Ljava/lang/String;");
298
errorOutstanding = checkForAndClearThrowable(jnienv);
299
jplis_assert(!errorOutstanding);
300
}
301
302
if (!errorOutstanding) {
303
message = (*jnienv)->CallObjectMethod(jnienv, exception, method);
304
errorOutstanding = checkForAndClearThrowable(jnienv);
305
jplis_assert(!errorOutstanding);
306
}
307
308
jplis_assert(isSafeForJNICalls(jnienv));
309
310
return message;
311
}
312
313
314
/**
315
* Returns whether the exception given is an unchecked exception:
316
* a subclass of Error or RuntimeException
317
*/
318
jboolean
319
isUnchecked( JNIEnv* jnienv,
320
jthrowable exception) {
321
jboolean result = JNI_FALSE;
322
323
jplis_assert(isSafeForJNICalls(jnienv));
324
result = (exception == NULL) ||
325
isInstanceofClassName(jnienv, exception, "java/lang/Error") ||
326
isInstanceofClassName(jnienv, exception, "java/lang/RuntimeException");
327
jplis_assert(isSafeForJNICalls(jnienv));
328
return result;
329
}
330
331
/*
332
* Returns the current throwable, if any. Clears the throwable state.
333
* Clients can use this to preserve the current throwable state on the stack.
334
*/
335
jthrowable
336
preserveThrowable(JNIEnv * jnienv) {
337
jthrowable result = (*jnienv)->ExceptionOccurred(jnienv);
338
if ( result != NULL ) {
339
(*jnienv)->ExceptionClear(jnienv);
340
}
341
return result;
342
}
343
344
/*
345
* Installs the supplied throwable into the JNIEnv if the throwable is not null.
346
* Clients can use this to preserve the current throwable state on the stack.
347
*/
348
void
349
restoreThrowable( JNIEnv * jnienv,
350
jthrowable preservedException) {
351
throwThrowable( jnienv,
352
preservedException);
353
return;
354
}
355
356
void
357
throwThrowable( JNIEnv * jnienv,
358
jthrowable exception) {
359
if ( exception != NULL ) {
360
jint result = (*jnienv)->Throw(jnienv, exception);
361
jplis_assert_msg(result == JNI_OK, "throwThrowable failed to re-throw");
362
}
363
return;
364
}
365
366
367
/*
368
* Always clears the JNIEnv throwable state. Returns true if an exception was present
369
* before the clearing operation.
370
*/
371
jboolean
372
checkForAndClearThrowable( JNIEnv * jnienv) {
373
jboolean result = (*jnienv)->ExceptionCheck(jnienv);
374
if ( result ) {
375
(*jnienv)->ExceptionClear(jnienv);
376
}
377
return result;
378
}
379
380
/* creates a java.lang.InternalError and installs it into the JNIEnv */
381
void
382
createAndThrowInternalError(JNIEnv * jnienv) {
383
jthrowable internalError = createInternalError( jnienv, NULL);
384
throwThrowable(jnienv, forceFallback(internalError));
385
}
386
387
void
388
createAndThrowThrowableFromJVMTIErrorCode(JNIEnv * jnienv, jvmtiError errorCode) {
389
jthrowable throwable = createThrowableFromJVMTIErrorCode(jnienv, errorCode);
390
throwThrowable(jnienv, forceFallback(throwable));
391
}
392
393
void
394
mapThrownThrowableIfNecessary( JNIEnv * jnienv,
395
CheckedExceptionMapper mapper) {
396
jthrowable originalThrowable = NULL;
397
jthrowable resultThrowable = NULL;
398
399
originalThrowable = preserveThrowable(jnienv);
400
401
/* the throwable is now cleared, so JNI calls are safe */
402
if ( originalThrowable != NULL ) {
403
/* if there is an exception: we can just throw it if it is unchecked. If checked,
404
* we need to map it (mapper is conditional, will vary by usage, hence the callback)
405
*/
406
if ( isUnchecked(jnienv, originalThrowable) ) {
407
resultThrowable = originalThrowable;
408
}
409
else {
410
resultThrowable = (*mapper) (jnienv, originalThrowable);
411
}
412
}
413
414
/* re-establish the correct throwable */
415
if ( resultThrowable != NULL ) {
416
throwThrowable(jnienv, forceFallback(resultThrowable));
417
}
418
419
}
420
421