CheckJni.cpp revision 3eb978998db281d704ec9146efb06ae3420ac3c6
1/* 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/* 18 * Support for -Xcheck:jni (the "careful" version of the JNI interfaces). 19 * 20 * We want to verify types, make sure class and field IDs are valid, and 21 * ensure that JNI's semantic expectations are being met. JNI seems to 22 * be relatively lax when it comes to requirements for permission checks, 23 * e.g. access to private methods is generally allowed from anywhere. 24 */ 25 26#include "Dalvik.h" 27#include "JniInternal.h" 28 29#include <sys/mman.h> 30#include <zlib.h> 31 32/* 33 * Abort if we are configured to bail out on JNI warnings. 34 */ 35static void abortMaybe() { 36 if (!gDvmJni.warnOnly) { 37 dvmDumpThread(dvmThreadSelf(), false); 38 dvmAbort(); 39 } 40} 41 42/* 43 * =========================================================================== 44 * JNI call bridge wrapper 45 * =========================================================================== 46 */ 47 48/* 49 * Check the result of a native method call that returns an object reference. 50 * 51 * The primary goal here is to verify that native code is returning the 52 * correct type of object. If it's declared to return a String but actually 53 * returns a byte array, things will fail in strange ways later on. 54 * 55 * This can be a fairly expensive operation, since we have to look up the 56 * return type class by name in method->clazz' class loader. We take a 57 * shortcut here and allow the call to succeed if the descriptor strings 58 * match. This will allow some false-positives when a class is redefined 59 * by a class loader, but that's rare enough that it doesn't seem worth 60 * testing for. 61 * 62 * At this point, pResult->l has already been converted to an object pointer. 63 */ 64static void checkCallResultCommon(const u4* args, const JValue* pResult, 65 const Method* method, Thread* self) 66{ 67 assert(pResult->l != NULL); 68 const Object* resultObj = (const Object*) pResult->l; 69 70 if (resultObj == kInvalidIndirectRefObject) { 71 LOGW("JNI WARNING: invalid reference returned from native code"); 72 const Method* method = dvmGetCurrentJNIMethod(); 73 char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 74 LOGW(" in %s.%s:%s", method->clazz->descriptor, method->name, desc); 75 free(desc); 76 abortMaybe(); 77 return; 78 } 79 80 ClassObject* objClazz = resultObj->clazz; 81 82 /* 83 * Make sure that pResult->l is an instance of the type this 84 * method was expected to return. 85 */ 86 const char* declType = dexProtoGetReturnType(&method->prototype); 87 const char* objType = objClazz->descriptor; 88 if (strcmp(declType, objType) == 0) { 89 /* names match; ignore class loader issues and allow it */ 90 LOGV("Check %s.%s: %s io %s (FAST-OK)", 91 method->clazz->descriptor, method->name, objType, declType); 92 } else { 93 /* 94 * Names didn't match. We need to resolve declType in the context 95 * of method->clazz->classLoader, and compare the class objects 96 * for equality. 97 * 98 * Since we're returning an instance of declType, it's safe to 99 * assume that it has been loaded and initialized (or, for the case 100 * of an array, generated). However, the current class loader may 101 * not be listed as an initiating loader, so we can't just look for 102 * it in the loaded-classes list. 103 */ 104 ClassObject* declClazz = dvmFindClassNoInit(declType, method->clazz->classLoader); 105 if (declClazz == NULL) { 106 LOGW("JNI WARNING: method declared to return '%s' returned '%s'", 107 declType, objType); 108 LOGW(" failed in %s.%s ('%s' not found)", 109 method->clazz->descriptor, method->name, declType); 110 abortMaybe(); 111 return; 112 } 113 if (!dvmInstanceof(objClazz, declClazz)) { 114 LOGW("JNI WARNING: method declared to return '%s' returned '%s'", 115 declType, objType); 116 LOGW(" failed in %s.%s", 117 method->clazz->descriptor, method->name); 118 abortMaybe(); 119 return; 120 } else { 121 LOGV("Check %s.%s: %s io %s (SLOW-OK)", 122 method->clazz->descriptor, method->name, objType, declType); 123 } 124 } 125} 126 127/* 128 * Determine if we need to check the return type coming out of the call. 129 * 130 * (We don't simply do this at the top of checkCallResultCommon() because 131 * this is on the critical path for native method calls.) 132 */ 133static inline bool callNeedsCheck(const u4* args, JValue* pResult, 134 const Method* method, Thread* self) 135{ 136 return (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL); 137} 138 139/* 140 * Check a call into native code. 141 */ 142void dvmCheckCallJNIMethod(const u4* args, JValue* pResult, 143 const Method* method, Thread* self) 144{ 145 dvmCallJNIMethod(args, pResult, method, self); 146 if (callNeedsCheck(args, pResult, method, self)) { 147 checkCallResultCommon(args, pResult, method, self); 148 } 149} 150 151/* 152 * =========================================================================== 153 * JNI function helpers 154 * =========================================================================== 155 */ 156 157static inline const JNINativeInterface* baseEnv(JNIEnv* env) { 158 return ((JNIEnvExt*) env)->baseFuncTable; 159} 160 161static inline const JNIInvokeInterface* baseVm(JavaVM* vm) { 162 return ((JavaVMExt*) vm)->baseFuncTable; 163} 164 165class ScopedJniThreadState { 166public: 167 explicit ScopedJniThreadState(JNIEnv* env) { 168 dvmChangeStatus(NULL, THREAD_RUNNING); 169 } 170 171 ~ScopedJniThreadState() { 172 dvmChangeStatus(NULL, THREAD_NATIVE); 173 } 174 175private: 176 // Disallow copy and assignment. 177 ScopedJniThreadState(const ScopedJniThreadState&); 178 void operator=(const ScopedJniThreadState&); 179}; 180 181/* 182 * Flags passed into ScopedCheck. 183 */ 184#define kFlag_Default 0x0000 185 186#define kFlag_CritBad 0x0000 /* calling while in critical is bad */ 187#define kFlag_CritOkay 0x0001 /* ...okay */ 188#define kFlag_CritGet 0x0002 /* this is a critical "get" */ 189#define kFlag_CritRelease 0x0003 /* this is a critical "release" */ 190#define kFlag_CritMask 0x0003 /* bit mask to get "crit" value */ 191 192#define kFlag_ExcepBad 0x0000 /* raised exceptions are bad */ 193#define kFlag_ExcepOkay 0x0004 /* ...okay */ 194 195#define kFlag_Release 0x0010 /* are we in a non-critical release function? */ 196#define kFlag_NullableUtf 0x0020 /* are our UTF parameters nullable? */ 197 198#define kFlag_Invocation 0x8000 /* Part of the invocation interface (JavaVM*) */ 199 200static const char* indirectRefKindName(IndirectRef iref) 201{ 202 return indirectRefKindToString(indirectRefKind(iref)); 203} 204 205class ScopedCheck { 206public: 207 // For JNIEnv* functions. 208 explicit ScopedCheck(JNIEnv* env, int flags, const char* functionName) { 209 init(env, flags, functionName, true); 210 checkThread(flags); 211 } 212 213 // For JavaVM* functions. 214 explicit ScopedCheck(bool hasMethod, const char* functionName) { 215 init(NULL, kFlag_Invocation, functionName, hasMethod); 216 } 217 218 /* 219 * In some circumstances the VM will screen class names, but it doesn't 220 * for class lookup. When things get bounced through a class loader, they 221 * can actually get normalized a couple of times; as a result, passing in 222 * a class name like "java.lang.Thread" instead of "java/lang/Thread" will 223 * work in some circumstances. 224 * 225 * This is incorrect and could cause strange behavior or compatibility 226 * problems, so we want to screen that out here. 227 * 228 * We expect "fully-qualified" class names, like "java/lang/Thread" or 229 * "[Ljava/lang/Object;". 230 */ 231 void checkClassName(const char* className) { 232 if (!dexIsValidClassName(className, false)) { 233 LOGW("JNI WARNING: illegal class name '%s' (%s)", className, mFunctionName); 234 LOGW(" (should be formed like 'dalvik/system/DexFile')"); 235 LOGW(" or '[Ldalvik/system/DexFile;' or '[[B')"); 236 abortMaybe(); 237 } 238 } 239 240 void checkFieldTypeForGet(jfieldID fid, const char* expectedSignature, bool isStatic) { 241 if (fid == NULL) { 242 LOGW("JNI WARNING: null jfieldID"); 243 showLocation(); 244 abortMaybe(); 245 } 246 247 bool printWarn = false; 248 Field* field = (Field*) fid; 249 const char* actualSignature = field->signature; 250 if (*expectedSignature == 'L') { 251 // 'actualSignature' has the exact type. 252 // We just know we're expecting some kind of reference. 253 if (*actualSignature != 'L' && *actualSignature != '[') { 254 printWarn = true; 255 } 256 } else if (*actualSignature != *expectedSignature) { 257 printWarn = true; 258 } 259 260 if (!printWarn && isStatic && !dvmIsStaticField(field)) { 261 if (isStatic) { 262 LOGW("JNI WARNING: accessing non-static field %s as static", field->name); 263 } else { 264 LOGW("JNI WARNING: accessing static field %s as non-static", field->name); 265 } 266 printWarn = true; 267 } 268 269 if (printWarn) { 270 LOGW("JNI WARNING: %s for field '%s' of expected type %s, got %s", 271 mFunctionName, field->name, expectedSignature, actualSignature); 272 showLocation(); 273 abortMaybe(); 274 } 275 } 276 277 /* 278 * Verify that the field is of the appropriate type. If the field has an 279 * object type, "jobj" is the object we're trying to assign into it. 280 * 281 * Works for both static and instance fields. 282 */ 283 void checkFieldTypeForSet(jobject jobj, jfieldID fieldID, PrimitiveType prim, bool isStatic) { 284 if (fieldID == NULL) { 285 LOGW("JNI WARNING: null jfieldID"); 286 showLocation(); 287 abortMaybe(); 288 } 289 290 bool printWarn = false; 291 Field* field = (Field*) fieldID; 292 if ((field->signature[0] == 'L' || field->signature[0] == '[') && jobj != NULL) { 293 ScopedJniThreadState ts(mEnv); 294 Object* obj = dvmDecodeIndirectRef(mEnv, jobj); 295 /* 296 * If jobj is a weak global ref whose referent has been cleared, 297 * obj will be NULL. Otherwise, obj should always be non-NULL 298 * and valid. 299 */ 300 if (obj != NULL && !dvmIsHeapAddress(obj)) { 301 LOGW("JNI WARNING: field operation on invalid %s reference (%p)", 302 indirectRefKindName(jobj), jobj); 303 printWarn = true; 304 } else { 305 ClassObject* fieldClass = dvmFindLoadedClass(field->signature); 306 ClassObject* objClass = obj->clazz; 307 308 assert(fieldClass != NULL); 309 assert(objClass != NULL); 310 311 if (!dvmInstanceof(objClass, fieldClass)) { 312 LOGW("JNI WARNING: set field '%s' expected type %s, got %s", 313 field->name, field->signature, objClass->descriptor); 314 printWarn = true; 315 } 316 } 317 } else if (dexGetPrimitiveTypeFromDescriptorChar(field->signature[0]) != prim) { 318 LOGW("JNI WARNING: %s for field '%s' expected type %s, got %s", 319 mFunctionName, field->name, field->signature, primitiveTypeToName(prim)); 320 printWarn = true; 321 } else if (isStatic && !dvmIsStaticField(field)) { 322 if (isStatic) { 323 LOGW("JNI WARNING: accessing non-static field %s as static", field->name); 324 } else { 325 LOGW("JNI WARNING: accessing static field %s as non-static", field->name); 326 } 327 printWarn = true; 328 } 329 330 if (printWarn) { 331 showLocation(); 332 abortMaybe(); 333 } 334 } 335 336 /* 337 * Verify that this instance field ID is valid for this object. 338 * 339 * Assumes "jobj" has already been validated. 340 */ 341 void checkInstanceFieldID(jobject jobj, jfieldID fieldID) { 342 ScopedJniThreadState ts(mEnv); 343 344 Object* obj = dvmDecodeIndirectRef(mEnv, jobj); 345 if (!dvmIsHeapAddress(obj)) { 346 LOGW("JNI ERROR: field operation on invalid reference (%p)", jobj); 347 dvmAbort(); 348 } 349 350 /* 351 * Check this class and all of its superclasses for a matching field. 352 * Don't need to scan interfaces. 353 */ 354 ClassObject* clazz = obj->clazz; 355 while (clazz != NULL) { 356 if ((InstField*) fieldID >= clazz->ifields && 357 (InstField*) fieldID < clazz->ifields + clazz->ifieldCount) { 358 return; 359 } 360 361 clazz = clazz->super; 362 } 363 364 LOGW("JNI WARNING: instance fieldID %p not valid for class %s", 365 fieldID, obj->clazz->descriptor); 366 showLocation(); 367 abortMaybe(); 368 } 369 370 /* 371 * Verify that the pointer value is non-NULL. 372 */ 373 void checkNonNull(const void* ptr) { 374 if (ptr == NULL) { 375 LOGW("JNI WARNING: invalid null pointer (%s)", mFunctionName); 376 abortMaybe(); 377 } 378 } 379 380 /* 381 * Verify that the method's return type matches the type of call. 382 * 'expectedType' will be "L" for all objects, including arrays. 383 */ 384 void checkSig(jmethodID methodID, const char* expectedType, bool isStatic) { 385 const Method* method = (const Method*) methodID; 386 bool printWarn = false; 387 388 if (*expectedType != method->shorty[0]) { 389 LOGW("JNI WARNING: expected return type '%s'", expectedType); 390 printWarn = true; 391 } else if (isStatic && !dvmIsStaticMethod(method)) { 392 if (isStatic) { 393 LOGW("JNI WARNING: calling non-static method with static call"); 394 } else { 395 LOGW("JNI WARNING: calling static method with non-static call"); 396 } 397 printWarn = true; 398 } 399 400 if (printWarn) { 401 char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 402 LOGW(" calling %s.%s %s", method->clazz->descriptor, method->name, desc); 403 free(desc); 404 showLocation(); 405 abortMaybe(); 406 } 407 } 408 409 /* 410 * Verify that this static field ID is valid for this class. 411 * 412 * Assumes "jclazz" has already been validated. 413 */ 414 void checkStaticFieldID(jclass jclazz, jfieldID fieldID) { 415 ScopedJniThreadState ts(mEnv); 416 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(mEnv, jclazz); 417 StaticField* base = &clazz->sfields[0]; 418 int fieldCount = clazz->sfieldCount; 419 if ((StaticField*) fieldID < base || (StaticField*) fieldID >= base + fieldCount) { 420 LOGW("JNI WARNING: static fieldID %p not valid for class %s", 421 fieldID, clazz->descriptor); 422 LOGW(" base=%p count=%d", base, fieldCount); 423 showLocation(); 424 abortMaybe(); 425 } 426 } 427 428 /* 429 * Verify that "methodID" is appropriate for "clazz". 430 * 431 * A mismatch isn't dangerous, because the jmethodID defines the class. In 432 * fact, jclazz is unused in the implementation. It's best if we don't 433 * allow bad code in the system though. 434 * 435 * Instances of "jclazz" must be instances of the method's declaring class. 436 */ 437 void checkStaticMethod(jclass jclazz, jmethodID methodID) { 438 ScopedJniThreadState ts(mEnv); 439 440 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(mEnv, jclazz); 441 const Method* method = (const Method*) methodID; 442 443 if (!dvmInstanceof(clazz, method->clazz)) { 444 LOGW("JNI WARNING: can't call static %s.%s on class %s", 445 method->clazz->descriptor, method->name, clazz->descriptor); 446 showLocation(); 447 // no abort? 448 } 449 } 450 451 /* 452 * Verify that "methodID" is appropriate for "jobj". 453 * 454 * Make sure the object is an instance of the method's declaring class. 455 * (Note the methodID might point to a declaration in an interface; this 456 * will be handled automatically by the instanceof check.) 457 */ 458 void checkVirtualMethod(jobject jobj, jmethodID methodID) { 459 ScopedJniThreadState ts(mEnv); 460 461 Object* obj = dvmDecodeIndirectRef(mEnv, jobj); 462 const Method* method = (const Method*) methodID; 463 464 if (!dvmInstanceof(obj->clazz, method->clazz)) { 465 LOGW("JNI WARNING: can't call %s.%s on instance of %s", 466 method->clazz->descriptor, method->name, obj->clazz->descriptor); 467 showLocation(); 468 abortMaybe(); 469 } 470 } 471 472 /** 473 * The format string is a sequence of the following characters, 474 * and must be followed by arguments of the corresponding types 475 * in the same order. 476 * 477 * Java primitive types: 478 * B - jbyte 479 * C - jchar 480 * D - jdouble 481 * F - jfloat 482 * I - jint 483 * J - jlong 484 * S - jshort 485 * Z - jboolean (shown as true and false) 486 * V - void 487 * 488 * Java reference types: 489 * L - jobject 490 * a - jarray 491 * c - jclass 492 * s - jstring 493 * 494 * JNI types: 495 * b - jboolean (shown as JNI_TRUE and JNI_FALSE) 496 * f - jfieldID 497 * m - jmethodID 498 * p - void* 499 * r - jint (for release mode arguments) 500 * u - const char* (modified UTF-8) 501 * z - jsize (for lengths; use i if negative values are okay) 502 * v - JavaVM* 503 * E - JNIEnv* 504 * . - no argument; just print "..." (used for varargs JNI calls) 505 * 506 * Use the kFlag_NullableUtf flag where 'u' field(s) are nullable. 507 */ 508 void check(bool entry, const char* fmt0, ...) { 509 va_list ap; 510 511 bool shouldTrace = false; 512 const Method* method = NULL; 513 if ((gDvm.jniTrace || gDvmJni.logThirdPartyJni) && mHasMethod) { 514 // We need to guard some of the invocation interface's calls: a bad caller might 515 // use DetachCurrentThread or GetEnv on a thread that's not yet attached. 516 if ((mFlags & kFlag_Invocation) == 0 || dvmThreadSelf() != NULL) { 517 method = dvmGetCurrentJNIMethod(); 518 } 519 } 520 if (method != NULL) { 521 // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages 522 // when a native method that matches the Xjnitrace argument calls a JNI function 523 // such as NewByteArray. 524 if (gDvm.jniTrace && strstr(method->clazz->descriptor, gDvm.jniTrace) != NULL) { 525 shouldTrace = true; 526 } 527 // If -Xjniopts:logThirdPartyJni is on, we want to log any JNI function calls 528 // made by a third-party native method. 529 if (gDvmJni.logThirdPartyJni) { 530 shouldTrace |= method->shouldTrace; 531 } 532 } 533 534 if (shouldTrace) { 535 va_start(ap, fmt0); 536 std::string msg; 537 for (const char* fmt = fmt0; *fmt;) { 538 char ch = *fmt++; 539 if (ch == 'B') { // jbyte 540 jbyte b = va_arg(ap, int); 541 if (b >= 0 && b < 10) { 542 StringAppendF(&msg, "%d", b); 543 } else { 544 StringAppendF(&msg, "%#x (%d)", b, b); 545 } 546 } else if (ch == 'C') { // jchar 547 jchar c = va_arg(ap, int); 548 if (c < 0x7f && c >= ' ') { 549 StringAppendF(&msg, "U+%x ('%c')", c, c); 550 } else { 551 StringAppendF(&msg, "U+%x", c); 552 } 553 } else if (ch == 'F' || ch == 'D') { // jfloat, jdouble 554 StringAppendF(&msg, "%g", va_arg(ap, double)); 555 } else if (ch == 'I' || ch == 'S') { // jint, jshort 556 StringAppendF(&msg, "%d", va_arg(ap, int)); 557 } else if (ch == 'J') { // jlong 558 StringAppendF(&msg, "%lld", va_arg(ap, jlong)); 559 } else if (ch == 'Z') { // jboolean 560 StringAppendF(&msg, "%s", va_arg(ap, int) ? "true" : "false"); 561 } else if (ch == 'V') { // void 562 msg += "void"; 563 } else if (ch == 'v') { // JavaVM* 564 JavaVM* vm = va_arg(ap, JavaVM*); 565 StringAppendF(&msg, "(JavaVM*)%p", vm); 566 } else if (ch == 'E') { // JNIEnv* 567 JNIEnv* env = va_arg(ap, JNIEnv*); 568 StringAppendF(&msg, "(JNIEnv*)%p", env); 569 } else if (ch == 'L' || ch == 'a' || ch == 's') { // jobject, jarray, jstring 570 // For logging purposes, these are identical. 571 jobject o = va_arg(ap, jobject); 572 if (o == NULL) { 573 msg += "NULL"; 574 } else { 575 StringAppendF(&msg, "%p", o); 576 } 577 } else if (ch == 'b') { // jboolean (JNI-style) 578 jboolean b = va_arg(ap, int); 579 msg += (b ? "JNI_TRUE" : "JNI_FALSE"); 580 } else if (ch == 'c') { // jclass 581 jclass jc = va_arg(ap, jclass); 582 Object* c = dvmDecodeIndirectRef(mEnv, jc); 583 if (c == NULL) { 584 msg += "NULL"; 585 } else if (c == kInvalidIndirectRefObject || !dvmIsHeapAddress(c)) { 586 StringAppendF(&msg, "%p(INVALID)", jc); 587 } else { 588 std::string className(dvmHumanReadableType(c)); 589 StringAppendF(&msg, "%s", className.c_str()); 590 if (!entry) { 591 StringAppendF(&msg, " (%p)", jc); 592 } 593 } 594 } else if (ch == 'f') { // jfieldID 595 jfieldID fid = va_arg(ap, jfieldID); 596 std::string name(dvmHumanReadableField((Field*) fid)); 597 StringAppendF(&msg, "%s", name.c_str()); 598 if (!entry) { 599 StringAppendF(&msg, " (%p)", fid); 600 } 601 } else if (ch == 'z') { // non-negative jsize 602 // You might expect jsize to be size_t, but it's not; it's the same as jint. 603 // We only treat this specially so we can do the non-negative check. 604 // TODO: maybe this wasn't worth it? 605 jint i = va_arg(ap, jint); 606 StringAppendF(&msg, "%d", i); 607 } else if (ch == 'm') { // jmethodID 608 jmethodID mid = va_arg(ap, jmethodID); 609 std::string name(dvmHumanReadableMethod((Method*) mid, true)); 610 StringAppendF(&msg, "%s", name.c_str()); 611 if (!entry) { 612 StringAppendF(&msg, " (%p)", mid); 613 } 614 } else if (ch == 'p') { // void* ("pointer") 615 void* p = va_arg(ap, void*); 616 if (p == NULL) { 617 msg += "NULL"; 618 } else { 619 StringAppendF(&msg, "(void*) %p", p); 620 } 621 } else if (ch == 'r') { // jint (release mode) 622 jint releaseMode = va_arg(ap, jint); 623 if (releaseMode == 0) { 624 msg += "0"; 625 } else if (releaseMode == JNI_ABORT) { 626 msg += "JNI_ABORT"; 627 } else if (releaseMode == JNI_COMMIT) { 628 msg += "JNI_COMMIT"; 629 } else { 630 StringAppendF(&msg, "invalid release mode %d", releaseMode); 631 } 632 } else if (ch == 'u') { // const char* (modified UTF-8) 633 const char* utf = va_arg(ap, const char*); 634 if (utf == NULL) { 635 msg += "NULL"; 636 } else { 637 StringAppendF(&msg, "\"%s\"", utf); 638 } 639 } else if (ch == '.') { 640 msg += "..."; 641 } else { 642 LOGE("unknown trace format specifier %c", ch); 643 dvmAbort(); 644 } 645 if (*fmt) { 646 StringAppendF(&msg, ", "); 647 } 648 } 649 va_end(ap); 650 651 if (entry) { 652 if (mHasMethod) { 653 std::string methodName(dvmHumanReadableMethod(method, false)); 654 LOGI("JNI: %s -> %s(%s)", methodName.c_str(), mFunctionName, msg.c_str()); 655 mIndent = methodName.size() + 1; 656 } else { 657 LOGI("JNI: -> %s(%s)", mFunctionName, msg.c_str()); 658 mIndent = 0; 659 } 660 } else { 661 LOGI("JNI: %*s<- %s returned %s", mIndent, "", mFunctionName, msg.c_str()); 662 } 663 } 664 665 // We always do the thorough checks on entry, and never on exit... 666 if (entry) { 667 va_start(ap, fmt0); 668 for (const char* fmt = fmt0; *fmt; ++fmt) { 669 char ch = *fmt; 670 if (ch == 'a') { 671 checkArray(va_arg(ap, jarray)); 672 } else if (ch == 'c') { 673 checkClass(va_arg(ap, jclass)); 674 } else if (ch == 'L') { 675 checkObject(va_arg(ap, jobject)); 676 } else if (ch == 'r') { 677 checkReleaseMode(va_arg(ap, jint)); 678 } else if (ch == 's') { 679 checkString(va_arg(ap, jstring)); 680 } else if (ch == 'u') { 681 if ((mFlags & kFlag_Release) != 0) { 682 checkNonNull(va_arg(ap, const char*)); 683 } else { 684 bool nullable = ((mFlags & kFlag_NullableUtf) != 0); 685 checkUtfString(va_arg(ap, const char*), nullable); 686 } 687 } else if (ch == 'z') { 688 checkLengthPositive(va_arg(ap, jsize)); 689 } else if (strchr("BCISZbfmpEv", ch) != NULL) { 690 va_arg(ap, int); // Skip this argument. 691 } else if (ch == 'D' || ch == 'F') { 692 va_arg(ap, double); // Skip this argument. 693 } else if (ch == 'J') { 694 va_arg(ap, long); // Skip this argument. 695 } else if (ch == '.') { 696 } else { 697 LOGE("unknown check format specifier %c", ch); 698 dvmAbort(); 699 } 700 } 701 va_end(ap); 702 } 703 } 704 705private: 706 JNIEnv* mEnv; 707 const char* mFunctionName; 708 int mFlags; 709 bool mHasMethod; 710 size_t mIndent; 711 712 void init(JNIEnv* env, int flags, const char* functionName, bool hasMethod) { 713 mEnv = env; 714 mFlags = flags; 715 716 // Use +6 to drop the leading "Check_"... 717 mFunctionName = functionName + 6; 718 719 // Set "hasMethod" to true if we have a valid thread with a method pointer. 720 // We won't have one before attaching a thread, after detaching a thread, or 721 // after destroying the VM. 722 mHasMethod = hasMethod; 723 } 724 725 /* 726 * Verify that "array" is non-NULL and points to an Array object. 727 * 728 * Since we're dealing with objects, switch to "running" mode. 729 */ 730 void checkArray(jarray jarr) { 731 if (jarr == NULL) { 732 LOGW("JNI WARNING: received null array"); 733 showLocation(); 734 abortMaybe(); 735 return; 736 } 737 738 ScopedJniThreadState ts(mEnv); 739 bool printWarn = false; 740 741 Object* obj = dvmDecodeIndirectRef(mEnv, jarr); 742 if (!dvmIsHeapAddress(obj)) { 743 LOGW("JNI WARNING: jarray is an invalid %s reference (%p)", 744 indirectRefKindName(jarr), jarr); 745 printWarn = true; 746 } else if (obj->clazz->descriptor[0] != '[') { 747 LOGW("JNI WARNING: jarray arg has wrong type (expected array, got %s)", 748 obj->clazz->descriptor); 749 printWarn = true; 750 } 751 752 if (printWarn) { 753 showLocation(); 754 abortMaybe(); 755 } 756 } 757 758 void checkClass(jclass c) { 759 checkInstance(c, gDvm.classJavaLangClass, "jclass"); 760 } 761 762 void checkLengthPositive(jsize length) { 763 if (length < 0) { 764 LOGW("JNI WARNING: negative jsize (%s)", mFunctionName); 765 abortMaybe(); 766 } 767 } 768 769 /* 770 * Verify that "jobj" is a valid object, and that it's an object that JNI 771 * is allowed to know about. We allow NULL references. 772 * 773 * Switches to "running" mode before performing checks. 774 */ 775 void checkObject(jobject jobj) { 776 if (jobj == NULL) { 777 return; 778 } 779 780 ScopedJniThreadState ts(mEnv); 781 782 bool printWarn = false; 783 if (dvmGetJNIRefType(mEnv, jobj) == JNIInvalidRefType) { 784 LOGW("JNI WARNING: %p is not a valid JNI reference", jobj); 785 printWarn = true; 786 } else { 787 Object* obj = dvmDecodeIndirectRef(mEnv, jobj); 788 if (obj == kInvalidIndirectRefObject) { 789 LOGW("JNI WARNING: native code passing in invalid reference %p", jobj); 790 printWarn = true; 791 } else if (obj != NULL && !dvmIsHeapAddress(obj)) { 792 // TODO: when we remove workAroundAppJniBugs, this should be impossible. 793 LOGW("JNI WARNING: native code passing in reference to invalid object %p %p", 794 jobj, obj); 795 printWarn = true; 796 } 797 } 798 799 if (printWarn) { 800 showLocation(); 801 abortMaybe(); 802 } 803 } 804 805 /* 806 * Verify that the "mode" argument passed to a primitive array Release 807 * function is one of the valid values. 808 */ 809 void checkReleaseMode(jint mode) { 810 if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) { 811 LOGW("JNI WARNING: bad value for mode (%d) (%s)", mode, mFunctionName); 812 abortMaybe(); 813 } 814 } 815 816 void checkString(jstring s) { 817 checkInstance(s, gDvm.classJavaLangString, "jstring"); 818 } 819 820 void checkThread(int flags) { 821 // Get the *correct* JNIEnv by going through our TLS pointer. 822 JNIEnvExt* threadEnv = dvmGetJNIEnvForThread(); 823 824 /* 825 * Verify that the current thread is (a) attached and (b) associated with 826 * this particular instance of JNIEnv. 827 */ 828 bool printWarn = false; 829 if (threadEnv == NULL) { 830 LOGE("JNI ERROR: non-VM thread making JNI calls"); 831 // don't set printWarn -- it'll try to call showLocation() 832 dvmAbort(); 833 } else if ((JNIEnvExt*) mEnv != threadEnv) { 834 if (dvmThreadSelf()->threadId != threadEnv->envThreadId) { 835 LOGE("JNI: threadEnv != thread->env?"); 836 dvmAbort(); 837 } 838 839 LOGW("JNI WARNING: threadid=%d using env from threadid=%d", 840 threadEnv->envThreadId, ((JNIEnvExt*) mEnv)->envThreadId); 841 printWarn = true; 842 843 // If we're keeping broken code limping along, we need to suppress the abort... 844 if (gDvmJni.workAroundAppJniBugs) { 845 printWarn = false; 846 } 847 848 /* this is a bad idea -- need to throw as we exit, or abort func */ 849 //dvmThrowRuntimeException("invalid use of JNI env ptr"); 850 } else if (((JNIEnvExt*) mEnv)->self != dvmThreadSelf()) { 851 /* correct JNIEnv*; make sure the "self" pointer is correct */ 852 LOGE("JNI ERROR: env->self != thread-self (%p vs. %p)", 853 ((JNIEnvExt*) mEnv)->self, dvmThreadSelf()); 854 dvmAbort(); 855 } 856 857 /* 858 * Verify that, if this thread previously made a critical "get" call, we 859 * do the corresponding "release" call before we try anything else. 860 */ 861 switch (flags & kFlag_CritMask) { 862 case kFlag_CritOkay: // okay to call this method 863 break; 864 case kFlag_CritBad: // not okay to call 865 if (threadEnv->critical) { 866 LOGW("JNI WARNING: threadid=%d using JNI after critical get", 867 threadEnv->envThreadId); 868 printWarn = true; 869 } 870 break; 871 case kFlag_CritGet: // this is a "get" call 872 /* don't check here; we allow nested gets */ 873 threadEnv->critical++; 874 break; 875 case kFlag_CritRelease: // this is a "release" call 876 threadEnv->critical--; 877 if (threadEnv->critical < 0) { 878 LOGW("JNI WARNING: threadid=%d called too many crit releases", 879 threadEnv->envThreadId); 880 printWarn = true; 881 } 882 break; 883 default: 884 assert(false); 885 } 886 887 /* 888 * Verify that, if an exception has been raised, the native code doesn't 889 * make any JNI calls other than the Exception* methods. 890 */ 891 bool printException = false; 892 if ((flags & kFlag_ExcepOkay) == 0 && dvmCheckException(dvmThreadSelf())) { 893 LOGW("JNI WARNING: JNI method called with exception pending"); 894 printWarn = true; 895 printException = true; 896 } 897 898 if (printWarn) { 899 showLocation(); 900 } 901 if (printException) { 902 LOGW("Pending exception is:"); 903 dvmLogExceptionStackTrace(); 904 } 905 if (printWarn) { 906 abortMaybe(); 907 } 908 } 909 910 /* 911 * Verify that "bytes" points to valid "modified UTF-8" data. 912 */ 913 void checkUtfString(const char* bytes, bool nullable) { 914 if (bytes == NULL) { 915 if (!nullable) { 916 LOGW("JNI WARNING: non-nullable const char* was NULL"); 917 showLocation(); 918 abortMaybe(); 919 } 920 return; 921 } 922 923 const char* errorKind = NULL; 924 u1 utf8 = checkUtfBytes(bytes, &errorKind); 925 if (errorKind != NULL) { 926 LOGW("JNI WARNING: input is not valid UTF-8: illegal %s byte %#x", errorKind, utf8); 927 LOGW(" string: '%s'", bytes); 928 showLocation(); 929 abortMaybe(); 930 } 931 } 932 933 /* 934 * Verify that "jobj" is a valid non-NULL object reference, and points to 935 * an instance of expectedClass. 936 * 937 * Because we're looking at an object on the GC heap, we have to switch 938 * to "running" mode before doing the checks. 939 */ 940 void checkInstance(jobject jobj, ClassObject* expectedClass, const char* argName) { 941 if (jobj == NULL) { 942 LOGW("JNI WARNING: received null %s", argName); 943 showLocation(); 944 abortMaybe(); 945 return; 946 } 947 948 ScopedJniThreadState ts(mEnv); 949 bool printWarn = false; 950 951 Object* obj = dvmDecodeIndirectRef(mEnv, jobj); 952 if (!dvmIsHeapAddress(obj)) { 953 LOGW("JNI WARNING: %s is an invalid %s reference (%p)", 954 argName, indirectRefKindName(jobj), jobj); 955 printWarn = true; 956 } else if (obj->clazz != expectedClass) { 957 LOGW("JNI WARNING: %s arg has wrong type (expected %s, got %s)", 958 argName, expectedClass->descriptor, obj->clazz->descriptor); 959 printWarn = true; 960 } 961 962 if (printWarn) { 963 showLocation(); 964 abortMaybe(); 965 } 966 } 967 968 static u1 checkUtfBytes(const char* bytes, const char** errorKind) { 969 while (*bytes != '\0') { 970 u1 utf8 = *(bytes++); 971 // Switch on the high four bits. 972 switch (utf8 >> 4) { 973 case 0x00: 974 case 0x01: 975 case 0x02: 976 case 0x03: 977 case 0x04: 978 case 0x05: 979 case 0x06: 980 case 0x07: 981 // Bit pattern 0xxx. No need for any extra bytes. 982 break; 983 case 0x08: 984 case 0x09: 985 case 0x0a: 986 case 0x0b: 987 case 0x0f: 988 /* 989 * Bit pattern 10xx or 1111, which are illegal start bytes. 990 * Note: 1111 is valid for normal UTF-8, but not the 991 * modified UTF-8 used here. 992 */ 993 *errorKind = "start"; 994 return utf8; 995 case 0x0e: 996 // Bit pattern 1110, so there are two additional bytes. 997 utf8 = *(bytes++); 998 if ((utf8 & 0xc0) != 0x80) { 999 *errorKind = "continuation"; 1000 return utf8; 1001 } 1002 // Fall through to take care of the final byte. 1003 case 0x0c: 1004 case 0x0d: 1005 // Bit pattern 110x, so there is one additional byte. 1006 utf8 = *(bytes++); 1007 if ((utf8 & 0xc0) != 0x80) { 1008 *errorKind = "continuation"; 1009 return utf8; 1010 } 1011 break; 1012 } 1013 } 1014 return 0; 1015 } 1016 1017 /** 1018 * Returns a human-readable name for the given primitive type. 1019 */ 1020 static const char* primitiveTypeToName(PrimitiveType primType) { 1021 switch (primType) { 1022 case PRIM_VOID: return "void"; 1023 case PRIM_BOOLEAN: return "boolean"; 1024 case PRIM_BYTE: return "byte"; 1025 case PRIM_SHORT: return "short"; 1026 case PRIM_CHAR: return "char"; 1027 case PRIM_INT: return "int"; 1028 case PRIM_LONG: return "long"; 1029 case PRIM_FLOAT: return "float"; 1030 case PRIM_DOUBLE: return "double"; 1031 case PRIM_NOT: return "Object/array"; 1032 default: return "???"; 1033 } 1034 } 1035 1036 void showLocation() { 1037 const Method* method = dvmGetCurrentJNIMethod(); 1038 char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 1039 LOGW(" in %s.%s:%s (%s)", method->clazz->descriptor, method->name, desc, mFunctionName); 1040 free(desc); 1041 } 1042 1043 // Disallow copy and assignment. 1044 ScopedCheck(const ScopedCheck&); 1045 void operator=(const ScopedCheck&); 1046}; 1047 1048/* 1049 * =========================================================================== 1050 * Guarded arrays 1051 * =========================================================================== 1052 */ 1053 1054#define kGuardLen 512 /* must be multiple of 2 */ 1055#define kGuardPattern 0xd5e3 /* uncommon values; d5e3d5e3 invalid addr */ 1056#define kGuardMagic 0xffd5aa96 1057 1058/* this gets tucked in at the start of the buffer; struct size must be even */ 1059struct GuardedCopy { 1060 u4 magic; 1061 uLong adler; 1062 size_t originalLen; 1063 const void* originalPtr; 1064 1065 /* find the GuardedCopy given the pointer into the "live" data */ 1066 static inline const GuardedCopy* fromData(const void* dataBuf) { 1067 return reinterpret_cast<const GuardedCopy*>(actualBuffer(dataBuf)); 1068 } 1069 1070 /* 1071 * Create an over-sized buffer to hold the contents of "buf". Copy it in, 1072 * filling in the area around it with guard data. 1073 * 1074 * We use a 16-bit pattern to make a rogue memset less likely to elude us. 1075 */ 1076 static void* create(const void* buf, size_t len, bool modOkay) { 1077 size_t newLen = actualLength(len); 1078 u1* newBuf = debugAlloc(newLen); 1079 1080 /* fill it in with a pattern */ 1081 u2* pat = (u2*) newBuf; 1082 for (size_t i = 0; i < newLen / 2; i++) { 1083 *pat++ = kGuardPattern; 1084 } 1085 1086 /* copy the data in; note "len" could be zero */ 1087 memcpy(newBuf + kGuardLen / 2, buf, len); 1088 1089 /* if modification is not expected, grab a checksum */ 1090 uLong adler = 0; 1091 if (!modOkay) { 1092 adler = adler32(0L, Z_NULL, 0); 1093 adler = adler32(adler, (const Bytef*)buf, len); 1094 *(uLong*)newBuf = adler; 1095 } 1096 1097 GuardedCopy* pExtra = reinterpret_cast<GuardedCopy*>(newBuf); 1098 pExtra->magic = kGuardMagic; 1099 pExtra->adler = adler; 1100 pExtra->originalPtr = buf; 1101 pExtra->originalLen = len; 1102 1103 return newBuf + kGuardLen / 2; 1104 } 1105 1106 /* 1107 * Free up the guard buffer, scrub it, and return the original pointer. 1108 */ 1109 static void* destroy(void* dataBuf) { 1110 const GuardedCopy* pExtra = GuardedCopy::fromData(dataBuf); 1111 void* originalPtr = (void*) pExtra->originalPtr; 1112 size_t len = pExtra->originalLen; 1113 debugFree(dataBuf, len); 1114 return originalPtr; 1115 } 1116 1117 /* 1118 * Verify the guard area and, if "modOkay" is false, that the data itself 1119 * has not been altered. 1120 * 1121 * The caller has already checked that "dataBuf" is non-NULL. 1122 */ 1123 static bool check(const void* dataBuf, bool modOkay) { 1124 static const u4 kMagicCmp = kGuardMagic; 1125 const u1* fullBuf = actualBuffer(dataBuf); 1126 const GuardedCopy* pExtra = GuardedCopy::fromData(dataBuf); 1127 1128 /* 1129 * Before we do anything with "pExtra", check the magic number. We 1130 * do the check with memcmp rather than "==" in case the pointer is 1131 * unaligned. If it points to completely bogus memory we're going 1132 * to crash, but there's no easy way around that. 1133 */ 1134 if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) { 1135 u1 buf[4]; 1136 memcpy(buf, &pExtra->magic, 4); 1137 LOGE("JNI: guard magic does not match (found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?", 1138 buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */ 1139 return false; 1140 } 1141 1142 size_t len = pExtra->originalLen; 1143 1144 /* check bottom half of guard; skip over optional checksum storage */ 1145 const u2* pat = (u2*) fullBuf; 1146 for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) { 1147 if (pat[i] != kGuardPattern) { 1148 LOGE("JNI: guard pattern(1) disturbed at %p + %d", fullBuf, i*2); 1149 return false; 1150 } 1151 } 1152 1153 int offset = kGuardLen / 2 + len; 1154 if (offset & 0x01) { 1155 /* odd byte; expected value depends on endian-ness of host */ 1156 const u2 patSample = kGuardPattern; 1157 if (fullBuf[offset] != ((const u1*) &patSample)[1]) { 1158 LOGE("JNI: guard pattern disturbed in odd byte after %p (+%d) 0x%02x 0x%02x", 1159 fullBuf, offset, fullBuf[offset], ((const u1*) &patSample)[1]); 1160 return false; 1161 } 1162 offset++; 1163 } 1164 1165 /* check top half of guard */ 1166 pat = (u2*) (fullBuf + offset); 1167 for (size_t i = 0; i < kGuardLen / 4; i++) { 1168 if (pat[i] != kGuardPattern) { 1169 LOGE("JNI: guard pattern(2) disturbed at %p + %d", fullBuf, offset + i*2); 1170 return false; 1171 } 1172 } 1173 1174 /* 1175 * If modification is not expected, verify checksum. Strictly speaking 1176 * this is wrong: if we told the client that we made a copy, there's no 1177 * reason they can't alter the buffer. 1178 */ 1179 if (!modOkay) { 1180 uLong adler = adler32(0L, Z_NULL, 0); 1181 adler = adler32(adler, (const Bytef*)dataBuf, len); 1182 if (pExtra->adler != adler) { 1183 LOGE("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p", 1184 pExtra->adler, adler, dataBuf); 1185 return false; 1186 } 1187 } 1188 1189 return true; 1190 } 1191 1192private: 1193 static u1* debugAlloc(size_t len) { 1194 void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); 1195 if (result == MAP_FAILED) { 1196 LOGE("GuardedCopy::create mmap(%d) failed: %s", len, strerror(errno)); 1197 dvmAbort(); 1198 } 1199 return reinterpret_cast<u1*>(result); 1200 } 1201 1202 static void debugFree(void* dataBuf, size_t len) { 1203 u1* fullBuf = actualBuffer(dataBuf); 1204 size_t totalByteCount = actualLength(len); 1205 // TODO: we could mprotect instead, and keep the allocation around for a while. 1206 // This would be even more expensive, but it might catch more errors. 1207 // if (mprotect(fullBuf, totalByteCount, PROT_NONE) != 0) { 1208 // LOGW("mprotect(PROT_NONE) failed: %s", strerror(errno)); 1209 // } 1210 if (munmap(fullBuf, totalByteCount) != 0) { 1211 LOGW("munmap failed: %s", strerror(errno)); 1212 dvmAbort(); 1213 } 1214 } 1215 1216 static const u1* actualBuffer(const void* dataBuf) { 1217 return reinterpret_cast<const u1*>(dataBuf) - kGuardLen / 2; 1218 } 1219 1220 static u1* actualBuffer(void* dataBuf) { 1221 return reinterpret_cast<u1*>(dataBuf) - kGuardLen / 2; 1222 } 1223 1224 // Underlying length of a user allocation of 'length' bytes. 1225 static size_t actualLength(size_t length) { 1226 return (length + kGuardLen + 1) & ~0x01; 1227 } 1228}; 1229 1230/* 1231 * Return the width, in bytes, of a primitive type. 1232 */ 1233static int dvmPrimitiveTypeWidth(PrimitiveType primType) { 1234 switch (primType) { 1235 case PRIM_BOOLEAN: return 1; 1236 case PRIM_BYTE: return 1; 1237 case PRIM_SHORT: return 2; 1238 case PRIM_CHAR: return 2; 1239 case PRIM_INT: return 4; 1240 case PRIM_LONG: return 8; 1241 case PRIM_FLOAT: return 4; 1242 case PRIM_DOUBLE: return 8; 1243 case PRIM_VOID: 1244 default: { 1245 assert(false); 1246 return -1; 1247 } 1248 } 1249} 1250 1251/* 1252 * Create a guarded copy of a primitive array. Modifications to the copied 1253 * data are allowed. Returns a pointer to the copied data. 1254 */ 1255static void* createGuardedPACopy(JNIEnv* env, const jarray jarr, jboolean* isCopy) { 1256 ScopedJniThreadState ts(env); 1257 1258 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); 1259 PrimitiveType primType = arrObj->clazz->elementClass->primitiveType; 1260 int len = arrObj->length * dvmPrimitiveTypeWidth(primType); 1261 void* result = GuardedCopy::create(arrObj->contents, len, true); 1262 if (isCopy != NULL) { 1263 *isCopy = JNI_TRUE; 1264 } 1265 return result; 1266} 1267 1268/* 1269 * Perform the array "release" operation, which may or may not copy data 1270 * back into the VM, and may or may not release the underlying storage. 1271 */ 1272static void* releaseGuardedPACopy(JNIEnv* env, jarray jarr, void* dataBuf, int mode) { 1273 ScopedJniThreadState ts(env); 1274 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); 1275 1276 if (!GuardedCopy::check(dataBuf, true)) { 1277 LOGE("JNI: failed guarded copy check in releaseGuardedPACopy"); 1278 abortMaybe(); 1279 return NULL; 1280 } 1281 1282 if (mode != JNI_ABORT) { 1283 size_t len = GuardedCopy::fromData(dataBuf)->originalLen; 1284 memcpy(arrObj->contents, dataBuf, len); 1285 } 1286 1287 u1* result = NULL; 1288 if (mode != JNI_COMMIT) { 1289 result = (u1*) GuardedCopy::destroy(dataBuf); 1290 } else { 1291 result = (u1*) (void*) GuardedCopy::fromData(dataBuf)->originalPtr; 1292 } 1293 1294 /* pointer is to the array contents; back up to the array object */ 1295 result -= OFFSETOF_MEMBER(ArrayObject, contents); 1296 return result; 1297} 1298 1299 1300/* 1301 * =========================================================================== 1302 * JNI functions 1303 * =========================================================================== 1304 */ 1305 1306#define CHECK_JNI_ENTRY(flags, types, args...) \ 1307 ScopedCheck sc(env, flags, __FUNCTION__); \ 1308 sc.check(true, types, ##args) 1309 1310#define CHECK_JNI_EXIT(type, exp) ({ \ 1311 typeof (exp) _rc = (exp); \ 1312 sc.check(false, type, _rc); \ 1313 _rc; }) 1314#define CHECK_JNI_EXIT_VOID() \ 1315 sc.check(false, "V") 1316 1317static jint Check_GetVersion(JNIEnv* env) { 1318 CHECK_JNI_ENTRY(kFlag_Default, "E", env); 1319 return CHECK_JNI_EXIT("I", baseEnv(env)->GetVersion(env)); 1320} 1321 1322static jclass Check_DefineClass(JNIEnv* env, const char* name, jobject loader, 1323 const jbyte* buf, jsize bufLen) 1324{ 1325 CHECK_JNI_ENTRY(kFlag_Default, "EuLpz", env, name, loader, buf, bufLen); 1326 sc.checkClassName(name); 1327 return CHECK_JNI_EXIT("c", baseEnv(env)->DefineClass(env, name, loader, buf, bufLen)); 1328} 1329 1330static jclass Check_FindClass(JNIEnv* env, const char* name) { 1331 CHECK_JNI_ENTRY(kFlag_Default, "Eu", env, name); 1332 sc.checkClassName(name); 1333 return CHECK_JNI_EXIT("c", baseEnv(env)->FindClass(env, name)); 1334} 1335 1336static jclass Check_GetSuperclass(JNIEnv* env, jclass clazz) { 1337 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz); 1338 return CHECK_JNI_EXIT("c", baseEnv(env)->GetSuperclass(env, clazz)); 1339} 1340 1341static jboolean Check_IsAssignableFrom(JNIEnv* env, jclass clazz1, jclass clazz2) { 1342 CHECK_JNI_ENTRY(kFlag_Default, "Ecc", env, clazz1, clazz2); 1343 return CHECK_JNI_EXIT("b", baseEnv(env)->IsAssignableFrom(env, clazz1, clazz2)); 1344} 1345 1346static jmethodID Check_FromReflectedMethod(JNIEnv* env, jobject method) { 1347 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, method); 1348 // TODO: check that 'field' is a java.lang.reflect.Method. 1349 return CHECK_JNI_EXIT("m", baseEnv(env)->FromReflectedMethod(env, method)); 1350} 1351 1352static jfieldID Check_FromReflectedField(JNIEnv* env, jobject field) { 1353 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, field); 1354 // TODO: check that 'field' is a java.lang.reflect.Field. 1355 return CHECK_JNI_EXIT("f", baseEnv(env)->FromReflectedField(env, field)); 1356} 1357 1358static jobject Check_ToReflectedMethod(JNIEnv* env, jclass cls, 1359 jmethodID methodID, jboolean isStatic) 1360{ 1361 CHECK_JNI_ENTRY(kFlag_Default, "Ecmb", env, cls, methodID, isStatic); 1362 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedMethod(env, cls, methodID, isStatic)); 1363} 1364 1365static jobject Check_ToReflectedField(JNIEnv* env, jclass cls, 1366 jfieldID fieldID, jboolean isStatic) 1367{ 1368 CHECK_JNI_ENTRY(kFlag_Default, "Ecfb", env, cls, fieldID, isStatic); 1369 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedField(env, cls, fieldID, isStatic)); 1370} 1371 1372static jint Check_Throw(JNIEnv* env, jthrowable obj) { 1373 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1374 // TODO: check that 'obj' is a java.lang.Throwable. 1375 return CHECK_JNI_EXIT("I", baseEnv(env)->Throw(env, obj)); 1376} 1377 1378static jint Check_ThrowNew(JNIEnv* env, jclass clazz, const char* message) { 1379 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Ecu", env, clazz, message); 1380 return CHECK_JNI_EXIT("I", baseEnv(env)->ThrowNew(env, clazz, message)); 1381} 1382 1383static jthrowable Check_ExceptionOccurred(JNIEnv* env) { 1384 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env); 1385 return CHECK_JNI_EXIT("L", baseEnv(env)->ExceptionOccurred(env)); 1386} 1387 1388static void Check_ExceptionDescribe(JNIEnv* env) { 1389 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env); 1390 baseEnv(env)->ExceptionDescribe(env); 1391 CHECK_JNI_EXIT_VOID(); 1392} 1393 1394static void Check_ExceptionClear(JNIEnv* env) { 1395 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env); 1396 baseEnv(env)->ExceptionClear(env); 1397 CHECK_JNI_EXIT_VOID(); 1398} 1399 1400static void Check_FatalError(JNIEnv* env, const char* msg) { 1401 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg); 1402 baseEnv(env)->FatalError(env, msg); 1403 CHECK_JNI_EXIT_VOID(); 1404} 1405 1406static jint Check_PushLocalFrame(JNIEnv* env, jint capacity) { 1407 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EI", env, capacity); 1408 return CHECK_JNI_EXIT("I", baseEnv(env)->PushLocalFrame(env, capacity)); 1409} 1410 1411static jobject Check_PopLocalFrame(JNIEnv* env, jobject res) { 1412 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, res); 1413 return CHECK_JNI_EXIT("L", baseEnv(env)->PopLocalFrame(env, res)); 1414} 1415 1416static jobject Check_NewGlobalRef(JNIEnv* env, jobject obj) { 1417 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1418 return CHECK_JNI_EXIT("L", baseEnv(env)->NewGlobalRef(env, obj)); 1419} 1420 1421static void Check_DeleteGlobalRef(JNIEnv* env, jobject globalRef) { 1422 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef); 1423 if (globalRef != NULL && dvmGetJNIRefType(env, globalRef) != JNIGlobalRefType) { 1424 LOGW("JNI WARNING: DeleteGlobalRef on non-global %p (type=%d)", 1425 globalRef, dvmGetJNIRefType(env, globalRef)); 1426 abortMaybe(); 1427 } else { 1428 baseEnv(env)->DeleteGlobalRef(env, globalRef); 1429 CHECK_JNI_EXIT_VOID(); 1430 } 1431} 1432 1433static jobject Check_NewLocalRef(JNIEnv* env, jobject ref) { 1434 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, ref); 1435 return CHECK_JNI_EXIT("L", baseEnv(env)->NewLocalRef(env, ref)); 1436} 1437 1438static void Check_DeleteLocalRef(JNIEnv* env, jobject localRef) { 1439 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef); 1440 if (localRef != NULL && dvmGetJNIRefType(env, localRef) != JNILocalRefType) { 1441 LOGW("JNI WARNING: DeleteLocalRef on non-local %p (type=%d)", 1442 localRef, dvmGetJNIRefType(env, localRef)); 1443 abortMaybe(); 1444 } else { 1445 baseEnv(env)->DeleteLocalRef(env, localRef); 1446 CHECK_JNI_EXIT_VOID(); 1447 } 1448} 1449 1450static jint Check_EnsureLocalCapacity(JNIEnv *env, jint capacity) { 1451 CHECK_JNI_ENTRY(kFlag_Default, "EI", env, capacity); 1452 return CHECK_JNI_EXIT("I", baseEnv(env)->EnsureLocalCapacity(env, capacity)); 1453} 1454 1455static jboolean Check_IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) { 1456 CHECK_JNI_ENTRY(kFlag_Default, "ELL", env, ref1, ref2); 1457 return CHECK_JNI_EXIT("b", baseEnv(env)->IsSameObject(env, ref1, ref2)); 1458} 1459 1460static jobject Check_AllocObject(JNIEnv* env, jclass clazz) { 1461 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz); 1462 return CHECK_JNI_EXIT("L", baseEnv(env)->AllocObject(env, clazz)); 1463} 1464 1465static jobject Check_NewObject(JNIEnv* env, jclass clazz, jmethodID methodID, ...) { 1466 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); 1467 va_list args; 1468 va_start(args, methodID); 1469 jobject result = baseEnv(env)->NewObjectV(env, clazz, methodID, args); 1470 va_end(args); 1471 return CHECK_JNI_EXIT("L", result); 1472} 1473 1474static jobject Check_NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID, va_list args) { 1475 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); 1476 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectV(env, clazz, methodID, args)); 1477} 1478 1479static jobject Check_NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID, jvalue* args) { 1480 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); 1481 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectA(env, clazz, methodID, args)); 1482} 1483 1484static jclass Check_GetObjectClass(JNIEnv* env, jobject obj) { 1485 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1486 return CHECK_JNI_EXIT("c", baseEnv(env)->GetObjectClass(env, obj)); 1487} 1488 1489static jboolean Check_IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz) { 1490 CHECK_JNI_ENTRY(kFlag_Default, "ELc", env, obj, clazz); 1491 return CHECK_JNI_EXIT("b", baseEnv(env)->IsInstanceOf(env, obj, clazz)); 1492} 1493 1494static jmethodID Check_GetMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) { 1495 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig); 1496 return CHECK_JNI_EXIT("m", baseEnv(env)->GetMethodID(env, clazz, name, sig)); 1497} 1498 1499static jfieldID Check_GetFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) { 1500 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig); 1501 return CHECK_JNI_EXIT("f", baseEnv(env)->GetFieldID(env, clazz, name, sig)); 1502} 1503 1504static jmethodID Check_GetStaticMethodID(JNIEnv* env, jclass clazz, 1505 const char* name, const char* sig) 1506{ 1507 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig); 1508 return CHECK_JNI_EXIT("m", baseEnv(env)->GetStaticMethodID(env, clazz, name, sig)); 1509} 1510 1511static jfieldID Check_GetStaticFieldID(JNIEnv* env, jclass clazz, 1512 const char* name, const char* sig) 1513{ 1514 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig); 1515 return CHECK_JNI_EXIT("f", baseEnv(env)->GetStaticFieldID(env, clazz, name, sig)); 1516} 1517 1518#define FIELD_ACCESSORS(_ctype, _jname, _ftype, _type) \ 1519 static _ctype Check_GetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fieldID) { \ 1520 CHECK_JNI_ENTRY(kFlag_Default, "Ecf", env, clazz, fieldID); \ 1521 sc.checkStaticFieldID(clazz, fieldID); \ 1522 sc.checkFieldTypeForGet(fieldID, _type, true); \ 1523 return CHECK_JNI_EXIT(_type, baseEnv(env)->GetStatic##_jname##Field(env, clazz, fieldID)); \ 1524 } \ 1525 static _ctype Check_Get##_jname##Field(JNIEnv* env, jobject obj, jfieldID fieldID) { \ 1526 CHECK_JNI_ENTRY(kFlag_Default, "ELf", env, obj, fieldID); \ 1527 sc.checkInstanceFieldID(obj, fieldID); \ 1528 sc.checkFieldTypeForGet(fieldID, _type, false); \ 1529 return CHECK_JNI_EXIT(_type, baseEnv(env)->Get##_jname##Field(env, obj, fieldID)); \ 1530 } \ 1531 static void Check_SetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fieldID, _ctype value) { \ 1532 CHECK_JNI_ENTRY(kFlag_Default, "Ecf" _type, env, clazz, fieldID, value); \ 1533 sc.checkStaticFieldID(clazz, fieldID); \ 1534 /* "value" arg only used when type == ref */ \ 1535 sc.checkFieldTypeForSet((jobject)(u4)value, fieldID, _ftype, true); \ 1536 baseEnv(env)->SetStatic##_jname##Field(env, clazz, fieldID, value); \ 1537 CHECK_JNI_EXIT_VOID(); \ 1538 } \ 1539 static void Check_Set##_jname##Field(JNIEnv* env, jobject obj, jfieldID fieldID, _ctype value) { \ 1540 CHECK_JNI_ENTRY(kFlag_Default, "ELf" _type, env, obj, fieldID, value); \ 1541 sc.checkInstanceFieldID(obj, fieldID); \ 1542 /* "value" arg only used when type == ref */ \ 1543 sc.checkFieldTypeForSet((jobject)(u4) value, fieldID, _ftype, false); \ 1544 baseEnv(env)->Set##_jname##Field(env, obj, fieldID, value); \ 1545 CHECK_JNI_EXIT_VOID(); \ 1546 } 1547 1548FIELD_ACCESSORS(jobject, Object, PRIM_NOT, "L"); 1549FIELD_ACCESSORS(jboolean, Boolean, PRIM_BOOLEAN, "Z"); 1550FIELD_ACCESSORS(jbyte, Byte, PRIM_BYTE, "B"); 1551FIELD_ACCESSORS(jchar, Char, PRIM_CHAR, "C"); 1552FIELD_ACCESSORS(jshort, Short, PRIM_SHORT, "S"); 1553FIELD_ACCESSORS(jint, Int, PRIM_INT, "I"); 1554FIELD_ACCESSORS(jlong, Long, PRIM_LONG, "J"); 1555FIELD_ACCESSORS(jfloat, Float, PRIM_FLOAT, "F"); 1556FIELD_ACCESSORS(jdouble, Double, PRIM_DOUBLE, "D"); 1557 1558#define CALL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \ 1559 /* Virtual... */ \ 1560 static _ctype Check_Call##_jname##Method(JNIEnv* env, jobject obj, \ 1561 jmethodID methodID, ...) \ 1562 { \ 1563 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \ 1564 sc.checkSig(methodID, _retsig, false); \ 1565 sc.checkVirtualMethod(obj, methodID); \ 1566 _retdecl; \ 1567 va_list args; \ 1568 va_start(args, methodID); \ 1569 _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, methodID, args); \ 1570 va_end(args); \ 1571 _retok; \ 1572 } \ 1573 static _ctype Check_Call##_jname##MethodV(JNIEnv* env, jobject obj, \ 1574 jmethodID methodID, va_list args) \ 1575 { \ 1576 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \ 1577 sc.checkSig(methodID, _retsig, false); \ 1578 sc.checkVirtualMethod(obj, methodID); \ 1579 _retdecl; \ 1580 _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, methodID, args); \ 1581 _retok; \ 1582 } \ 1583 static _ctype Check_Call##_jname##MethodA(JNIEnv* env, jobject obj, \ 1584 jmethodID methodID, jvalue* args) \ 1585 { \ 1586 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \ 1587 sc.checkSig(methodID, _retsig, false); \ 1588 sc.checkVirtualMethod(obj, methodID); \ 1589 _retdecl; \ 1590 _retasgn baseEnv(env)->Call##_jname##MethodA(env, obj, methodID, args); \ 1591 _retok; \ 1592 } \ 1593 /* Non-virtual... */ \ 1594 static _ctype Check_CallNonvirtual##_jname##Method(JNIEnv* env, \ 1595 jobject obj, jclass clazz, jmethodID methodID, ...) \ 1596 { \ 1597 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \ 1598 sc.checkSig(methodID, _retsig, false); \ 1599 sc.checkVirtualMethod(obj, methodID); \ 1600 _retdecl; \ 1601 va_list args; \ 1602 va_start(args, methodID); \ 1603 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, methodID, args); \ 1604 va_end(args); \ 1605 _retok; \ 1606 } \ 1607 static _ctype Check_CallNonvirtual##_jname##MethodV(JNIEnv* env, \ 1608 jobject obj, jclass clazz, jmethodID methodID, va_list args) \ 1609 { \ 1610 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \ 1611 sc.checkSig(methodID, _retsig, false); \ 1612 sc.checkVirtualMethod(obj, methodID); \ 1613 _retdecl; \ 1614 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, methodID, args); \ 1615 _retok; \ 1616 } \ 1617 static _ctype Check_CallNonvirtual##_jname##MethodA(JNIEnv* env, \ 1618 jobject obj, jclass clazz, jmethodID methodID, jvalue* args) \ 1619 { \ 1620 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \ 1621 sc.checkSig(methodID, _retsig, false); \ 1622 sc.checkVirtualMethod(obj, methodID); \ 1623 _retdecl; \ 1624 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodA(env, obj, clazz, methodID, args); \ 1625 _retok; \ 1626 } \ 1627 /* Static... */ \ 1628 static _ctype Check_CallStatic##_jname##Method(JNIEnv* env, \ 1629 jclass clazz, jmethodID methodID, ...) \ 1630 { \ 1631 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \ 1632 sc.checkSig(methodID, _retsig, true); \ 1633 sc.checkStaticMethod(clazz, methodID); \ 1634 _retdecl; \ 1635 va_list args; \ 1636 va_start(args, methodID); \ 1637 _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, methodID, args); \ 1638 va_end(args); \ 1639 _retok; \ 1640 } \ 1641 static _ctype Check_CallStatic##_jname##MethodV(JNIEnv* env, \ 1642 jclass clazz, jmethodID methodID, va_list args) \ 1643 { \ 1644 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \ 1645 sc.checkSig(methodID, _retsig, true); \ 1646 sc.checkStaticMethod(clazz, methodID); \ 1647 _retdecl; \ 1648 _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, methodID, args); \ 1649 _retok; \ 1650 } \ 1651 static _ctype Check_CallStatic##_jname##MethodA(JNIEnv* env, \ 1652 jclass clazz, jmethodID methodID, jvalue* args) \ 1653 { \ 1654 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \ 1655 sc.checkSig(methodID, _retsig, true); \ 1656 sc.checkStaticMethod(clazz, methodID); \ 1657 _retdecl; \ 1658 _retasgn baseEnv(env)->CallStatic##_jname##MethodA(env, clazz, methodID, args); \ 1659 _retok; \ 1660 } 1661 1662#define NON_VOID_RETURN(_retsig, _ctype) return CHECK_JNI_EXIT(_retsig, (_ctype) result) 1663#define VOID_RETURN CHECK_JNI_EXIT_VOID() 1664 1665CALL(jobject, Object, Object* result, result=(Object*), NON_VOID_RETURN("L", jobject), "L"); 1666CALL(jboolean, Boolean, jboolean result, result=, NON_VOID_RETURN("Z", jboolean), "Z"); 1667CALL(jbyte, Byte, jbyte result, result=, NON_VOID_RETURN("B", jbyte), "B"); 1668CALL(jchar, Char, jchar result, result=, NON_VOID_RETURN("C", jchar), "C"); 1669CALL(jshort, Short, jshort result, result=, NON_VOID_RETURN("S", jshort), "S"); 1670CALL(jint, Int, jint result, result=, NON_VOID_RETURN("I", jint), "I"); 1671CALL(jlong, Long, jlong result, result=, NON_VOID_RETURN("J", jlong), "J"); 1672CALL(jfloat, Float, jfloat result, result=, NON_VOID_RETURN("F", jfloat), "F"); 1673CALL(jdouble, Double, jdouble result, result=, NON_VOID_RETURN("D", jdouble), "D"); 1674CALL(void, Void, , , VOID_RETURN, "V"); 1675 1676static jstring Check_NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) { 1677 CHECK_JNI_ENTRY(kFlag_Default, "Epz", env, unicodeChars, len); 1678 return CHECK_JNI_EXIT("s", baseEnv(env)->NewString(env, unicodeChars, len)); 1679} 1680 1681static jsize Check_GetStringLength(JNIEnv* env, jstring string) { 1682 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string); 1683 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringLength(env, string)); 1684} 1685 1686static const jchar* Check_GetStringChars(JNIEnv* env, jstring string, jboolean* isCopy) { 1687 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy); 1688 const jchar* result = baseEnv(env)->GetStringChars(env, string, isCopy); 1689 if (gDvmJni.forceCopy && result != NULL) { 1690 ScopedJniThreadState ts(env); 1691 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, string); 1692 int byteCount = strObj->length() * 2; 1693 result = (const jchar*) GuardedCopy::create(result, byteCount, false); 1694 if (isCopy != NULL) { 1695 *isCopy = JNI_TRUE; 1696 } 1697 } 1698 return CHECK_JNI_EXIT("p", result); 1699} 1700 1701static void Check_ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars) { 1702 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Esp", env, string, chars); 1703 sc.checkNonNull(chars); 1704 if (gDvmJni.forceCopy) { 1705 if (!GuardedCopy::check(chars, false)) { 1706 LOGE("JNI: failed guarded copy check in ReleaseStringChars"); 1707 abortMaybe(); 1708 return; 1709 } 1710 chars = (const jchar*) GuardedCopy::destroy((jchar*)chars); 1711 } 1712 baseEnv(env)->ReleaseStringChars(env, string, chars); 1713 CHECK_JNI_EXIT_VOID(); 1714} 1715 1716static jstring Check_NewStringUTF(JNIEnv* env, const char* bytes) { 1717 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, bytes); // TODO: show pointer and truncate string. 1718 return CHECK_JNI_EXIT("s", baseEnv(env)->NewStringUTF(env, bytes)); 1719} 1720 1721static jsize Check_GetStringUTFLength(JNIEnv* env, jstring string) { 1722 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string); 1723 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringUTFLength(env, string)); 1724} 1725 1726static const char* Check_GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) { 1727 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy); 1728 const char* result = baseEnv(env)->GetStringUTFChars(env, string, isCopy); 1729 if (gDvmJni.forceCopy && result != NULL) { 1730 result = (const char*) GuardedCopy::create(result, strlen(result) + 1, false); 1731 if (isCopy != NULL) { 1732 *isCopy = JNI_TRUE; 1733 } 1734 } 1735 return CHECK_JNI_EXIT("u", result); // TODO: show pointer and truncate string. 1736} 1737 1738static void Check_ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf) { 1739 CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_Release, "Esu", env, string, utf); // TODO: show pointer and truncate string. 1740 if (gDvmJni.forceCopy) { 1741 if (!GuardedCopy::check(utf, false)) { 1742 LOGE("JNI: failed guarded copy check in ReleaseStringUTFChars"); 1743 abortMaybe(); 1744 return; 1745 } 1746 utf = (const char*) GuardedCopy::destroy((char*)utf); 1747 } 1748 baseEnv(env)->ReleaseStringUTFChars(env, string, utf); 1749 CHECK_JNI_EXIT_VOID(); 1750} 1751 1752static jsize Check_GetArrayLength(JNIEnv* env, jarray array) { 1753 CHECK_JNI_ENTRY(kFlag_CritOkay, "Ea", env, array); 1754 return CHECK_JNI_EXIT("I", baseEnv(env)->GetArrayLength(env, array)); 1755} 1756 1757static jobjectArray Check_NewObjectArray(JNIEnv* env, jsize length, 1758 jclass elementClass, jobject initialElement) 1759{ 1760 CHECK_JNI_ENTRY(kFlag_Default, "EzcL", env, length, elementClass, initialElement); 1761 return CHECK_JNI_EXIT("a", baseEnv(env)->NewObjectArray(env, length, elementClass, initialElement)); 1762} 1763 1764static jobject Check_GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) { 1765 CHECK_JNI_ENTRY(kFlag_Default, "EaI", env, array, index); 1766 return CHECK_JNI_EXIT("L", baseEnv(env)->GetObjectArrayElement(env, array, index)); 1767} 1768 1769static void Check_SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value) 1770{ 1771 CHECK_JNI_ENTRY(kFlag_Default, "EaIL", env, array, index, value); 1772 baseEnv(env)->SetObjectArrayElement(env, array, index, value); 1773 CHECK_JNI_EXIT_VOID(); 1774} 1775 1776#define NEW_PRIMITIVE_ARRAY(_artype, _jname) \ 1777 static _artype Check_New##_jname##Array(JNIEnv* env, jsize length) { \ 1778 CHECK_JNI_ENTRY(kFlag_Default, "Ez", env, length); \ 1779 return CHECK_JNI_EXIT("a", baseEnv(env)->New##_jname##Array(env, length)); \ 1780 } 1781NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean); 1782NEW_PRIMITIVE_ARRAY(jbyteArray, Byte); 1783NEW_PRIMITIVE_ARRAY(jcharArray, Char); 1784NEW_PRIMITIVE_ARRAY(jshortArray, Short); 1785NEW_PRIMITIVE_ARRAY(jintArray, Int); 1786NEW_PRIMITIVE_ARRAY(jlongArray, Long); 1787NEW_PRIMITIVE_ARRAY(jfloatArray, Float); 1788NEW_PRIMITIVE_ARRAY(jdoubleArray, Double); 1789 1790 1791/* 1792 * Hack to allow forcecopy to work with jniGetNonMovableArrayElements. 1793 * The code deliberately uses an invalid sequence of operations, so we 1794 * need to pass it through unmodified. Review that code before making 1795 * any changes here. 1796 */ 1797#define kNoCopyMagic 0xd5aab57f 1798 1799#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \ 1800 static _ctype* Check_Get##_jname##ArrayElements(JNIEnv* env, \ 1801 _ctype##Array array, jboolean* isCopy) \ 1802 { \ 1803 CHECK_JNI_ENTRY(kFlag_Default, "Eap", env, array, isCopy); \ 1804 u4 noCopy = 0; \ 1805 if (gDvmJni.forceCopy && isCopy != NULL) { \ 1806 /* capture this before the base call tramples on it */ \ 1807 noCopy = *(u4*) isCopy; \ 1808 } \ 1809 _ctype* result = baseEnv(env)->Get##_jname##ArrayElements(env, array, isCopy); \ 1810 if (gDvmJni.forceCopy && result != NULL) { \ 1811 if (noCopy == kNoCopyMagic) { \ 1812 LOGV("FC: not copying %p %x", array, noCopy); \ 1813 } else { \ 1814 result = (_ctype*) createGuardedPACopy(env, array, isCopy); \ 1815 } \ 1816 } \ 1817 return CHECK_JNI_EXIT("p", result); \ 1818 } 1819 1820#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \ 1821 static void Check_Release##_jname##ArrayElements(JNIEnv* env, \ 1822 _ctype##Array array, _ctype* elems, jint mode) \ 1823 { \ 1824 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Eapr", env, array, elems, mode); \ 1825 sc.checkNonNull(elems); \ 1826 if (gDvmJni.forceCopy) { \ 1827 if ((uintptr_t)elems == kNoCopyMagic) { \ 1828 LOGV("FC: not freeing %p", array); \ 1829 elems = NULL; /* base JNI call doesn't currently need */ \ 1830 } else { \ 1831 elems = (_ctype*) releaseGuardedPACopy(env, array, elems, mode); \ 1832 } \ 1833 } \ 1834 baseEnv(env)->Release##_jname##ArrayElements(env, array, elems, mode); \ 1835 CHECK_JNI_EXIT_VOID(); \ 1836 } 1837 1838#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \ 1839 static void Check_Get##_jname##ArrayRegion(JNIEnv* env, \ 1840 _ctype##Array array, jsize start, jsize len, _ctype* buf) { \ 1841 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \ 1842 baseEnv(env)->Get##_jname##ArrayRegion(env, array, start, len, buf); \ 1843 CHECK_JNI_EXIT_VOID(); \ 1844 } 1845 1846#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \ 1847 static void Check_Set##_jname##ArrayRegion(JNIEnv* env, \ 1848 _ctype##Array array, jsize start, jsize len, const _ctype* buf) { \ 1849 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \ 1850 baseEnv(env)->Set##_jname##ArrayRegion(env, array, start, len, buf); \ 1851 CHECK_JNI_EXIT_VOID(); \ 1852 } 1853 1854#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname, _typechar) \ 1855 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \ 1856 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \ 1857 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \ 1858 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); 1859 1860/* TODO: verify primitive array type matches call type */ 1861PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean, 'Z'); 1862PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte, 'B'); 1863PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char, 'C'); 1864PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short, 'S'); 1865PRIMITIVE_ARRAY_FUNCTIONS(jint, Int, 'I'); 1866PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long, 'J'); 1867PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float, 'F'); 1868PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D'); 1869 1870static jint Check_RegisterNatives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods, 1871 jint nMethods) 1872{ 1873 CHECK_JNI_ENTRY(kFlag_Default, "EcpI", env, clazz, methods, nMethods); 1874 return CHECK_JNI_EXIT("I", baseEnv(env)->RegisterNatives(env, clazz, methods, nMethods)); 1875} 1876 1877static jint Check_UnregisterNatives(JNIEnv* env, jclass clazz) { 1878 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz); 1879 return CHECK_JNI_EXIT("I", baseEnv(env)->UnregisterNatives(env, clazz)); 1880} 1881 1882static jint Check_MonitorEnter(JNIEnv* env, jobject obj) { 1883 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1884 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorEnter(env, obj)); 1885} 1886 1887static jint Check_MonitorExit(JNIEnv* env, jobject obj) { 1888 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj); 1889 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorExit(env, obj)); 1890} 1891 1892static jint Check_GetJavaVM(JNIEnv *env, JavaVM **vm) { 1893 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, vm); 1894 return CHECK_JNI_EXIT("I", baseEnv(env)->GetJavaVM(env, vm)); 1895} 1896 1897static void Check_GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar* buf) { 1898 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf); 1899 baseEnv(env)->GetStringRegion(env, str, start, len, buf); 1900 CHECK_JNI_EXIT_VOID(); 1901} 1902 1903static void Check_GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char* buf) { 1904 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf); 1905 baseEnv(env)->GetStringUTFRegion(env, str, start, len, buf); 1906 CHECK_JNI_EXIT_VOID(); 1907} 1908 1909static void* Check_GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) { 1910 CHECK_JNI_ENTRY(kFlag_CritGet, "Eap", env, array, isCopy); 1911 void* result = baseEnv(env)->GetPrimitiveArrayCritical(env, array, isCopy); 1912 if (gDvmJni.forceCopy && result != NULL) { 1913 result = createGuardedPACopy(env, array, isCopy); 1914 } 1915 return CHECK_JNI_EXIT("p", result); 1916} 1917 1918static void Check_ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode) 1919{ 1920 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Eapr", env, array, carray, mode); 1921 sc.checkNonNull(carray); 1922 if (gDvmJni.forceCopy) { 1923 carray = releaseGuardedPACopy(env, array, carray, mode); 1924 } 1925 baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode); 1926 CHECK_JNI_EXIT_VOID(); 1927} 1928 1929static const jchar* Check_GetStringCritical(JNIEnv* env, jstring string, jboolean* isCopy) { 1930 CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, string, isCopy); 1931 const jchar* result = baseEnv(env)->GetStringCritical(env, string, isCopy); 1932 if (gDvmJni.forceCopy && result != NULL) { 1933 ScopedJniThreadState ts(env); 1934 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, string); 1935 int byteCount = strObj->length() * 2; 1936 result = (const jchar*) GuardedCopy::create(result, byteCount, false); 1937 if (isCopy != NULL) { 1938 *isCopy = JNI_TRUE; 1939 } 1940 } 1941 return CHECK_JNI_EXIT("p", result); 1942} 1943 1944static void Check_ReleaseStringCritical(JNIEnv* env, jstring string, const jchar* carray) { 1945 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Esp", env, string, carray); 1946 sc.checkNonNull(carray); 1947 if (gDvmJni.forceCopy) { 1948 if (!GuardedCopy::check(carray, false)) { 1949 LOGE("JNI: failed guarded copy check in ReleaseStringCritical"); 1950 abortMaybe(); 1951 return; 1952 } 1953 carray = (const jchar*) GuardedCopy::destroy((jchar*)carray); 1954 } 1955 baseEnv(env)->ReleaseStringCritical(env, string, carray); 1956 CHECK_JNI_EXIT_VOID(); 1957} 1958 1959static jweak Check_NewWeakGlobalRef(JNIEnv* env, jobject obj) { 1960 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1961 return CHECK_JNI_EXIT("L", baseEnv(env)->NewWeakGlobalRef(env, obj)); 1962} 1963 1964static void Check_DeleteWeakGlobalRef(JNIEnv* env, jweak obj) { 1965 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj); 1966 baseEnv(env)->DeleteWeakGlobalRef(env, obj); 1967 CHECK_JNI_EXIT_VOID(); 1968} 1969 1970static jboolean Check_ExceptionCheck(JNIEnv* env) { 1971 CHECK_JNI_ENTRY(kFlag_CritOkay | kFlag_ExcepOkay, "E", env); 1972 return CHECK_JNI_EXIT("b", baseEnv(env)->ExceptionCheck(env)); 1973} 1974 1975static jobjectRefType Check_GetObjectRefType(JNIEnv* env, jobject obj) { 1976 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1977 // TODO: proper decoding of jobjectRefType! 1978 return CHECK_JNI_EXIT("I", baseEnv(env)->GetObjectRefType(env, obj)); 1979} 1980 1981static jobject Check_NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) { 1982 CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity); 1983 if (address == NULL || capacity < 0) { 1984 LOGW("JNI WARNING: invalid values for address (%p) or capacity (%ld)", 1985 address, (long) capacity); 1986 abortMaybe(); 1987 return NULL; 1988 } 1989 return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity)); 1990} 1991 1992static void* Check_GetDirectBufferAddress(JNIEnv* env, jobject buf) { 1993 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf); 1994 // TODO: check that 'buf' is a java.nio.Buffer. 1995 return CHECK_JNI_EXIT("p", baseEnv(env)->GetDirectBufferAddress(env, buf)); 1996} 1997 1998static jlong Check_GetDirectBufferCapacity(JNIEnv* env, jobject buf) { 1999 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf); 2000 // TODO: check that 'buf' is a java.nio.Buffer. 2001 return CHECK_JNI_EXIT("J", baseEnv(env)->GetDirectBufferCapacity(env, buf)); 2002} 2003 2004 2005/* 2006 * =========================================================================== 2007 * JNI invocation functions 2008 * =========================================================================== 2009 */ 2010 2011static jint Check_DestroyJavaVM(JavaVM* vm) { 2012 ScopedCheck sc(false, __FUNCTION__); 2013 sc.check(true, "v", vm); 2014 return CHECK_JNI_EXIT("I", baseVm(vm)->DestroyJavaVM(vm)); 2015} 2016 2017static jint Check_AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) { 2018 ScopedCheck sc(false, __FUNCTION__); 2019 sc.check(true, "vpp", vm, p_env, thr_args); 2020 return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThread(vm, p_env, thr_args)); 2021} 2022 2023static jint Check_AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) { 2024 ScopedCheck sc(false, __FUNCTION__); 2025 sc.check(true, "vpp", vm, p_env, thr_args); 2026 return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args)); 2027} 2028 2029static jint Check_DetachCurrentThread(JavaVM* vm) { 2030 ScopedCheck sc(true, __FUNCTION__); 2031 sc.check(true, "v", vm); 2032 return CHECK_JNI_EXIT("I", baseVm(vm)->DetachCurrentThread(vm)); 2033} 2034 2035static jint Check_GetEnv(JavaVM* vm, void** env, jint version) { 2036 ScopedCheck sc(true, __FUNCTION__); 2037 sc.check(true, "v", vm); 2038 return CHECK_JNI_EXIT("I", baseVm(vm)->GetEnv(vm, env, version)); 2039} 2040 2041 2042/* 2043 * =========================================================================== 2044 * Function tables 2045 * =========================================================================== 2046 */ 2047 2048static const struct JNINativeInterface gCheckNativeInterface = { 2049 NULL, 2050 NULL, 2051 NULL, 2052 NULL, 2053 2054 Check_GetVersion, 2055 2056 Check_DefineClass, 2057 Check_FindClass, 2058 2059 Check_FromReflectedMethod, 2060 Check_FromReflectedField, 2061 Check_ToReflectedMethod, 2062 2063 Check_GetSuperclass, 2064 Check_IsAssignableFrom, 2065 2066 Check_ToReflectedField, 2067 2068 Check_Throw, 2069 Check_ThrowNew, 2070 Check_ExceptionOccurred, 2071 Check_ExceptionDescribe, 2072 Check_ExceptionClear, 2073 Check_FatalError, 2074 2075 Check_PushLocalFrame, 2076 Check_PopLocalFrame, 2077 2078 Check_NewGlobalRef, 2079 Check_DeleteGlobalRef, 2080 Check_DeleteLocalRef, 2081 Check_IsSameObject, 2082 Check_NewLocalRef, 2083 Check_EnsureLocalCapacity, 2084 2085 Check_AllocObject, 2086 Check_NewObject, 2087 Check_NewObjectV, 2088 Check_NewObjectA, 2089 2090 Check_GetObjectClass, 2091 Check_IsInstanceOf, 2092 2093 Check_GetMethodID, 2094 2095 Check_CallObjectMethod, 2096 Check_CallObjectMethodV, 2097 Check_CallObjectMethodA, 2098 Check_CallBooleanMethod, 2099 Check_CallBooleanMethodV, 2100 Check_CallBooleanMethodA, 2101 Check_CallByteMethod, 2102 Check_CallByteMethodV, 2103 Check_CallByteMethodA, 2104 Check_CallCharMethod, 2105 Check_CallCharMethodV, 2106 Check_CallCharMethodA, 2107 Check_CallShortMethod, 2108 Check_CallShortMethodV, 2109 Check_CallShortMethodA, 2110 Check_CallIntMethod, 2111 Check_CallIntMethodV, 2112 Check_CallIntMethodA, 2113 Check_CallLongMethod, 2114 Check_CallLongMethodV, 2115 Check_CallLongMethodA, 2116 Check_CallFloatMethod, 2117 Check_CallFloatMethodV, 2118 Check_CallFloatMethodA, 2119 Check_CallDoubleMethod, 2120 Check_CallDoubleMethodV, 2121 Check_CallDoubleMethodA, 2122 Check_CallVoidMethod, 2123 Check_CallVoidMethodV, 2124 Check_CallVoidMethodA, 2125 2126 Check_CallNonvirtualObjectMethod, 2127 Check_CallNonvirtualObjectMethodV, 2128 Check_CallNonvirtualObjectMethodA, 2129 Check_CallNonvirtualBooleanMethod, 2130 Check_CallNonvirtualBooleanMethodV, 2131 Check_CallNonvirtualBooleanMethodA, 2132 Check_CallNonvirtualByteMethod, 2133 Check_CallNonvirtualByteMethodV, 2134 Check_CallNonvirtualByteMethodA, 2135 Check_CallNonvirtualCharMethod, 2136 Check_CallNonvirtualCharMethodV, 2137 Check_CallNonvirtualCharMethodA, 2138 Check_CallNonvirtualShortMethod, 2139 Check_CallNonvirtualShortMethodV, 2140 Check_CallNonvirtualShortMethodA, 2141 Check_CallNonvirtualIntMethod, 2142 Check_CallNonvirtualIntMethodV, 2143 Check_CallNonvirtualIntMethodA, 2144 Check_CallNonvirtualLongMethod, 2145 Check_CallNonvirtualLongMethodV, 2146 Check_CallNonvirtualLongMethodA, 2147 Check_CallNonvirtualFloatMethod, 2148 Check_CallNonvirtualFloatMethodV, 2149 Check_CallNonvirtualFloatMethodA, 2150 Check_CallNonvirtualDoubleMethod, 2151 Check_CallNonvirtualDoubleMethodV, 2152 Check_CallNonvirtualDoubleMethodA, 2153 Check_CallNonvirtualVoidMethod, 2154 Check_CallNonvirtualVoidMethodV, 2155 Check_CallNonvirtualVoidMethodA, 2156 2157 Check_GetFieldID, 2158 2159 Check_GetObjectField, 2160 Check_GetBooleanField, 2161 Check_GetByteField, 2162 Check_GetCharField, 2163 Check_GetShortField, 2164 Check_GetIntField, 2165 Check_GetLongField, 2166 Check_GetFloatField, 2167 Check_GetDoubleField, 2168 Check_SetObjectField, 2169 Check_SetBooleanField, 2170 Check_SetByteField, 2171 Check_SetCharField, 2172 Check_SetShortField, 2173 Check_SetIntField, 2174 Check_SetLongField, 2175 Check_SetFloatField, 2176 Check_SetDoubleField, 2177 2178 Check_GetStaticMethodID, 2179 2180 Check_CallStaticObjectMethod, 2181 Check_CallStaticObjectMethodV, 2182 Check_CallStaticObjectMethodA, 2183 Check_CallStaticBooleanMethod, 2184 Check_CallStaticBooleanMethodV, 2185 Check_CallStaticBooleanMethodA, 2186 Check_CallStaticByteMethod, 2187 Check_CallStaticByteMethodV, 2188 Check_CallStaticByteMethodA, 2189 Check_CallStaticCharMethod, 2190 Check_CallStaticCharMethodV, 2191 Check_CallStaticCharMethodA, 2192 Check_CallStaticShortMethod, 2193 Check_CallStaticShortMethodV, 2194 Check_CallStaticShortMethodA, 2195 Check_CallStaticIntMethod, 2196 Check_CallStaticIntMethodV, 2197 Check_CallStaticIntMethodA, 2198 Check_CallStaticLongMethod, 2199 Check_CallStaticLongMethodV, 2200 Check_CallStaticLongMethodA, 2201 Check_CallStaticFloatMethod, 2202 Check_CallStaticFloatMethodV, 2203 Check_CallStaticFloatMethodA, 2204 Check_CallStaticDoubleMethod, 2205 Check_CallStaticDoubleMethodV, 2206 Check_CallStaticDoubleMethodA, 2207 Check_CallStaticVoidMethod, 2208 Check_CallStaticVoidMethodV, 2209 Check_CallStaticVoidMethodA, 2210 2211 Check_GetStaticFieldID, 2212 2213 Check_GetStaticObjectField, 2214 Check_GetStaticBooleanField, 2215 Check_GetStaticByteField, 2216 Check_GetStaticCharField, 2217 Check_GetStaticShortField, 2218 Check_GetStaticIntField, 2219 Check_GetStaticLongField, 2220 Check_GetStaticFloatField, 2221 Check_GetStaticDoubleField, 2222 2223 Check_SetStaticObjectField, 2224 Check_SetStaticBooleanField, 2225 Check_SetStaticByteField, 2226 Check_SetStaticCharField, 2227 Check_SetStaticShortField, 2228 Check_SetStaticIntField, 2229 Check_SetStaticLongField, 2230 Check_SetStaticFloatField, 2231 Check_SetStaticDoubleField, 2232 2233 Check_NewString, 2234 2235 Check_GetStringLength, 2236 Check_GetStringChars, 2237 Check_ReleaseStringChars, 2238 2239 Check_NewStringUTF, 2240 Check_GetStringUTFLength, 2241 Check_GetStringUTFChars, 2242 Check_ReleaseStringUTFChars, 2243 2244 Check_GetArrayLength, 2245 Check_NewObjectArray, 2246 Check_GetObjectArrayElement, 2247 Check_SetObjectArrayElement, 2248 2249 Check_NewBooleanArray, 2250 Check_NewByteArray, 2251 Check_NewCharArray, 2252 Check_NewShortArray, 2253 Check_NewIntArray, 2254 Check_NewLongArray, 2255 Check_NewFloatArray, 2256 Check_NewDoubleArray, 2257 2258 Check_GetBooleanArrayElements, 2259 Check_GetByteArrayElements, 2260 Check_GetCharArrayElements, 2261 Check_GetShortArrayElements, 2262 Check_GetIntArrayElements, 2263 Check_GetLongArrayElements, 2264 Check_GetFloatArrayElements, 2265 Check_GetDoubleArrayElements, 2266 2267 Check_ReleaseBooleanArrayElements, 2268 Check_ReleaseByteArrayElements, 2269 Check_ReleaseCharArrayElements, 2270 Check_ReleaseShortArrayElements, 2271 Check_ReleaseIntArrayElements, 2272 Check_ReleaseLongArrayElements, 2273 Check_ReleaseFloatArrayElements, 2274 Check_ReleaseDoubleArrayElements, 2275 2276 Check_GetBooleanArrayRegion, 2277 Check_GetByteArrayRegion, 2278 Check_GetCharArrayRegion, 2279 Check_GetShortArrayRegion, 2280 Check_GetIntArrayRegion, 2281 Check_GetLongArrayRegion, 2282 Check_GetFloatArrayRegion, 2283 Check_GetDoubleArrayRegion, 2284 Check_SetBooleanArrayRegion, 2285 Check_SetByteArrayRegion, 2286 Check_SetCharArrayRegion, 2287 Check_SetShortArrayRegion, 2288 Check_SetIntArrayRegion, 2289 Check_SetLongArrayRegion, 2290 Check_SetFloatArrayRegion, 2291 Check_SetDoubleArrayRegion, 2292 2293 Check_RegisterNatives, 2294 Check_UnregisterNatives, 2295 2296 Check_MonitorEnter, 2297 Check_MonitorExit, 2298 2299 Check_GetJavaVM, 2300 2301 Check_GetStringRegion, 2302 Check_GetStringUTFRegion, 2303 2304 Check_GetPrimitiveArrayCritical, 2305 Check_ReleasePrimitiveArrayCritical, 2306 2307 Check_GetStringCritical, 2308 Check_ReleaseStringCritical, 2309 2310 Check_NewWeakGlobalRef, 2311 Check_DeleteWeakGlobalRef, 2312 2313 Check_ExceptionCheck, 2314 2315 Check_NewDirectByteBuffer, 2316 Check_GetDirectBufferAddress, 2317 Check_GetDirectBufferCapacity, 2318 2319 Check_GetObjectRefType 2320}; 2321 2322static const struct JNIInvokeInterface gCheckInvokeInterface = { 2323 NULL, 2324 NULL, 2325 NULL, 2326 2327 Check_DestroyJavaVM, 2328 Check_AttachCurrentThread, 2329 Check_DetachCurrentThread, 2330 2331 Check_GetEnv, 2332 2333 Check_AttachCurrentThreadAsDaemon, 2334}; 2335 2336/* 2337 * Replace the normal table with the checked table. 2338 */ 2339void dvmUseCheckedJniEnv(JNIEnvExt* pEnv) { 2340 assert(pEnv->funcTable != &gCheckNativeInterface); 2341 pEnv->baseFuncTable = pEnv->funcTable; 2342 pEnv->funcTable = &gCheckNativeInterface; 2343} 2344 2345/* 2346 * Replace the normal table with the checked table. 2347 */ 2348void dvmUseCheckedJniVm(JavaVMExt* pVm) { 2349 assert(pVm->funcTable != &gCheckInvokeInterface); 2350 pVm->baseFuncTable = pVm->funcTable; 2351 pVm->funcTable = &gCheckInvokeInterface; 2352} 2353