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