blob: a1a8a18d03d1df3a3f89914971d1c64a2a5c54c8 [file] [log] [blame]
Elliott Hughesa2501992011-08-26 19:39:54 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "jni_internal.h"
18
19#include <sys/mman.h>
20#include <zlib.h>
21
22#include "class_linker.h"
23#include "logging.h"
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -070024#include "scoped_jni_thread_state.h"
Elliott Hughesa2501992011-08-26 19:39:54 -070025#include "thread.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070026#include "runtime.h"
Elliott Hughesa2501992011-08-26 19:39:54 -070027
Elliott Hughese6087632011-09-26 12:18:25 -070028#define LIBCORE_CPP_JNI_HELPERS
29#include <JNIHelp.h> // from libcore
30#undef LIBCORE_CPP_JNI_HELPERS
31
Elliott Hughesa2501992011-08-26 19:39:54 -070032namespace art {
33
34void JniAbort(const char* jni_function_name) {
Elliott Hughesa0957642011-09-02 14:27:33 -070035 Thread* self = Thread::Current();
36 const Method* current_method = self->GetCurrentMethod();
Elliott Hughesa2501992011-08-26 19:39:54 -070037
Elliott Hughes3b6baaa2011-10-14 19:13:56 -070038 std::ostringstream os;
Elliott Hughese6087632011-09-26 12:18:25 -070039 os << "Aborting because JNI app bug detected (see above for details)";
Elliott Hughesa2501992011-08-26 19:39:54 -070040
41 if (jni_function_name != NULL) {
42 os << "\n in call to " << jni_function_name;
43 }
Elliott Hughesa0957642011-09-02 14:27:33 -070044 // TODO: is this useful given that we're about to dump the calling thread's stack?
45 if (current_method != NULL) {
46 os << "\n from " << PrettyMethod(current_method);
47 }
48 os << "\n";
49 self->Dump(os);
Elliott Hughesa2501992011-08-26 19:39:54 -070050
51 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
52 if (vm->check_jni_abort_hook != NULL) {
53 vm->check_jni_abort_hook(os.str());
54 } else {
55 LOG(FATAL) << os.str();
56 }
57}
58
59/*
60 * ===========================================================================
61 * JNI function helpers
62 * ===========================================================================
63 */
64
Elliott Hughesa2501992011-08-26 19:39:54 -070065template<typename T>
66T Decode(ScopedJniThreadState& ts, jobject obj) {
67 return reinterpret_cast<T>(ts.Self()->DecodeJObject(obj));
68}
69
Elliott Hughesa2501992011-08-26 19:39:54 -070070/*
71 * Hack to allow forcecopy to work with jniGetNonMovableArrayElements.
72 * The code deliberately uses an invalid sequence of operations, so we
73 * need to pass it through unmodified. Review that code before making
74 * any changes here.
75 */
76#define kNoCopyMagic 0xd5aab57f
77
78/*
79 * Flags passed into ScopedCheck.
80 */
81#define kFlag_Default 0x0000
82
83#define kFlag_CritBad 0x0000 /* calling while in critical is bad */
84#define kFlag_CritOkay 0x0001 /* ...okay */
85#define kFlag_CritGet 0x0002 /* this is a critical "get" */
86#define kFlag_CritRelease 0x0003 /* this is a critical "release" */
87#define kFlag_CritMask 0x0003 /* bit mask to get "crit" value */
88
89#define kFlag_ExcepBad 0x0000 /* raised exceptions are bad */
90#define kFlag_ExcepOkay 0x0004 /* ...okay */
91
92#define kFlag_Release 0x0010 /* are we in a non-critical release function? */
93#define kFlag_NullableUtf 0x0020 /* are our UTF parameters nullable? */
94
95#define kFlag_Invocation 0x8000 /* Part of the invocation interface (JavaVM*) */
96
Elliott Hughesa0957642011-09-02 14:27:33 -070097static const char* gBuiltInPrefixes[] = {
98 "Landroid/",
99 "Lcom/android/",
100 "Lcom/google/android/",
101 "Ldalvik/",
102 "Ljava/",
103 "Ljavax/",
104 "Llibcore/",
105 "Lorg/apache/harmony/",
106 NULL
107};
108
109bool ShouldTrace(JavaVMExt* vm, const Method* method) {
110 // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages
111 // when a native method that matches the -Xjnitrace argument calls a JNI function
112 // such as NewByteArray.
113 // If -verbose:third-party-jni is on, we want to log any JNI function calls
114 // made by a third-party native method.
115 std::string classNameStr(method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8());
116 if (!vm->trace.empty() && classNameStr.find(vm->trace) != std::string::npos) {
117 return true;
118 }
119 if (vm->log_third_party_jni) {
120 // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
121 // like part of Android.
122 StringPiece className(classNameStr);
123 for (size_t i = 0; gBuiltInPrefixes[i] != NULL; ++i) {
124 if (className.starts_with(gBuiltInPrefixes[i])) {
125 return false;
126 }
127 }
128 return true;
129 }
130 return false;
131}
132
Elliott Hughesa2501992011-08-26 19:39:54 -0700133class ScopedCheck {
134public:
135 // For JNIEnv* functions.
136 explicit ScopedCheck(JNIEnv* env, int flags, const char* functionName) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700137 Init(env, reinterpret_cast<JNIEnvExt*>(env)->vm, flags, functionName, true);
138 CheckThread(flags);
Elliott Hughesa2501992011-08-26 19:39:54 -0700139 }
140
141 // For JavaVM* functions.
Elliott Hughesa0957642011-09-02 14:27:33 -0700142 explicit ScopedCheck(JavaVM* vm, bool hasMethod, const char* functionName) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700143 Init(NULL, vm, kFlag_Invocation, functionName, hasMethod);
Elliott Hughesa2501992011-08-26 19:39:54 -0700144 }
145
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700146 bool ForceCopy() {
Elliott Hughesa2501992011-08-26 19:39:54 -0700147 return Runtime::Current()->GetJavaVM()->force_copy;
148 }
149
150 /*
151 * In some circumstances the VM will screen class names, but it doesn't
152 * for class lookup. When things get bounced through a class loader, they
153 * can actually get normalized a couple of times; as a result, passing in
154 * a class name like "java.lang.Thread" instead of "java/lang/Thread" will
155 * work in some circumstances.
156 *
157 * This is incorrect and could cause strange behavior or compatibility
158 * problems, so we want to screen that out here.
159 *
160 * We expect "fully-qualified" class names, like "java/lang/Thread" or
161 * "[Ljava/lang/Object;".
162 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700163 void CheckClassName(const char* className) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700164 if (!IsValidClassName(className, true, false)) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700165 LOG(ERROR) << "JNI ERROR: illegal class name '" << className << "' (" << function_name_ << ")\n"
Elliott Hughesa2501992011-08-26 19:39:54 -0700166 << " (should be of the form 'java/lang/String', [Ljava/lang/String;' or '[[B')\n";
167 JniAbort();
168 }
169 }
170
171 /*
172 * Verify that the field is of the appropriate type. If the field has an
173 * object type, "java_object" is the object we're trying to assign into it.
174 *
175 * Works for both static and instance fields.
176 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700177 void CheckFieldType(jobject java_object, jfieldID fid, char prim, bool isStatic) {
178 ScopedJniThreadState ts(env_);
179 Field* f = CheckFieldID(fid);
180 if (f == NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700181 return;
182 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700183 Class* field_type = f->GetType();
184 if (!field_type->IsPrimitive()) {
185 if (java_object != NULL) {
186 Object* obj = Decode<Object*>(ts, java_object);
187 /*
188 * If java_object is a weak global ref whose referent has been cleared,
189 * obj will be NULL. Otherwise, obj should always be non-NULL
190 * and valid.
191 */
192 if (obj != NULL && !Heap::IsHeapAddress(obj)) {
193 LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
Elliott Hughesa2501992011-08-26 19:39:54 -0700194 JniAbort();
195 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700196 } else {
Brian Carlstrom16192862011-09-12 17:50:06 -0700197 if (!obj->InstanceOf(field_type)) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700198 LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << PrettyTypeOf(obj);
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700199 JniAbort();
200 return;
201 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700202 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700203 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700204 } else if (field_type != Runtime::Current()->GetClassLinker()->FindPrimitiveClass(prim)) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700205 LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << prim;
206 JniAbort();
207 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700208 }
209
210 if (isStatic && !f->IsStatic()) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700211 if (isStatic) {
212 LOG(ERROR) << "JNI ERROR: accessing non-static field " << PrettyField(f) << " as static";
213 } else {
214 LOG(ERROR) << "JNI ERROR: accessing static field " << PrettyField(f) << " as non-static";
215 }
216 JniAbort();
217 return;
218 }
219 }
220
221 /*
222 * Verify that this instance field ID is valid for this object.
223 *
224 * Assumes "jobj" has already been validated.
225 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700226 void CheckInstanceFieldID(jobject java_object, jfieldID fid) {
227 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700228
229 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700230 if (o == NULL || !Heap::IsHeapAddress(o)) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700231 LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
232 JniAbort();
233 return;
234 }
235
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700236 Field* f = CheckFieldID(fid);
237 if (f == NULL) {
238 return;
239 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700240 Class* f_type = f->GetType();
Brian Carlstrom5d40f182011-09-26 22:29:18 -0700241 // check invariant that all jfieldIDs have resolved types
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700242 DCHECK(f_type != NULL);
Elliott Hughesa2501992011-08-26 19:39:54 -0700243 Class* c = o->GetClass();
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700244 if (c->FindInstanceField(f->GetName()->ToModifiedUtf8(), f_type) == NULL) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700245 LOG(ERROR) << "JNI ERROR: jfieldID " << PrettyField(f) << " not valid for an object of class " << PrettyTypeOf(o);
Elliott Hughesa2501992011-08-26 19:39:54 -0700246 JniAbort();
247 }
248 }
249
250 /*
251 * Verify that the pointer value is non-NULL.
252 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700253 void CheckNonNull(const void* ptr) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700254 if (ptr == NULL) {
255 LOG(ERROR) << "JNI ERROR: invalid null pointer";
256 JniAbort();
257 }
258 }
259
260 /*
261 * Verify that the method's return type matches the type of call.
262 * 'expectedType' will be "L" for all objects, including arrays.
263 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700264 void CheckSig(jmethodID mid, const char* expectedType, bool isStatic) {
265 ScopedJniThreadState ts(env_);
266 const Method* m = CheckMethodID(mid);
267 if (m == NULL) {
268 return;
269 }
Brian Carlstrom2ed67392011-09-09 14:53:28 -0700270 if (*expectedType != m->GetShorty()->CharAt(0)) {
Elliott Hughes726079d2011-10-07 18:43:44 -0700271 LOG(ERROR) << "JNI ERROR: the return type of " << function_name_ << " does not match "
272 << PrettyMethod(m);
Elliott Hughesa2501992011-08-26 19:39:54 -0700273 JniAbort();
274 } else if (isStatic && !m->IsStatic()) {
275 if (isStatic) {
Elliott Hughes726079d2011-10-07 18:43:44 -0700276 LOG(ERROR) << "JNI ERROR: calling non-static method "
277 << PrettyMethod(m) << " with " << function_name_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700278 } else {
Elliott Hughes726079d2011-10-07 18:43:44 -0700279 LOG(ERROR) << "JNI ERROR: calling static method "
280 << PrettyMethod(m) << " with non-static " << function_name_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700281 }
282 JniAbort();
283 }
284 }
285
286 /*
287 * Verify that this static field ID is valid for this class.
288 *
289 * Assumes "java_class" has already been validated.
290 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700291 void CheckStaticFieldID(jclass java_class, jfieldID fid) {
292 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700293 Class* c = Decode<Class*>(ts, java_class);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700294 const Field* f = CheckFieldID(fid);
295 if (f == NULL) {
296 return;
297 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700298 if (f->GetDeclaringClass() != c) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700299 LOG(ERROR) << "JNI ERROR: static jfieldID " << fid << " not valid for class " << PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700300 JniAbort();
301 }
302 }
303
304 /*
305 * Verify that "mid" is appropriate for "clazz".
306 *
307 * A mismatch isn't dangerous, because the jmethodID defines the class. In
308 * fact, jclazz is unused in the implementation. It's best if we don't
309 * allow bad code in the system though.
310 *
311 * Instances of "jclazz" must be instances of the method's declaring class.
312 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700313 void CheckStaticMethod(jclass java_class, jmethodID mid) {
314 ScopedJniThreadState ts(env_);
315 const Method* m = CheckMethodID(mid);
316 if (m == NULL) {
317 return;
318 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700319 Class* c = Decode<Class*>(ts, java_class);
Elliott Hughesa2501992011-08-26 19:39:54 -0700320 if (!c->IsAssignableFrom(m->GetDeclaringClass())) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700321 LOG(ERROR) << "JNI ERROR: can't call static " << PrettyMethod(m) << " on class " << PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700322 JniAbort();
323 }
324 }
325
326 /*
327 * Verify that "mid" is appropriate for "jobj".
328 *
329 * Make sure the object is an instance of the method's declaring class.
330 * (Note the mid might point to a declaration in an interface; this
331 * will be handled automatically by the instanceof check.)
332 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700333 void CheckVirtualMethod(jobject java_object, jmethodID mid) {
334 ScopedJniThreadState ts(env_);
335 const Method* m = CheckMethodID(mid);
336 if (m == NULL) {
337 return;
338 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700339 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughesa2501992011-08-26 19:39:54 -0700340 if (!o->InstanceOf(m->GetDeclaringClass())) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700341 LOG(ERROR) << "JNI ERROR: can't call " << PrettyMethod(m) << " on instance of " << PrettyTypeOf(o);
Elliott Hughesa2501992011-08-26 19:39:54 -0700342 JniAbort();
343 }
344 }
345
346 /**
347 * The format string is a sequence of the following characters,
348 * and must be followed by arguments of the corresponding types
349 * in the same order.
350 *
351 * Java primitive types:
352 * B - jbyte
353 * C - jchar
354 * D - jdouble
355 * F - jfloat
356 * I - jint
357 * J - jlong
358 * S - jshort
359 * Z - jboolean (shown as true and false)
360 * V - void
361 *
362 * Java reference types:
363 * L - jobject
364 * a - jarray
365 * c - jclass
366 * s - jstring
367 *
368 * JNI types:
369 * b - jboolean (shown as JNI_TRUE and JNI_FALSE)
370 * f - jfieldID
371 * m - jmethodID
372 * p - void*
373 * r - jint (for release mode arguments)
Elliott Hughes78090d12011-10-07 14:31:47 -0700374 * u - const char* (Modified UTF-8)
Elliott Hughesa2501992011-08-26 19:39:54 -0700375 * z - jsize (for lengths; use i if negative values are okay)
376 * v - JavaVM*
377 * E - JNIEnv*
378 * . - no argument; just print "..." (used for varargs JNI calls)
379 *
380 * Use the kFlag_NullableUtf flag where 'u' field(s) are nullable.
381 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700382 void Check(bool entry, const char* fmt0, ...) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700383 va_list ap;
384
Elliott Hughesa0957642011-09-02 14:27:33 -0700385 const Method* traceMethod = NULL;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700386 if ((!vm_->trace.empty() || vm_->log_third_party_jni) && has_method_) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700387 // We need to guard some of the invocation interface's calls: a bad caller might
388 // use DetachCurrentThread or GetEnv on a thread that's not yet attached.
Elliott Hughesa0957642011-09-02 14:27:33 -0700389 Thread* self = Thread::Current();
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700390 if ((flags_ & kFlag_Invocation) == 0 || self != NULL) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700391 traceMethod = self->GetCurrentMethod();
Elliott Hughesa2501992011-08-26 19:39:54 -0700392 }
393 }
Elliott Hughesa0957642011-09-02 14:27:33 -0700394
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700395 if (traceMethod != NULL && ShouldTrace(vm_, traceMethod)) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700396 va_start(ap, fmt0);
397 std::string msg;
398 for (const char* fmt = fmt0; *fmt;) {
399 char ch = *fmt++;
400 if (ch == 'B') { // jbyte
401 jbyte b = va_arg(ap, int);
402 if (b >= 0 && b < 10) {
403 StringAppendF(&msg, "%d", b);
404 } else {
405 StringAppendF(&msg, "%#x (%d)", b, b);
406 }
407 } else if (ch == 'C') { // jchar
408 jchar c = va_arg(ap, int);
409 if (c < 0x7f && c >= ' ') {
410 StringAppendF(&msg, "U+%x ('%c')", c, c);
411 } else {
412 StringAppendF(&msg, "U+%x", c);
413 }
414 } else if (ch == 'F' || ch == 'D') { // jfloat, jdouble
415 StringAppendF(&msg, "%g", va_arg(ap, double));
416 } else if (ch == 'I' || ch == 'S') { // jint, jshort
417 StringAppendF(&msg, "%d", va_arg(ap, int));
418 } else if (ch == 'J') { // jlong
419 StringAppendF(&msg, "%lld", va_arg(ap, jlong));
420 } else if (ch == 'Z') { // jboolean
421 StringAppendF(&msg, "%s", va_arg(ap, int) ? "true" : "false");
422 } else if (ch == 'V') { // void
423 msg += "void";
424 } else if (ch == 'v') { // JavaVM*
425 JavaVM* vm = va_arg(ap, JavaVM*);
426 StringAppendF(&msg, "(JavaVM*)%p", vm);
427 } else if (ch == 'E') { // JNIEnv*
428 JNIEnv* env = va_arg(ap, JNIEnv*);
429 StringAppendF(&msg, "(JNIEnv*)%p", env);
430 } else if (ch == 'L' || ch == 'a' || ch == 's') { // jobject, jarray, jstring
431 // For logging purposes, these are identical.
432 jobject o = va_arg(ap, jobject);
433 if (o == NULL) {
434 msg += "NULL";
435 } else {
436 StringAppendF(&msg, "%p", o);
437 }
438 } else if (ch == 'b') { // jboolean (JNI-style)
439 jboolean b = va_arg(ap, int);
440 msg += (b ? "JNI_TRUE" : "JNI_FALSE");
441 } else if (ch == 'c') { // jclass
442 jclass jc = va_arg(ap, jclass);
443 Class* c = reinterpret_cast<Class*>(Thread::Current()->DecodeJObject(jc));
444 if (c == NULL) {
445 msg += "NULL";
446 } else if (c == kInvalidIndirectRefObject || !Heap::IsHeapAddress(c)) {
447 StringAppendF(&msg, "%p(INVALID)", jc);
448 } else {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700449 msg += PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700450 if (!entry) {
451 StringAppendF(&msg, " (%p)", jc);
452 }
453 }
454 } else if (ch == 'f') { // jfieldID
455 jfieldID fid = va_arg(ap, jfieldID);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700456 Field* f = reinterpret_cast<Field*>(fid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700457 msg += PrettyField(f);
458 if (!entry) {
459 StringAppendF(&msg, " (%p)", fid);
460 }
461 } else if (ch == 'z') { // non-negative jsize
462 // You might expect jsize to be size_t, but it's not; it's the same as jint.
463 // We only treat this specially so we can do the non-negative check.
464 // TODO: maybe this wasn't worth it?
465 jint i = va_arg(ap, jint);
466 StringAppendF(&msg, "%d", i);
467 } else if (ch == 'm') { // jmethodID
468 jmethodID mid = va_arg(ap, jmethodID);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700469 Method* m = reinterpret_cast<Method*>(mid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700470 msg += PrettyMethod(m);
471 if (!entry) {
472 StringAppendF(&msg, " (%p)", mid);
473 }
474 } else if (ch == 'p') { // void* ("pointer")
475 void* p = va_arg(ap, void*);
476 if (p == NULL) {
477 msg += "NULL";
478 } else {
479 StringAppendF(&msg, "(void*) %p", p);
480 }
481 } else if (ch == 'r') { // jint (release mode)
482 jint releaseMode = va_arg(ap, jint);
483 if (releaseMode == 0) {
484 msg += "0";
485 } else if (releaseMode == JNI_ABORT) {
486 msg += "JNI_ABORT";
487 } else if (releaseMode == JNI_COMMIT) {
488 msg += "JNI_COMMIT";
489 } else {
490 StringAppendF(&msg, "invalid release mode %d", releaseMode);
491 }
Elliott Hughes78090d12011-10-07 14:31:47 -0700492 } else if (ch == 'u') { // const char* (Modified UTF-8)
Elliott Hughesa2501992011-08-26 19:39:54 -0700493 const char* utf = va_arg(ap, const char*);
494 if (utf == NULL) {
495 msg += "NULL";
496 } else {
497 StringAppendF(&msg, "\"%s\"", utf);
498 }
499 } else if (ch == '.') {
500 msg += "...";
501 } else {
502 LOG(ERROR) << "unknown trace format specifier: " << ch;
503 JniAbort();
504 return;
505 }
506 if (*fmt) {
507 StringAppendF(&msg, ", ");
508 }
509 }
510 va_end(ap);
511
512 if (entry) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700513 if (has_method_) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700514 std::string methodName(PrettyMethod(traceMethod, false));
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700515 LOG(INFO) << "JNI: " << methodName << " -> " << function_name_ << "(" << msg << ")";
516 indent_ = methodName.size() + 1;
Elliott Hughesa2501992011-08-26 19:39:54 -0700517 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700518 LOG(INFO) << "JNI: -> " << function_name_ << "(" << msg << ")";
519 indent_ = 0;
Elliott Hughesa2501992011-08-26 19:39:54 -0700520 }
521 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700522 LOG(INFO) << StringPrintf("JNI: %*s<- %s returned %s", indent_, "", function_name_, msg.c_str());
Elliott Hughesa2501992011-08-26 19:39:54 -0700523 }
524 }
525
526 // We always do the thorough checks on entry, and never on exit...
527 if (entry) {
528 va_start(ap, fmt0);
529 for (const char* fmt = fmt0; *fmt; ++fmt) {
530 char ch = *fmt;
531 if (ch == 'a') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700532 CheckArray(va_arg(ap, jarray));
Elliott Hughesa2501992011-08-26 19:39:54 -0700533 } else if (ch == 'c') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700534 CheckInstance(kClass, va_arg(ap, jclass));
Elliott Hughesa2501992011-08-26 19:39:54 -0700535 } else if (ch == 'L') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700536 CheckObject(va_arg(ap, jobject));
Elliott Hughesa2501992011-08-26 19:39:54 -0700537 } else if (ch == 'r') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700538 CheckReleaseMode(va_arg(ap, jint));
Elliott Hughesa2501992011-08-26 19:39:54 -0700539 } else if (ch == 's') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700540 CheckInstance(kString, va_arg(ap, jstring));
Elliott Hughesa2501992011-08-26 19:39:54 -0700541 } else if (ch == 'u') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700542 if ((flags_ & kFlag_Release) != 0) {
543 CheckNonNull(va_arg(ap, const char*));
Elliott Hughesa2501992011-08-26 19:39:54 -0700544 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700545 bool nullable = ((flags_ & kFlag_NullableUtf) != 0);
546 CheckUtfString(va_arg(ap, const char*), nullable);
Elliott Hughesa2501992011-08-26 19:39:54 -0700547 }
548 } else if (ch == 'z') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700549 CheckLengthPositive(va_arg(ap, jsize));
Elliott Hughesa2501992011-08-26 19:39:54 -0700550 } else if (strchr("BCISZbfmpEv", ch) != NULL) {
551 va_arg(ap, int); // Skip this argument.
552 } else if (ch == 'D' || ch == 'F') {
553 va_arg(ap, double); // Skip this argument.
554 } else if (ch == 'J') {
555 va_arg(ap, long); // Skip this argument.
556 } else if (ch == '.') {
557 } else {
558 LOG(FATAL) << "unknown check format specifier: " << ch;
559 }
560 }
561 va_end(ap);
562 }
563 }
564
565private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700566 void Init(JNIEnv* env, JavaVM* vm, int flags, const char* functionName, bool hasMethod) {
567 env_ = reinterpret_cast<JNIEnvExt*>(env);
568 vm_ = reinterpret_cast<JavaVMExt*>(vm);
569 flags_ = flags;
570 function_name_ = functionName;
Elliott Hughesa2501992011-08-26 19:39:54 -0700571
572 // Set "hasMethod" to true if we have a valid thread with a method pointer.
573 // We won't have one before attaching a thread, after detaching a thread, or
574 // after destroying the VM.
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700575 has_method_ = hasMethod;
Elliott Hughesa2501992011-08-26 19:39:54 -0700576 }
577
578 /*
579 * Verify that "array" is non-NULL and points to an Array object.
580 *
581 * Since we're dealing with objects, switch to "running" mode.
582 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700583 void CheckArray(jarray java_array) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700584 if (java_array == NULL) {
585 LOG(ERROR) << "JNI ERROR: received null array";
586 JniAbort();
587 return;
588 }
589
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700590 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700591 Array* a = Decode<Array*>(ts, java_array);
592 if (!Heap::IsHeapAddress(a)) {
593 LOG(ERROR) << "JNI ERROR: jarray is an invalid " << GetIndirectRefKind(java_array) << ": " << reinterpret_cast<void*>(java_array);
594 JniAbort();
595 } else if (!a->IsArrayInstance()) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700596 LOG(ERROR) << "JNI ERROR: jarray argument has non-array type: " << PrettyTypeOf(a);
Elliott Hughesa2501992011-08-26 19:39:54 -0700597 JniAbort();
598 }
599 }
600
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700601 void CheckLengthPositive(jsize length) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700602 if (length < 0) {
603 LOG(ERROR) << "JNI ERROR: negative jsize: " << length;
604 JniAbort();
605 }
606 }
607
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700608 Field* CheckFieldID(jfieldID fid) {
609 if (fid == NULL) {
610 LOG(ERROR) << "JNI ERROR: null jfieldID";
611 JniAbort();
612 return NULL;
613 }
614 Field* f = DecodeField(fid);
615 if (!Heap::IsHeapAddress(f)) {
616 LOG(ERROR) << "JNI ERROR: invalid jfieldID: " << fid;
617 JniAbort();
618 return NULL;
619 }
620 return f;
621 }
622
623 Method* CheckMethodID(jmethodID mid) {
624 if (mid == NULL) {
625 LOG(ERROR) << "JNI ERROR: null jmethodID";
626 JniAbort();
627 return NULL;
628 }
629 Method* m = DecodeMethod(mid);
630 if (!Heap::IsHeapAddress(m)) {
631 LOG(ERROR) << "JNI ERROR: invalid jmethodID: " << mid;
632 JniAbort();
633 return NULL;
634 }
635 return m;
636 }
637
Elliott Hughesa2501992011-08-26 19:39:54 -0700638 /*
639 * Verify that "jobj" is a valid object, and that it's an object that JNI
640 * is allowed to know about. We allow NULL references.
641 *
642 * Switches to "running" mode before performing checks.
643 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700644 void CheckObject(jobject java_object) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700645 if (java_object == NULL) {
646 return;
647 }
648
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700649 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700650
651 Object* o = Decode<Object*>(ts, java_object);
652 if (o != NULL && !Heap::IsHeapAddress(o)) {
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -0700653 // TODO: when we remove work_around_app_jni_bugs, this should be impossible.
Elliott Hughesa2501992011-08-26 19:39:54 -0700654 LOG(ERROR) << "JNI ERROR: native code passing in reference to invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
655 JniAbort();
656 }
657 }
658
659 /*
660 * Verify that the "mode" argument passed to a primitive array Release
661 * function is one of the valid values.
662 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700663 void CheckReleaseMode(jint mode) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700664 if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) {
665 LOG(ERROR) << "JNI ERROR: bad value for release mode: " << mode;
666 JniAbort();
667 }
668 }
669
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700670 void CheckThread(int flags) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700671 Thread* self = Thread::Current();
672 if (self == NULL) {
673 LOG(ERROR) << "JNI ERROR: non-VM thread making JNI calls";
674 JniAbort();
675 return;
676 }
677
678 // Get the *correct* JNIEnv by going through our TLS pointer.
679 JNIEnvExt* threadEnv = self->GetJniEnv();
680
681 /*
682 * Verify that the current thread is (a) attached and (b) associated with
683 * this particular instance of JNIEnv.
684 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700685 if (env_ != threadEnv) {
686 LOG(ERROR) << "JNI ERROR: thread " << *self << " using JNIEnv* from thread " << *env_->self;
Elliott Hughesa2501992011-08-26 19:39:54 -0700687 // If we're keeping broken code limping along, we need to suppress the abort...
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700688 if (!env_->work_around_app_jni_bugs) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700689 JniAbort();
690 return;
691 }
692 }
693
694 /*
695 * Verify that, if this thread previously made a critical "get" call, we
696 * do the corresponding "release" call before we try anything else.
697 */
698 switch (flags & kFlag_CritMask) {
699 case kFlag_CritOkay: // okay to call this method
700 break;
701 case kFlag_CritBad: // not okay to call
702 if (threadEnv->critical) {
703 LOG(ERROR) << "JNI ERROR: thread " << *self << " using JNI after critical get";
704 JniAbort();
705 return;
706 }
707 break;
708 case kFlag_CritGet: // this is a "get" call
709 /* don't check here; we allow nested gets */
710 threadEnv->critical++;
711 break;
712 case kFlag_CritRelease: // this is a "release" call
713 threadEnv->critical--;
714 if (threadEnv->critical < 0) {
715 LOG(ERROR) << "JNI ERROR: thread " << *self << " called too many critical releases";
716 JniAbort();
717 return;
718 }
719 break;
720 default:
721 LOG(FATAL) << "bad flags (internal error): " << flags;
722 }
723
724 /*
725 * Verify that, if an exception has been raised, the native code doesn't
726 * make any JNI calls other than the Exception* methods.
727 */
728 if ((flags & kFlag_ExcepOkay) == 0 && self->IsExceptionPending()) {
Elliott Hughes30646832011-10-13 16:59:46 -0700729 std::string type(PrettyTypeOf(self->GetException()));
730 LOG(ERROR) << "JNI ERROR: JNI " << function_name_ << " called with " << type << " pending";
731 // TODO: write native code that doesn't require allocation for dumping an exception.
732 if (type != "java.lang.OutOfMemoryError") {
733 LOG(ERROR) << "Pending exception is: ";
734 LOG(ERROR) << jniGetStackTrace(env_);
735 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700736 JniAbort();
737 return;
738 }
739 }
740
741 /*
Elliott Hughes78090d12011-10-07 14:31:47 -0700742 * Verify that "bytes" points to valid Modified UTF-8 data.
Elliott Hughesa2501992011-08-26 19:39:54 -0700743 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700744 void CheckUtfString(const char* bytes, bool nullable) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700745 if (bytes == NULL) {
746 if (!nullable) {
747 LOG(ERROR) << "JNI ERROR: non-nullable const char* was NULL";
748 JniAbort();
749 return;
750 }
751 return;
752 }
753
754 const char* errorKind = NULL;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700755 uint8_t utf8 = CheckUtfBytes(bytes, &errorKind);
Elliott Hughesa2501992011-08-26 19:39:54 -0700756 if (errorKind != NULL) {
Elliott Hughes78090d12011-10-07 14:31:47 -0700757 LOG(ERROR) << "JNI ERROR: input is not valid Modified UTF-8: "
758 << "illegal " << errorKind << " byte " << StringPrintf("%#x", utf8) << "\n"
759 << " string: '" << bytes << "'";
Elliott Hughesa2501992011-08-26 19:39:54 -0700760 JniAbort();
761 return;
762 }
763 }
764
765 enum InstanceKind {
766 kClass,
767 kDirectByteBuffer,
768 kString,
769 kThrowable,
770 };
771
772 /*
773 * Verify that "jobj" is a valid non-NULL object reference, and points to
774 * an instance of expectedClass.
775 *
776 * Because we're looking at an object on the GC heap, we have to switch
777 * to "running" mode before doing the checks.
778 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700779 void CheckInstance(InstanceKind kind, jobject java_object) {
Elliott Hughesd92bec42011-09-02 17:04:36 -0700780 const char* what = NULL;
Elliott Hughesa2501992011-08-26 19:39:54 -0700781 switch (kind) {
782 case kClass:
783 what = "jclass";
784 break;
785 case kDirectByteBuffer:
786 what = "direct ByteBuffer";
787 break;
788 case kString:
789 what = "jstring";
790 break;
791 case kThrowable:
792 what = "jthrowable";
793 break;
794 default:
795 CHECK(false) << static_cast<int>(kind);
796 }
797
798 if (java_object == NULL) {
799 LOG(ERROR) << "JNI ERROR: received null " << what;
800 JniAbort();
801 return;
802 }
803
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700804 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700805 Object* obj = Decode<Object*>(ts, java_object);
806 if (!Heap::IsHeapAddress(obj)) {
807 LOG(ERROR) << "JNI ERROR: " << what << " is an invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
808 JniAbort();
809 return;
810 }
811
812 bool okay = true;
813 switch (kind) {
814 case kClass:
815 okay = obj->IsClass();
816 break;
817 case kDirectByteBuffer:
818 // TODO
819 break;
820 case kString:
821 okay = obj->IsString();
822 break;
823 case kThrowable:
824 // TODO
825 break;
826 }
827 if (!okay) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700828 LOG(ERROR) << "JNI ERROR: " << what << " has wrong type: " << PrettyTypeOf(obj);
Elliott Hughesa2501992011-08-26 19:39:54 -0700829 JniAbort();
830 }
831 }
832
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700833 static uint8_t CheckUtfBytes(const char* bytes, const char** errorKind) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700834 while (*bytes != '\0') {
835 uint8_t utf8 = *(bytes++);
836 // Switch on the high four bits.
837 switch (utf8 >> 4) {
838 case 0x00:
839 case 0x01:
840 case 0x02:
841 case 0x03:
842 case 0x04:
843 case 0x05:
844 case 0x06:
845 case 0x07:
846 // Bit pattern 0xxx. No need for any extra bytes.
847 break;
848 case 0x08:
849 case 0x09:
850 case 0x0a:
851 case 0x0b:
852 case 0x0f:
853 /*
854 * Bit pattern 10xx or 1111, which are illegal start bytes.
855 * Note: 1111 is valid for normal UTF-8, but not the
Elliott Hughes78090d12011-10-07 14:31:47 -0700856 * Modified UTF-8 used here.
Elliott Hughesa2501992011-08-26 19:39:54 -0700857 */
858 *errorKind = "start";
859 return utf8;
860 case 0x0e:
861 // Bit pattern 1110, so there are two additional bytes.
862 utf8 = *(bytes++);
863 if ((utf8 & 0xc0) != 0x80) {
864 *errorKind = "continuation";
865 return utf8;
866 }
867 // Fall through to take care of the final byte.
868 case 0x0c:
869 case 0x0d:
870 // Bit pattern 110x, so there is one additional byte.
871 utf8 = *(bytes++);
872 if ((utf8 & 0xc0) != 0x80) {
873 *errorKind = "continuation";
874 return utf8;
875 }
876 break;
877 }
878 }
879 return 0;
880 }
881
882 void JniAbort() {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700883 ::art::JniAbort(function_name_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700884 }
885
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700886 JNIEnvExt* env_;
887 JavaVMExt* vm_;
888 const char* function_name_;
889 int flags_;
890 bool has_method_;
891 size_t indent_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700892
893 DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
894};
895
896#define CHECK_JNI_ENTRY(flags, types, args...) \
897 ScopedCheck sc(env, flags, __FUNCTION__); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700898 sc.Check(true, types, ##args)
Elliott Hughesa2501992011-08-26 19:39:54 -0700899
900#define CHECK_JNI_EXIT(type, exp) ({ \
901 typeof (exp) _rc = (exp); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700902 sc.Check(false, type, _rc); \
Elliott Hughesa2501992011-08-26 19:39:54 -0700903 _rc; })
904#define CHECK_JNI_EXIT_VOID() \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700905 sc.Check(false, "V")
Elliott Hughesa2501992011-08-26 19:39:54 -0700906
907/*
908 * ===========================================================================
909 * Guarded arrays
910 * ===========================================================================
911 */
912
913#define kGuardLen 512 /* must be multiple of 2 */
914#define kGuardPattern 0xd5e3 /* uncommon values; d5e3d5e3 invalid addr */
915#define kGuardMagic 0xffd5aa96
916
917/* this gets tucked in at the start of the buffer; struct size must be even */
918struct GuardedCopy {
919 uint32_t magic;
920 uLong adler;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700921 size_t original_length;
922 const void* original_ptr;
Elliott Hughesa2501992011-08-26 19:39:54 -0700923
924 /* find the GuardedCopy given the pointer into the "live" data */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700925 static inline const GuardedCopy* FromData(const void* dataBuf) {
926 return reinterpret_cast<const GuardedCopy*>(ActualBuffer(dataBuf));
Elliott Hughesa2501992011-08-26 19:39:54 -0700927 }
928
929 /*
930 * Create an over-sized buffer to hold the contents of "buf". Copy it in,
931 * filling in the area around it with guard data.
932 *
933 * We use a 16-bit pattern to make a rogue memset less likely to elude us.
934 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700935 static void* Create(const void* buf, size_t len, bool modOkay) {
936 size_t newLen = ActualLength(len);
937 uint8_t* newBuf = DebugAlloc(newLen);
Elliott Hughesa2501992011-08-26 19:39:54 -0700938
939 /* fill it in with a pattern */
940 uint16_t* pat = (uint16_t*) newBuf;
941 for (size_t i = 0; i < newLen / 2; i++) {
942 *pat++ = kGuardPattern;
943 }
944
945 /* copy the data in; note "len" could be zero */
946 memcpy(newBuf + kGuardLen / 2, buf, len);
947
948 /* if modification is not expected, grab a checksum */
949 uLong adler = 0;
950 if (!modOkay) {
951 adler = adler32(0L, Z_NULL, 0);
952 adler = adler32(adler, (const Bytef*)buf, len);
953 *(uLong*)newBuf = adler;
954 }
955
956 GuardedCopy* pExtra = reinterpret_cast<GuardedCopy*>(newBuf);
957 pExtra->magic = kGuardMagic;
958 pExtra->adler = adler;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700959 pExtra->original_ptr = buf;
960 pExtra->original_length = len;
Elliott Hughesa2501992011-08-26 19:39:54 -0700961
962 return newBuf + kGuardLen / 2;
963 }
964
965 /*
966 * Free up the guard buffer, scrub it, and return the original pointer.
967 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700968 static void* Destroy(void* dataBuf) {
969 const GuardedCopy* pExtra = GuardedCopy::FromData(dataBuf);
970 void* original_ptr = (void*) pExtra->original_ptr;
971 size_t len = pExtra->original_length;
972 DebugFree(dataBuf, len);
973 return original_ptr;
Elliott Hughesa2501992011-08-26 19:39:54 -0700974 }
975
976 /*
977 * Verify the guard area and, if "modOkay" is false, that the data itself
978 * has not been altered.
979 *
980 * The caller has already checked that "dataBuf" is non-NULL.
981 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700982 static void Check(const char* functionName, const void* dataBuf, bool modOkay) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700983 static const uint32_t kMagicCmp = kGuardMagic;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700984 const uint8_t* fullBuf = ActualBuffer(dataBuf);
985 const GuardedCopy* pExtra = GuardedCopy::FromData(dataBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -0700986
987 /*
988 * Before we do anything with "pExtra", check the magic number. We
989 * do the check with memcmp rather than "==" in case the pointer is
990 * unaligned. If it points to completely bogus memory we're going
991 * to crash, but there's no easy way around that.
992 */
993 if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) {
994 uint8_t buf[4];
995 memcpy(buf, &pExtra->magic, 4);
996 LOG(ERROR) << StringPrintf("JNI: guard magic does not match "
997 "(found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?",
998 buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */
999 JniAbort(functionName);
1000 }
1001
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001002 size_t len = pExtra->original_length;
Elliott Hughesa2501992011-08-26 19:39:54 -07001003
1004 /* check bottom half of guard; skip over optional checksum storage */
1005 const uint16_t* pat = (uint16_t*) fullBuf;
1006 for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) {
1007 if (pat[i] != kGuardPattern) {
1008 LOG(ERROR) << "JNI: guard pattern(1) disturbed at " << (void*) fullBuf << " + " << (i*2);
1009 JniAbort(functionName);
1010 }
1011 }
1012
1013 int offset = kGuardLen / 2 + len;
1014 if (offset & 0x01) {
1015 /* odd byte; expected value depends on endian-ness of host */
1016 const uint16_t patSample = kGuardPattern;
1017 if (fullBuf[offset] != ((const uint8_t*) &patSample)[1]) {
1018 LOG(ERROR) << "JNI: guard pattern disturbed in odd byte after "
1019 << (void*) fullBuf << " (+" << offset << ") "
1020 << StringPrintf("0x%02x 0x%02x", fullBuf[offset], ((const uint8_t*) &patSample)[1]);
1021 JniAbort(functionName);
1022 }
1023 offset++;
1024 }
1025
1026 /* check top half of guard */
1027 pat = (uint16_t*) (fullBuf + offset);
1028 for (size_t i = 0; i < kGuardLen / 4; i++) {
1029 if (pat[i] != kGuardPattern) {
1030 LOG(ERROR) << "JNI: guard pattern(2) disturbed at " << (void*) fullBuf << " + " << (offset + i*2);
1031 JniAbort(functionName);
1032 }
1033 }
1034
1035 /*
1036 * If modification is not expected, verify checksum. Strictly speaking
1037 * this is wrong: if we told the client that we made a copy, there's no
1038 * reason they can't alter the buffer.
1039 */
1040 if (!modOkay) {
1041 uLong adler = adler32(0L, Z_NULL, 0);
1042 adler = adler32(adler, (const Bytef*)dataBuf, len);
1043 if (pExtra->adler != adler) {
1044 LOG(ERROR) << StringPrintf("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p", pExtra->adler, adler, dataBuf);
1045 JniAbort(functionName);
1046 }
1047 }
1048 }
1049
1050 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001051 static uint8_t* DebugAlloc(size_t len) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001052 void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
1053 if (result == MAP_FAILED) {
1054 PLOG(FATAL) << "GuardedCopy::create mmap(" << len << ") failed";
1055 }
1056 return reinterpret_cast<uint8_t*>(result);
1057 }
1058
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001059 static void DebugFree(void* dataBuf, size_t len) {
1060 uint8_t* fullBuf = ActualBuffer(dataBuf);
1061 size_t totalByteCount = ActualLength(len);
Elliott Hughesa2501992011-08-26 19:39:54 -07001062 // TODO: we could mprotect instead, and keep the allocation around for a while.
1063 // This would be even more expensive, but it might catch more errors.
1064 // if (mprotect(fullBuf, totalByteCount, PROT_NONE) != 0) {
1065 // LOGW("mprotect(PROT_NONE) failed: %s", strerror(errno));
1066 // }
1067 if (munmap(fullBuf, totalByteCount) != 0) {
1068 PLOG(FATAL) << "munmap(" << (void*) fullBuf << ", " << totalByteCount << ") failed";
1069 }
1070 }
1071
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001072 static const uint8_t* ActualBuffer(const void* dataBuf) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001073 return reinterpret_cast<const uint8_t*>(dataBuf) - kGuardLen / 2;
1074 }
1075
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001076 static uint8_t* ActualBuffer(void* dataBuf) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001077 return reinterpret_cast<uint8_t*>(dataBuf) - kGuardLen / 2;
1078 }
1079
1080 // Underlying length of a user allocation of 'length' bytes.
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001081 static size_t ActualLength(size_t length) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001082 return (length + kGuardLen + 1) & ~0x01;
1083 }
1084};
1085
1086/*
1087 * Create a guarded copy of a primitive array. Modifications to the copied
1088 * data are allowed. Returns a pointer to the copied data.
1089 */
1090void* CreateGuardedPACopy(JNIEnv* env, const jarray java_array, jboolean* isCopy) {
1091 ScopedJniThreadState ts(env);
1092
1093 Array* a = Decode<Array*>(ts, java_array);
1094 size_t byte_count = a->GetLength() * a->GetClass()->GetComponentSize();
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001095 void* result = GuardedCopy::Create(a->GetRawData(), byte_count, true);
Elliott Hughesa2501992011-08-26 19:39:54 -07001096 if (isCopy != NULL) {
1097 *isCopy = JNI_TRUE;
1098 }
1099 return result;
1100}
1101
1102/*
1103 * Perform the array "release" operation, which may or may not copy data
1104 * back into the VM, and may or may not release the underlying storage.
1105 */
1106void ReleaseGuardedPACopy(JNIEnv* env, jarray java_array, void* dataBuf, int mode) {
1107 if (reinterpret_cast<uintptr_t>(dataBuf) == kNoCopyMagic) {
1108 return;
1109 }
1110
1111 ScopedJniThreadState ts(env);
1112 Array* a = Decode<Array*>(ts, java_array);
1113
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001114 GuardedCopy::Check(__FUNCTION__, dataBuf, true);
Elliott Hughesa2501992011-08-26 19:39:54 -07001115
1116 if (mode != JNI_ABORT) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001117 size_t len = GuardedCopy::FromData(dataBuf)->original_length;
Elliott Hughesbf86d042011-08-31 17:53:14 -07001118 memcpy(a->GetRawData(), dataBuf, len);
Elliott Hughesa2501992011-08-26 19:39:54 -07001119 }
1120 if (mode != JNI_COMMIT) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001121 GuardedCopy::Destroy(dataBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -07001122 }
1123}
1124
1125/*
1126 * ===========================================================================
1127 * JNI functions
1128 * ===========================================================================
1129 */
1130
1131class CheckJNI {
1132 public:
1133 static jint GetVersion(JNIEnv* env) {
1134 CHECK_JNI_ENTRY(kFlag_Default, "E", env);
1135 return CHECK_JNI_EXIT("I", baseEnv(env)->GetVersion(env));
1136 }
1137
1138 static jclass DefineClass(JNIEnv* env, const char* name, jobject loader, const jbyte* buf, jsize bufLen) {
1139 CHECK_JNI_ENTRY(kFlag_Default, "EuLpz", env, name, loader, buf, bufLen);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001140 sc.CheckClassName(name);
Elliott Hughesa2501992011-08-26 19:39:54 -07001141 return CHECK_JNI_EXIT("c", baseEnv(env)->DefineClass(env, name, loader, buf, bufLen));
1142 }
1143
1144 static jclass FindClass(JNIEnv* env, const char* name) {
1145 CHECK_JNI_ENTRY(kFlag_Default, "Eu", env, name);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001146 sc.CheckClassName(name);
Elliott Hughesa2501992011-08-26 19:39:54 -07001147 return CHECK_JNI_EXIT("c", baseEnv(env)->FindClass(env, name));
1148 }
1149
1150 static jclass GetSuperclass(JNIEnv* env, jclass clazz) {
1151 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1152 return CHECK_JNI_EXIT("c", baseEnv(env)->GetSuperclass(env, clazz));
1153 }
1154
1155 static jboolean IsAssignableFrom(JNIEnv* env, jclass clazz1, jclass clazz2) {
1156 CHECK_JNI_ENTRY(kFlag_Default, "Ecc", env, clazz1, clazz2);
1157 return CHECK_JNI_EXIT("b", baseEnv(env)->IsAssignableFrom(env, clazz1, clazz2));
1158 }
1159
1160 static jmethodID FromReflectedMethod(JNIEnv* env, jobject method) {
1161 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, method);
1162 // TODO: check that 'field' is a java.lang.reflect.Method.
1163 return CHECK_JNI_EXIT("m", baseEnv(env)->FromReflectedMethod(env, method));
1164 }
1165
1166 static jfieldID FromReflectedField(JNIEnv* env, jobject field) {
1167 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, field);
1168 // TODO: check that 'field' is a java.lang.reflect.Field.
1169 return CHECK_JNI_EXIT("f", baseEnv(env)->FromReflectedField(env, field));
1170 }
1171
1172 static jobject ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID mid, jboolean isStatic) {
1173 CHECK_JNI_ENTRY(kFlag_Default, "Ecmb", env, cls, mid, isStatic);
1174 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedMethod(env, cls, mid, isStatic));
1175 }
1176
1177 static jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fid, jboolean isStatic) {
1178 CHECK_JNI_ENTRY(kFlag_Default, "Ecfb", env, cls, fid, isStatic);
1179 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedField(env, cls, fid, isStatic));
1180 }
1181
1182 static jint Throw(JNIEnv* env, jthrowable obj) {
1183 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1184 // TODO: check that 'obj' is a java.lang.Throwable.
1185 return CHECK_JNI_EXIT("I", baseEnv(env)->Throw(env, obj));
1186 }
1187
1188 static jint ThrowNew(JNIEnv* env, jclass clazz, const char* message) {
1189 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Ecu", env, clazz, message);
1190 return CHECK_JNI_EXIT("I", baseEnv(env)->ThrowNew(env, clazz, message));
1191 }
1192
1193 static jthrowable ExceptionOccurred(JNIEnv* env) {
1194 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1195 return CHECK_JNI_EXIT("L", baseEnv(env)->ExceptionOccurred(env));
1196 }
1197
1198 static void ExceptionDescribe(JNIEnv* env) {
1199 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1200 baseEnv(env)->ExceptionDescribe(env);
1201 CHECK_JNI_EXIT_VOID();
1202 }
1203
1204 static void ExceptionClear(JNIEnv* env) {
1205 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1206 baseEnv(env)->ExceptionClear(env);
1207 CHECK_JNI_EXIT_VOID();
1208 }
1209
1210 static void FatalError(JNIEnv* env, const char* msg) {
1211 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg);
1212 baseEnv(env)->FatalError(env, msg);
1213 CHECK_JNI_EXIT_VOID();
1214 }
1215
1216 static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1217 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EI", env, capacity);
1218 return CHECK_JNI_EXIT("I", baseEnv(env)->PushLocalFrame(env, capacity));
1219 }
1220
1221 static jobject PopLocalFrame(JNIEnv* env, jobject res) {
1222 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, res);
1223 return CHECK_JNI_EXIT("L", baseEnv(env)->PopLocalFrame(env, res));
1224 }
1225
1226 static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
1227 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1228 return CHECK_JNI_EXIT("L", baseEnv(env)->NewGlobalRef(env, obj));
1229 }
1230
1231 static jobject NewLocalRef(JNIEnv* env, jobject ref) {
1232 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, ref);
1233 return CHECK_JNI_EXIT("L", baseEnv(env)->NewLocalRef(env, ref));
1234 }
1235
1236 static void DeleteGlobalRef(JNIEnv* env, jobject globalRef) {
1237 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef);
1238 if (globalRef != NULL && GetIndirectRefKind(globalRef) != kGlobal) {
1239 LOG(ERROR) << "JNI ERROR: DeleteGlobalRef on " << GetIndirectRefKind(globalRef) << ": " << globalRef;
1240 JniAbort(__FUNCTION__);
1241 } else {
1242 baseEnv(env)->DeleteGlobalRef(env, globalRef);
1243 CHECK_JNI_EXIT_VOID();
1244 }
1245 }
1246
1247 static void DeleteWeakGlobalRef(JNIEnv* env, jweak weakGlobalRef) {
1248 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, weakGlobalRef);
1249 if (weakGlobalRef != NULL && GetIndirectRefKind(weakGlobalRef) != kWeakGlobal) {
1250 LOG(ERROR) << "JNI ERROR: DeleteWeakGlobalRef on " << GetIndirectRefKind(weakGlobalRef) << ": " << weakGlobalRef;
1251 JniAbort(__FUNCTION__);
1252 } else {
1253 baseEnv(env)->DeleteWeakGlobalRef(env, weakGlobalRef);
1254 CHECK_JNI_EXIT_VOID();
1255 }
1256 }
1257
1258 static void DeleteLocalRef(JNIEnv* env, jobject localRef) {
1259 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef);
1260 if (localRef != NULL && GetIndirectRefKind(localRef) != kLocal) {
1261 LOG(ERROR) << "JNI ERROR: DeleteLocalRef on " << GetIndirectRefKind(localRef) << ": " << localRef;
1262 JniAbort(__FUNCTION__);
1263 } else {
1264 baseEnv(env)->DeleteLocalRef(env, localRef);
1265 CHECK_JNI_EXIT_VOID();
1266 }
1267 }
1268
1269 static jint EnsureLocalCapacity(JNIEnv *env, jint capacity) {
1270 CHECK_JNI_ENTRY(kFlag_Default, "EI", env, capacity);
1271 return CHECK_JNI_EXIT("I", baseEnv(env)->EnsureLocalCapacity(env, capacity));
1272 }
1273
1274 static jboolean IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) {
1275 CHECK_JNI_ENTRY(kFlag_Default, "ELL", env, ref1, ref2);
1276 return CHECK_JNI_EXIT("b", baseEnv(env)->IsSameObject(env, ref1, ref2));
1277 }
1278
1279 static jobject AllocObject(JNIEnv* env, jclass clazz) {
1280 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1281 return CHECK_JNI_EXIT("L", baseEnv(env)->AllocObject(env, clazz));
1282 }
1283
1284 static jobject NewObject(JNIEnv* env, jclass clazz, jmethodID mid, ...) {
1285 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1286 va_list args;
1287 va_start(args, mid);
1288 jobject result = baseEnv(env)->NewObjectV(env, clazz, mid, args);
1289 va_end(args);
1290 return CHECK_JNI_EXIT("L", result);
1291 }
1292
1293 static jobject NewObjectV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) {
1294 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1295 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectV(env, clazz, mid, args));
1296 }
1297
1298 static jobject NewObjectA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) {
1299 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1300 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectA(env, clazz, mid, args));
1301 }
1302
1303 static jclass GetObjectClass(JNIEnv* env, jobject obj) {
1304 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1305 return CHECK_JNI_EXIT("c", baseEnv(env)->GetObjectClass(env, obj));
1306 }
1307
1308 static jboolean IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz) {
1309 CHECK_JNI_ENTRY(kFlag_Default, "ELc", env, obj, clazz);
1310 return CHECK_JNI_EXIT("b", baseEnv(env)->IsInstanceOf(env, obj, clazz));
1311 }
1312
1313 static jmethodID GetMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1314 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1315 return CHECK_JNI_EXIT("m", baseEnv(env)->GetMethodID(env, clazz, name, sig));
1316 }
1317
1318 static jfieldID GetFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1319 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1320 return CHECK_JNI_EXIT("f", baseEnv(env)->GetFieldID(env, clazz, name, sig));
1321 }
1322
1323 static jmethodID GetStaticMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1324 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1325 return CHECK_JNI_EXIT("m", baseEnv(env)->GetStaticMethodID(env, clazz, name, sig));
1326 }
1327
1328 static jfieldID GetStaticFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1329 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1330 return CHECK_JNI_EXIT("f", baseEnv(env)->GetStaticFieldID(env, clazz, name, sig));
1331 }
1332
1333#define FIELD_ACCESSORS(_ctype, _jname, _type) \
1334 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fid) { \
1335 CHECK_JNI_ENTRY(kFlag_Default, "Ecf", env, clazz, fid); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001336 sc.CheckStaticFieldID(clazz, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001337 return CHECK_JNI_EXIT(_type, baseEnv(env)->GetStatic##_jname##Field(env, clazz, fid)); \
1338 } \
1339 static _ctype Get##_jname##Field(JNIEnv* env, jobject obj, jfieldID fid) { \
1340 CHECK_JNI_ENTRY(kFlag_Default, "ELf", env, obj, fid); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001341 sc.CheckInstanceFieldID(obj, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001342 return CHECK_JNI_EXIT(_type, baseEnv(env)->Get##_jname##Field(env, obj, fid)); \
1343 } \
1344 static void SetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fid, _ctype value) { \
1345 CHECK_JNI_ENTRY(kFlag_Default, "Ecf" _type, env, clazz, fid, value); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001346 sc.CheckStaticFieldID(clazz, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001347 /* "value" arg only used when type == ref */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001348 sc.CheckFieldType((jobject)(uint32_t)value, fid, _type[0], true); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001349 baseEnv(env)->SetStatic##_jname##Field(env, clazz, fid, value); \
1350 CHECK_JNI_EXIT_VOID(); \
1351 } \
1352 static void Set##_jname##Field(JNIEnv* env, jobject obj, jfieldID fid, _ctype value) { \
1353 CHECK_JNI_ENTRY(kFlag_Default, "ELf" _type, env, obj, fid, value); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001354 sc.CheckInstanceFieldID(obj, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001355 /* "value" arg only used when type == ref */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001356 sc.CheckFieldType((jobject)(uint32_t) value, fid, _type[0], false); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001357 baseEnv(env)->Set##_jname##Field(env, obj, fid, value); \
1358 CHECK_JNI_EXIT_VOID(); \
1359 }
1360
1361FIELD_ACCESSORS(jobject, Object, "L");
1362FIELD_ACCESSORS(jboolean, Boolean, "Z");
1363FIELD_ACCESSORS(jbyte, Byte, "B");
1364FIELD_ACCESSORS(jchar, Char, "C");
1365FIELD_ACCESSORS(jshort, Short, "S");
1366FIELD_ACCESSORS(jint, Int, "I");
1367FIELD_ACCESSORS(jlong, Long, "J");
1368FIELD_ACCESSORS(jfloat, Float, "F");
1369FIELD_ACCESSORS(jdouble, Double, "D");
1370
1371#define CALL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \
1372 /* Virtual... */ \
1373 static _ctype Call##_jname##Method(JNIEnv* env, jobject obj, \
1374 jmethodID mid, ...) \
1375 { \
1376 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001377 sc.CheckSig(mid, _retsig, false); \
1378 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001379 _retdecl; \
1380 va_list args; \
1381 va_start(args, mid); \
1382 _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, mid, args); \
1383 va_end(args); \
1384 _retok; \
1385 } \
1386 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject obj, \
1387 jmethodID mid, va_list args) \
1388 { \
1389 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001390 sc.CheckSig(mid, _retsig, false); \
1391 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001392 _retdecl; \
1393 _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, mid, args); \
1394 _retok; \
1395 } \
1396 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject obj, \
1397 jmethodID mid, jvalue* args) \
1398 { \
1399 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001400 sc.CheckSig(mid, _retsig, false); \
1401 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001402 _retdecl; \
1403 _retasgn baseEnv(env)->Call##_jname##MethodA(env, obj, mid, args); \
1404 _retok; \
1405 } \
1406 /* Non-virtual... */ \
1407 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, \
1408 jobject obj, jclass clazz, jmethodID mid, ...) \
1409 { \
1410 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001411 sc.CheckSig(mid, _retsig, false); \
1412 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001413 _retdecl; \
1414 va_list args; \
1415 va_start(args, mid); \
1416 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, mid, args); \
1417 va_end(args); \
1418 _retok; \
1419 } \
1420 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, \
1421 jobject obj, jclass clazz, jmethodID mid, va_list args) \
1422 { \
1423 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001424 sc.CheckSig(mid, _retsig, false); \
1425 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001426 _retdecl; \
1427 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, mid, args); \
1428 _retok; \
1429 } \
1430 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, \
1431 jobject obj, jclass clazz, jmethodID mid, jvalue* args) \
1432 { \
1433 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001434 sc.CheckSig(mid, _retsig, false); \
1435 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001436 _retdecl; \
1437 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodA(env, obj, clazz, mid, args); \
1438 _retok; \
1439 } \
1440 /* Static... */ \
1441 static _ctype CallStatic##_jname##Method(JNIEnv* env, \
1442 jclass clazz, jmethodID mid, ...) \
1443 { \
1444 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001445 sc.CheckSig(mid, _retsig, true); \
1446 sc.CheckStaticMethod(clazz, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001447 _retdecl; \
1448 va_list args; \
1449 va_start(args, mid); \
1450 _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, mid, args); \
1451 va_end(args); \
1452 _retok; \
1453 } \
1454 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, \
1455 jclass clazz, jmethodID mid, va_list args) \
1456 { \
1457 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001458 sc.CheckSig(mid, _retsig, true); \
1459 sc.CheckStaticMethod(clazz, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001460 _retdecl; \
1461 _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, mid, args); \
1462 _retok; \
1463 } \
1464 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, \
1465 jclass clazz, jmethodID mid, jvalue* args) \
1466 { \
1467 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001468 sc.CheckSig(mid, _retsig, true); \
1469 sc.CheckStaticMethod(clazz, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001470 _retdecl; \
1471 _retasgn baseEnv(env)->CallStatic##_jname##MethodA(env, clazz, mid, args); \
1472 _retok; \
1473 }
1474
1475#define NON_VOID_RETURN(_retsig, _ctype) return CHECK_JNI_EXIT(_retsig, (_ctype) result)
1476#define VOID_RETURN CHECK_JNI_EXIT_VOID()
1477
1478CALL(jobject, Object, Object* result, result=(Object*), NON_VOID_RETURN("L", jobject), "L");
1479CALL(jboolean, Boolean, jboolean result, result=, NON_VOID_RETURN("Z", jboolean), "Z");
1480CALL(jbyte, Byte, jbyte result, result=, NON_VOID_RETURN("B", jbyte), "B");
1481CALL(jchar, Char, jchar result, result=, NON_VOID_RETURN("C", jchar), "C");
1482CALL(jshort, Short, jshort result, result=, NON_VOID_RETURN("S", jshort), "S");
1483CALL(jint, Int, jint result, result=, NON_VOID_RETURN("I", jint), "I");
1484CALL(jlong, Long, jlong result, result=, NON_VOID_RETURN("J", jlong), "J");
1485CALL(jfloat, Float, jfloat result, result=, NON_VOID_RETURN("F", jfloat), "F");
1486CALL(jdouble, Double, jdouble result, result=, NON_VOID_RETURN("D", jdouble), "D");
1487CALL(void, Void, , , VOID_RETURN, "V");
1488
1489 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
1490 CHECK_JNI_ENTRY(kFlag_Default, "Epz", env, unicodeChars, len);
1491 return CHECK_JNI_EXIT("s", baseEnv(env)->NewString(env, unicodeChars, len));
1492 }
1493
1494 static jsize GetStringLength(JNIEnv* env, jstring string) {
1495 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1496 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringLength(env, string));
1497 }
1498
1499 static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* isCopy) {
1500 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, java_string, isCopy);
1501 const jchar* result = baseEnv(env)->GetStringChars(env, java_string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001502 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001503 ScopedJniThreadState ts(env);
1504 String* s = Decode<String*>(ts, java_string);
1505 int byteCount = s->GetLength() * 2;
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001506 result = (const jchar*) GuardedCopy::Create(result, byteCount, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001507 if (isCopy != NULL) {
1508 *isCopy = JNI_TRUE;
1509 }
1510 }
1511 return CHECK_JNI_EXIT("p", result);
1512 }
1513
1514 static void ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars) {
1515 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Esp", env, string, chars);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001516 sc.CheckNonNull(chars);
1517 if (sc.ForceCopy()) {
1518 GuardedCopy::Check(__FUNCTION__, chars, false);
1519 chars = (const jchar*) GuardedCopy::Destroy((jchar*)chars);
Elliott Hughesa2501992011-08-26 19:39:54 -07001520 }
1521 baseEnv(env)->ReleaseStringChars(env, string, chars);
1522 CHECK_JNI_EXIT_VOID();
1523 }
1524
1525 static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
1526 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, bytes); // TODO: show pointer and truncate string.
1527 return CHECK_JNI_EXIT("s", baseEnv(env)->NewStringUTF(env, bytes));
1528 }
1529
1530 static jsize GetStringUTFLength(JNIEnv* env, jstring string) {
1531 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1532 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringUTFLength(env, string));
1533 }
1534
1535 static const char* GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) {
1536 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy);
1537 const char* result = baseEnv(env)->GetStringUTFChars(env, string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001538 if (sc.ForceCopy() && result != NULL) {
1539 result = (const char*) GuardedCopy::Create(result, strlen(result) + 1, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001540 if (isCopy != NULL) {
1541 *isCopy = JNI_TRUE;
1542 }
1543 }
1544 return CHECK_JNI_EXIT("u", result); // TODO: show pointer and truncate string.
1545 }
1546
1547 static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf) {
1548 CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_Release, "Esu", env, string, utf); // TODO: show pointer and truncate string.
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001549 if (sc.ForceCopy()) {
1550 GuardedCopy::Check(__FUNCTION__, utf, false);
1551 utf = (const char*) GuardedCopy::Destroy((char*)utf);
Elliott Hughesa2501992011-08-26 19:39:54 -07001552 }
1553 baseEnv(env)->ReleaseStringUTFChars(env, string, utf);
1554 CHECK_JNI_EXIT_VOID();
1555 }
1556
1557 static jsize GetArrayLength(JNIEnv* env, jarray array) {
1558 CHECK_JNI_ENTRY(kFlag_CritOkay, "Ea", env, array);
1559 return CHECK_JNI_EXIT("I", baseEnv(env)->GetArrayLength(env, array));
1560 }
1561
1562 static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass elementClass, jobject initialElement) {
1563 CHECK_JNI_ENTRY(kFlag_Default, "EzcL", env, length, elementClass, initialElement);
1564 return CHECK_JNI_EXIT("a", baseEnv(env)->NewObjectArray(env, length, elementClass, initialElement));
1565 }
1566
1567 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
1568 CHECK_JNI_ENTRY(kFlag_Default, "EaI", env, array, index);
1569 return CHECK_JNI_EXIT("L", baseEnv(env)->GetObjectArrayElement(env, array, index));
1570 }
1571
1572 static void SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value) {
1573 CHECK_JNI_ENTRY(kFlag_Default, "EaIL", env, array, index, value);
1574 baseEnv(env)->SetObjectArrayElement(env, array, index, value);
1575 CHECK_JNI_EXIT_VOID();
1576 }
1577
1578#define NEW_PRIMITIVE_ARRAY(_artype, _jname) \
1579 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
1580 CHECK_JNI_ENTRY(kFlag_Default, "Ez", env, length); \
1581 return CHECK_JNI_EXIT("a", baseEnv(env)->New##_jname##Array(env, length)); \
1582 }
1583NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean);
1584NEW_PRIMITIVE_ARRAY(jbyteArray, Byte);
1585NEW_PRIMITIVE_ARRAY(jcharArray, Char);
1586NEW_PRIMITIVE_ARRAY(jshortArray, Short);
1587NEW_PRIMITIVE_ARRAY(jintArray, Int);
1588NEW_PRIMITIVE_ARRAY(jlongArray, Long);
1589NEW_PRIMITIVE_ARRAY(jfloatArray, Float);
1590NEW_PRIMITIVE_ARRAY(jdoubleArray, Double);
1591
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001592struct ForceCopyGetChecker {
Elliott Hughesa2501992011-08-26 19:39:54 -07001593public:
1594 ForceCopyGetChecker(ScopedCheck& sc, jboolean* isCopy) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001595 force_copy = sc.ForceCopy();
1596 no_copy = 0;
1597 if (force_copy && isCopy != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001598 /* capture this before the base call tramples on it */
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001599 no_copy = *(uint32_t*) isCopy;
Elliott Hughesa2501992011-08-26 19:39:54 -07001600 }
1601 }
1602
1603 template<typename ResultT>
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001604 ResultT Check(JNIEnv* env, jarray array, jboolean* isCopy, ResultT result) {
1605 if (force_copy && result != NULL) {
1606 if (no_copy != kNoCopyMagic) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001607 result = reinterpret_cast<ResultT>(CreateGuardedPACopy(env, array, isCopy));
1608 }
1609 }
1610 return result;
1611 }
1612
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001613 uint32_t no_copy;
1614 bool force_copy;
Elliott Hughesa2501992011-08-26 19:39:54 -07001615};
1616
1617#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1618 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, _ctype##Array array, jboolean* isCopy) { \
1619 CHECK_JNI_ENTRY(kFlag_Default, "Eap", env, array, isCopy); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001620 _ctype* result = ForceCopyGetChecker(sc, isCopy).Check(env, array, isCopy, baseEnv(env)->Get##_jname##ArrayElements(env, array, isCopy)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001621 return CHECK_JNI_EXIT("p", result); \
1622 }
1623
1624#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1625 static void Release##_jname##ArrayElements(JNIEnv* env, _ctype##Array array, _ctype* elems, jint mode) { \
1626 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Eapr", env, array, elems, mode); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001627 sc.CheckNonNull(elems); \
1628 if (sc.ForceCopy()) { \
Elliott Hughesa2501992011-08-26 19:39:54 -07001629 ReleaseGuardedPACopy(env, array, elems, mode); \
1630 } \
1631 baseEnv(env)->Release##_jname##ArrayElements(env, array, elems, mode); \
1632 CHECK_JNI_EXIT_VOID(); \
1633 }
1634
1635#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1636 static void Get##_jname##ArrayRegion(JNIEnv* env, _ctype##Array array, jsize start, jsize len, _ctype* buf) { \
1637 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1638 baseEnv(env)->Get##_jname##ArrayRegion(env, array, start, len, buf); \
1639 CHECK_JNI_EXIT_VOID(); \
1640 }
1641
1642#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1643 static void Set##_jname##ArrayRegion(JNIEnv* env, _ctype##Array array, jsize start, jsize len, const _ctype* buf) { \
1644 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1645 baseEnv(env)->Set##_jname##ArrayRegion(env, array, start, len, buf); \
1646 CHECK_JNI_EXIT_VOID(); \
1647 }
1648
1649#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname, _typechar) \
1650 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1651 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1652 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
1653 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
1654
1655/* TODO: verify primitive array type matches call type */
1656PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean, 'Z');
1657PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte, 'B');
1658PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char, 'C');
1659PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short, 'S');
1660PRIMITIVE_ARRAY_FUNCTIONS(jint, Int, 'I');
1661PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long, 'J');
1662PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float, 'F');
1663PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D');
1664
1665 static jint RegisterNatives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods, jint nMethods) {
1666 CHECK_JNI_ENTRY(kFlag_Default, "EcpI", env, clazz, methods, nMethods);
1667 return CHECK_JNI_EXIT("I", baseEnv(env)->RegisterNatives(env, clazz, methods, nMethods));
1668 }
1669
1670 static jint UnregisterNatives(JNIEnv* env, jclass clazz) {
1671 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1672 return CHECK_JNI_EXIT("I", baseEnv(env)->UnregisterNatives(env, clazz));
1673 }
1674
1675 static jint MonitorEnter(JNIEnv* env, jobject obj) {
1676 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1677 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorEnter(env, obj));
1678 }
1679
1680 static jint MonitorExit(JNIEnv* env, jobject obj) {
1681 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj);
1682 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorExit(env, obj));
1683 }
1684
1685 static jint GetJavaVM(JNIEnv *env, JavaVM **vm) {
1686 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, vm);
1687 return CHECK_JNI_EXIT("I", baseEnv(env)->GetJavaVM(env, vm));
1688 }
1689
1690 static void GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar* buf) {
1691 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1692 baseEnv(env)->GetStringRegion(env, str, start, len, buf);
1693 CHECK_JNI_EXIT_VOID();
1694 }
1695
1696 static void GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char* buf) {
1697 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1698 baseEnv(env)->GetStringUTFRegion(env, str, start, len, buf);
1699 CHECK_JNI_EXIT_VOID();
1700 }
1701
1702 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) {
1703 CHECK_JNI_ENTRY(kFlag_CritGet, "Eap", env, array, isCopy);
1704 void* result = baseEnv(env)->GetPrimitiveArrayCritical(env, array, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001705 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001706 result = CreateGuardedPACopy(env, array, isCopy);
1707 }
1708 return CHECK_JNI_EXIT("p", result);
1709 }
1710
1711 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode) {
1712 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Eapr", env, array, carray, mode);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001713 sc.CheckNonNull(carray);
1714 if (sc.ForceCopy()) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001715 ReleaseGuardedPACopy(env, array, carray, mode);
1716 }
1717 baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode);
1718 CHECK_JNI_EXIT_VOID();
1719 }
1720
1721 static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* isCopy) {
1722 CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, java_string, isCopy);
1723 const jchar* result = baseEnv(env)->GetStringCritical(env, java_string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001724 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001725 ScopedJniThreadState ts(env);
1726 String* s = Decode<String*>(ts, java_string);
1727 int byteCount = s->GetLength() * 2;
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001728 result = (const jchar*) GuardedCopy::Create(result, byteCount, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001729 if (isCopy != NULL) {
1730 *isCopy = JNI_TRUE;
1731 }
1732 }
1733 return CHECK_JNI_EXIT("p", result);
1734 }
1735
1736 static void ReleaseStringCritical(JNIEnv* env, jstring string, const jchar* carray) {
1737 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Esp", env, string, carray);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001738 sc.CheckNonNull(carray);
1739 if (sc.ForceCopy()) {
1740 GuardedCopy::Check(__FUNCTION__, carray, false);
1741 carray = (const jchar*) GuardedCopy::Destroy((jchar*)carray);
Elliott Hughesa2501992011-08-26 19:39:54 -07001742 }
1743 baseEnv(env)->ReleaseStringCritical(env, string, carray);
1744 CHECK_JNI_EXIT_VOID();
1745 }
1746
1747 static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
1748 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1749 return CHECK_JNI_EXIT("L", baseEnv(env)->NewWeakGlobalRef(env, obj));
1750 }
1751
1752 static jboolean ExceptionCheck(JNIEnv* env) {
1753 CHECK_JNI_ENTRY(kFlag_CritOkay | kFlag_ExcepOkay, "E", env);
1754 return CHECK_JNI_EXIT("b", baseEnv(env)->ExceptionCheck(env));
1755 }
1756
1757 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj) {
1758 // Note: we use "Ep" rather than "EL" because this is the one JNI function
1759 // that it's okay to pass an invalid reference to.
1760 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, obj);
1761 // TODO: proper decoding of jobjectRefType!
1762 return CHECK_JNI_EXIT("I", baseEnv(env)->GetObjectRefType(env, obj));
1763 }
1764
1765 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
1766 CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity);
1767 if (address == NULL) {
1768 LOG(ERROR) << "JNI ERROR: non-nullable address is NULL";
1769 JniAbort(__FUNCTION__);
1770 }
1771 if (capacity <= 0) {
1772 LOG(ERROR) << "JNI ERROR: capacity must be greater than 0: " << capacity;
1773 JniAbort(__FUNCTION__);
1774 }
1775 return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity));
1776 }
1777
1778 static void* GetDirectBufferAddress(JNIEnv* env, jobject buf) {
1779 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1780 // TODO: check that 'buf' is a java.nio.Buffer.
1781 return CHECK_JNI_EXIT("p", baseEnv(env)->GetDirectBufferAddress(env, buf));
1782 }
1783
1784 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
1785 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1786 // TODO: check that 'buf' is a java.nio.Buffer.
1787 return CHECK_JNI_EXIT("J", baseEnv(env)->GetDirectBufferCapacity(env, buf));
1788 }
1789
1790 private:
1791 static inline const JNINativeInterface* baseEnv(JNIEnv* env) {
1792 return reinterpret_cast<JNIEnvExt*>(env)->unchecked_functions;
1793 }
1794};
1795
1796const JNINativeInterface gCheckNativeInterface = {
1797 NULL, // reserved0.
1798 NULL, // reserved1.
1799 NULL, // reserved2.
1800 NULL, // reserved3.
1801 CheckJNI::GetVersion,
1802 CheckJNI::DefineClass,
1803 CheckJNI::FindClass,
1804 CheckJNI::FromReflectedMethod,
1805 CheckJNI::FromReflectedField,
1806 CheckJNI::ToReflectedMethod,
1807 CheckJNI::GetSuperclass,
1808 CheckJNI::IsAssignableFrom,
1809 CheckJNI::ToReflectedField,
1810 CheckJNI::Throw,
1811 CheckJNI::ThrowNew,
1812 CheckJNI::ExceptionOccurred,
1813 CheckJNI::ExceptionDescribe,
1814 CheckJNI::ExceptionClear,
1815 CheckJNI::FatalError,
1816 CheckJNI::PushLocalFrame,
1817 CheckJNI::PopLocalFrame,
1818 CheckJNI::NewGlobalRef,
1819 CheckJNI::DeleteGlobalRef,
1820 CheckJNI::DeleteLocalRef,
1821 CheckJNI::IsSameObject,
1822 CheckJNI::NewLocalRef,
1823 CheckJNI::EnsureLocalCapacity,
1824 CheckJNI::AllocObject,
1825 CheckJNI::NewObject,
1826 CheckJNI::NewObjectV,
1827 CheckJNI::NewObjectA,
1828 CheckJNI::GetObjectClass,
1829 CheckJNI::IsInstanceOf,
1830 CheckJNI::GetMethodID,
1831 CheckJNI::CallObjectMethod,
1832 CheckJNI::CallObjectMethodV,
1833 CheckJNI::CallObjectMethodA,
1834 CheckJNI::CallBooleanMethod,
1835 CheckJNI::CallBooleanMethodV,
1836 CheckJNI::CallBooleanMethodA,
1837 CheckJNI::CallByteMethod,
1838 CheckJNI::CallByteMethodV,
1839 CheckJNI::CallByteMethodA,
1840 CheckJNI::CallCharMethod,
1841 CheckJNI::CallCharMethodV,
1842 CheckJNI::CallCharMethodA,
1843 CheckJNI::CallShortMethod,
1844 CheckJNI::CallShortMethodV,
1845 CheckJNI::CallShortMethodA,
1846 CheckJNI::CallIntMethod,
1847 CheckJNI::CallIntMethodV,
1848 CheckJNI::CallIntMethodA,
1849 CheckJNI::CallLongMethod,
1850 CheckJNI::CallLongMethodV,
1851 CheckJNI::CallLongMethodA,
1852 CheckJNI::CallFloatMethod,
1853 CheckJNI::CallFloatMethodV,
1854 CheckJNI::CallFloatMethodA,
1855 CheckJNI::CallDoubleMethod,
1856 CheckJNI::CallDoubleMethodV,
1857 CheckJNI::CallDoubleMethodA,
1858 CheckJNI::CallVoidMethod,
1859 CheckJNI::CallVoidMethodV,
1860 CheckJNI::CallVoidMethodA,
1861 CheckJNI::CallNonvirtualObjectMethod,
1862 CheckJNI::CallNonvirtualObjectMethodV,
1863 CheckJNI::CallNonvirtualObjectMethodA,
1864 CheckJNI::CallNonvirtualBooleanMethod,
1865 CheckJNI::CallNonvirtualBooleanMethodV,
1866 CheckJNI::CallNonvirtualBooleanMethodA,
1867 CheckJNI::CallNonvirtualByteMethod,
1868 CheckJNI::CallNonvirtualByteMethodV,
1869 CheckJNI::CallNonvirtualByteMethodA,
1870 CheckJNI::CallNonvirtualCharMethod,
1871 CheckJNI::CallNonvirtualCharMethodV,
1872 CheckJNI::CallNonvirtualCharMethodA,
1873 CheckJNI::CallNonvirtualShortMethod,
1874 CheckJNI::CallNonvirtualShortMethodV,
1875 CheckJNI::CallNonvirtualShortMethodA,
1876 CheckJNI::CallNonvirtualIntMethod,
1877 CheckJNI::CallNonvirtualIntMethodV,
1878 CheckJNI::CallNonvirtualIntMethodA,
1879 CheckJNI::CallNonvirtualLongMethod,
1880 CheckJNI::CallNonvirtualLongMethodV,
1881 CheckJNI::CallNonvirtualLongMethodA,
1882 CheckJNI::CallNonvirtualFloatMethod,
1883 CheckJNI::CallNonvirtualFloatMethodV,
1884 CheckJNI::CallNonvirtualFloatMethodA,
1885 CheckJNI::CallNonvirtualDoubleMethod,
1886 CheckJNI::CallNonvirtualDoubleMethodV,
1887 CheckJNI::CallNonvirtualDoubleMethodA,
1888 CheckJNI::CallNonvirtualVoidMethod,
1889 CheckJNI::CallNonvirtualVoidMethodV,
1890 CheckJNI::CallNonvirtualVoidMethodA,
1891 CheckJNI::GetFieldID,
1892 CheckJNI::GetObjectField,
1893 CheckJNI::GetBooleanField,
1894 CheckJNI::GetByteField,
1895 CheckJNI::GetCharField,
1896 CheckJNI::GetShortField,
1897 CheckJNI::GetIntField,
1898 CheckJNI::GetLongField,
1899 CheckJNI::GetFloatField,
1900 CheckJNI::GetDoubleField,
1901 CheckJNI::SetObjectField,
1902 CheckJNI::SetBooleanField,
1903 CheckJNI::SetByteField,
1904 CheckJNI::SetCharField,
1905 CheckJNI::SetShortField,
1906 CheckJNI::SetIntField,
1907 CheckJNI::SetLongField,
1908 CheckJNI::SetFloatField,
1909 CheckJNI::SetDoubleField,
1910 CheckJNI::GetStaticMethodID,
1911 CheckJNI::CallStaticObjectMethod,
1912 CheckJNI::CallStaticObjectMethodV,
1913 CheckJNI::CallStaticObjectMethodA,
1914 CheckJNI::CallStaticBooleanMethod,
1915 CheckJNI::CallStaticBooleanMethodV,
1916 CheckJNI::CallStaticBooleanMethodA,
1917 CheckJNI::CallStaticByteMethod,
1918 CheckJNI::CallStaticByteMethodV,
1919 CheckJNI::CallStaticByteMethodA,
1920 CheckJNI::CallStaticCharMethod,
1921 CheckJNI::CallStaticCharMethodV,
1922 CheckJNI::CallStaticCharMethodA,
1923 CheckJNI::CallStaticShortMethod,
1924 CheckJNI::CallStaticShortMethodV,
1925 CheckJNI::CallStaticShortMethodA,
1926 CheckJNI::CallStaticIntMethod,
1927 CheckJNI::CallStaticIntMethodV,
1928 CheckJNI::CallStaticIntMethodA,
1929 CheckJNI::CallStaticLongMethod,
1930 CheckJNI::CallStaticLongMethodV,
1931 CheckJNI::CallStaticLongMethodA,
1932 CheckJNI::CallStaticFloatMethod,
1933 CheckJNI::CallStaticFloatMethodV,
1934 CheckJNI::CallStaticFloatMethodA,
1935 CheckJNI::CallStaticDoubleMethod,
1936 CheckJNI::CallStaticDoubleMethodV,
1937 CheckJNI::CallStaticDoubleMethodA,
1938 CheckJNI::CallStaticVoidMethod,
1939 CheckJNI::CallStaticVoidMethodV,
1940 CheckJNI::CallStaticVoidMethodA,
1941 CheckJNI::GetStaticFieldID,
1942 CheckJNI::GetStaticObjectField,
1943 CheckJNI::GetStaticBooleanField,
1944 CheckJNI::GetStaticByteField,
1945 CheckJNI::GetStaticCharField,
1946 CheckJNI::GetStaticShortField,
1947 CheckJNI::GetStaticIntField,
1948 CheckJNI::GetStaticLongField,
1949 CheckJNI::GetStaticFloatField,
1950 CheckJNI::GetStaticDoubleField,
1951 CheckJNI::SetStaticObjectField,
1952 CheckJNI::SetStaticBooleanField,
1953 CheckJNI::SetStaticByteField,
1954 CheckJNI::SetStaticCharField,
1955 CheckJNI::SetStaticShortField,
1956 CheckJNI::SetStaticIntField,
1957 CheckJNI::SetStaticLongField,
1958 CheckJNI::SetStaticFloatField,
1959 CheckJNI::SetStaticDoubleField,
1960 CheckJNI::NewString,
1961 CheckJNI::GetStringLength,
1962 CheckJNI::GetStringChars,
1963 CheckJNI::ReleaseStringChars,
1964 CheckJNI::NewStringUTF,
1965 CheckJNI::GetStringUTFLength,
1966 CheckJNI::GetStringUTFChars,
1967 CheckJNI::ReleaseStringUTFChars,
1968 CheckJNI::GetArrayLength,
1969 CheckJNI::NewObjectArray,
1970 CheckJNI::GetObjectArrayElement,
1971 CheckJNI::SetObjectArrayElement,
1972 CheckJNI::NewBooleanArray,
1973 CheckJNI::NewByteArray,
1974 CheckJNI::NewCharArray,
1975 CheckJNI::NewShortArray,
1976 CheckJNI::NewIntArray,
1977 CheckJNI::NewLongArray,
1978 CheckJNI::NewFloatArray,
1979 CheckJNI::NewDoubleArray,
1980 CheckJNI::GetBooleanArrayElements,
1981 CheckJNI::GetByteArrayElements,
1982 CheckJNI::GetCharArrayElements,
1983 CheckJNI::GetShortArrayElements,
1984 CheckJNI::GetIntArrayElements,
1985 CheckJNI::GetLongArrayElements,
1986 CheckJNI::GetFloatArrayElements,
1987 CheckJNI::GetDoubleArrayElements,
1988 CheckJNI::ReleaseBooleanArrayElements,
1989 CheckJNI::ReleaseByteArrayElements,
1990 CheckJNI::ReleaseCharArrayElements,
1991 CheckJNI::ReleaseShortArrayElements,
1992 CheckJNI::ReleaseIntArrayElements,
1993 CheckJNI::ReleaseLongArrayElements,
1994 CheckJNI::ReleaseFloatArrayElements,
1995 CheckJNI::ReleaseDoubleArrayElements,
1996 CheckJNI::GetBooleanArrayRegion,
1997 CheckJNI::GetByteArrayRegion,
1998 CheckJNI::GetCharArrayRegion,
1999 CheckJNI::GetShortArrayRegion,
2000 CheckJNI::GetIntArrayRegion,
2001 CheckJNI::GetLongArrayRegion,
2002 CheckJNI::GetFloatArrayRegion,
2003 CheckJNI::GetDoubleArrayRegion,
2004 CheckJNI::SetBooleanArrayRegion,
2005 CheckJNI::SetByteArrayRegion,
2006 CheckJNI::SetCharArrayRegion,
2007 CheckJNI::SetShortArrayRegion,
2008 CheckJNI::SetIntArrayRegion,
2009 CheckJNI::SetLongArrayRegion,
2010 CheckJNI::SetFloatArrayRegion,
2011 CheckJNI::SetDoubleArrayRegion,
2012 CheckJNI::RegisterNatives,
2013 CheckJNI::UnregisterNatives,
2014 CheckJNI::MonitorEnter,
2015 CheckJNI::MonitorExit,
2016 CheckJNI::GetJavaVM,
2017 CheckJNI::GetStringRegion,
2018 CheckJNI::GetStringUTFRegion,
2019 CheckJNI::GetPrimitiveArrayCritical,
2020 CheckJNI::ReleasePrimitiveArrayCritical,
2021 CheckJNI::GetStringCritical,
2022 CheckJNI::ReleaseStringCritical,
2023 CheckJNI::NewWeakGlobalRef,
2024 CheckJNI::DeleteWeakGlobalRef,
2025 CheckJNI::ExceptionCheck,
2026 CheckJNI::NewDirectByteBuffer,
2027 CheckJNI::GetDirectBufferAddress,
2028 CheckJNI::GetDirectBufferCapacity,
2029 CheckJNI::GetObjectRefType,
2030};
2031
2032const JNINativeInterface* GetCheckJniNativeInterface() {
2033 return &gCheckNativeInterface;
2034}
2035
2036class CheckJII {
2037public:
2038 static jint DestroyJavaVM(JavaVM* vm) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002039 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002040 sc.Check(true, "v", vm);
2041 return CHECK_JNI_EXIT("I", BaseVm(vm)->DestroyJavaVM(vm));
Elliott Hughesa2501992011-08-26 19:39:54 -07002042 }
2043
2044 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002045 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002046 sc.Check(true, "vpp", vm, p_env, thr_args);
2047 return CHECK_JNI_EXIT("I", BaseVm(vm)->AttachCurrentThread(vm, p_env, thr_args));
Elliott Hughesa2501992011-08-26 19:39:54 -07002048 }
2049
2050 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002051 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002052 sc.Check(true, "vpp", vm, p_env, thr_args);
2053 return CHECK_JNI_EXIT("I", BaseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args));
Elliott Hughesa2501992011-08-26 19:39:54 -07002054 }
2055
2056 static jint DetachCurrentThread(JavaVM* vm) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002057 ScopedCheck sc(vm, true, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002058 sc.Check(true, "v", vm);
2059 return CHECK_JNI_EXIT("I", BaseVm(vm)->DetachCurrentThread(vm));
Elliott Hughesa2501992011-08-26 19:39:54 -07002060 }
2061
2062 static jint GetEnv(JavaVM* vm, void** env, jint version) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002063 ScopedCheck sc(vm, true, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002064 sc.Check(true, "v", vm);
2065 return CHECK_JNI_EXIT("I", BaseVm(vm)->GetEnv(vm, env, version));
Elliott Hughesa2501992011-08-26 19:39:54 -07002066 }
2067
2068 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002069 static inline const JNIInvokeInterface* BaseVm(JavaVM* vm) {
Elliott Hughesa2501992011-08-26 19:39:54 -07002070 return reinterpret_cast<JavaVMExt*>(vm)->unchecked_functions;
2071 }
2072};
2073
2074const JNIInvokeInterface gCheckInvokeInterface = {
2075 NULL, // reserved0
2076 NULL, // reserved1
2077 NULL, // reserved2
2078 CheckJII::DestroyJavaVM,
2079 CheckJII::AttachCurrentThread,
2080 CheckJII::DetachCurrentThread,
2081 CheckJII::GetEnv,
2082 CheckJII::AttachCurrentThreadAsDaemon
2083};
2084
2085const JNIInvokeInterface* GetCheckJniInvokeInterface() {
2086 return &gCheckInvokeInterface;
2087}
2088
2089} // namespace art