Home | History | Annotate | Download | only in analysis
      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  * Dalvik classfile verification.  This file contains the verifier entry
     19  * points and the static constraint checks.
     20  */
     21 #include "Dalvik.h"
     22 #include "analysis/CodeVerify.h"
     23 #include "libdex/DexCatch.h"
     24 
     25 
     26 /* fwd */
     27 static bool verifyMethod(Method* meth);
     28 static bool verifyInstructions(VerifierData* vdata);
     29 
     30 
     31 /*
     32  * Verify a class.
     33  *
     34  * By the time we get here, the value of gDvm.classVerifyMode should already
     35  * have been factored in.  If you want to call into the verifier even
     36  * though verification is disabled, that's your business.
     37  *
     38  * Returns "true" on success.
     39  */
     40 bool dvmVerifyClass(ClassObject* clazz)
     41 {
     42     int i;
     43 
     44     if (dvmIsClassVerified(clazz)) {
     45         ALOGD("Ignoring duplicate verify attempt on %s", clazz->descriptor);
     46         return true;
     47     }
     48 
     49     for (i = 0; i < clazz->directMethodCount; i++) {
     50         if (!verifyMethod(&clazz->directMethods[i])) {
     51             LOG_VFY("Verifier rejected class %s", clazz->descriptor);
     52             return false;
     53         }
     54     }
     55     for (i = 0; i < clazz->virtualMethodCount; i++) {
     56         if (!verifyMethod(&clazz->virtualMethods[i])) {
     57             LOG_VFY("Verifier rejected class %s", clazz->descriptor);
     58             return false;
     59         }
     60     }
     61 
     62     return true;
     63 }
     64 
     65 
     66 /*
     67  * Compute the width of the instruction at each address in the instruction
     68  * stream, and store it in vdata->insnFlags.  Addresses that are in the
     69  * middle of an instruction, or that are part of switch table data, are not
     70  * touched (so the caller should probably initialize "insnFlags" to zero).
     71  *
     72  * The "newInstanceCount" and "monitorEnterCount" fields in vdata are
     73  * also set.
     74  *
     75  * Performs some static checks, notably:
     76  * - opcode of first instruction begins at index 0
     77  * - only documented instructions may appear
     78  * - each instruction follows the last
     79  * - last byte of last instruction is at (code_length-1)
     80  *
     81  * Logs an error and returns "false" on failure.
     82  */
     83 static bool computeWidthsAndCountOps(VerifierData* vdata)
     84 {
     85     const Method* meth = vdata->method;
     86     InsnFlags* insnFlags = vdata->insnFlags;
     87     size_t insnCount = vdata->insnsSize;
     88     const u2* insns = meth->insns;
     89     bool result = false;
     90     int newInstanceCount = 0;
     91     int monitorEnterCount = 0;
     92     int i;
     93 
     94     for (i = 0; i < (int) insnCount; /**/) {
     95         size_t width = dexGetWidthFromInstruction(insns);
     96         if (width == 0) {
     97             LOG_VFY_METH(meth, "VFY: invalid instruction (0x%04x)", *insns);
     98             goto bail;
     99         } else if (width > 65535) {
    100             LOG_VFY_METH(meth,
    101                 "VFY: warning: unusually large instr width (%d)", width);
    102         }
    103 
    104         Opcode opcode = dexOpcodeFromCodeUnit(*insns);
    105         if (opcode == OP_NEW_INSTANCE)
    106             newInstanceCount++;
    107         if (opcode == OP_MONITOR_ENTER)
    108             monitorEnterCount++;
    109 
    110         insnFlags[i] |= width;
    111         i += width;
    112         insns += width;
    113     }
    114     if (i != (int) vdata->insnsSize) {
    115         LOG_VFY_METH(meth, "VFY: code did not end where expected (%d vs. %d)",
    116             i, dvmGetMethodInsnsSize(meth));
    117         goto bail;
    118     }
    119 
    120     result = true;
    121     vdata->newInstanceCount = newInstanceCount;
    122     vdata->monitorEnterCount = monitorEnterCount;
    123 
    124 bail:
    125     return result;
    126 }
    127 
    128 /*
    129  * Set the "in try" flags for all instructions protected by "try" statements.
    130  * Also sets the "branch target" flags for exception handlers.
    131  *
    132  * Call this after widths have been set in "insnFlags".
    133  *
    134  * Returns "false" if something in the exception table looks fishy, but
    135  * we're expecting the exception table to be somewhat sane.
    136  */
    137 static bool scanTryCatchBlocks(const Method* meth, InsnFlags* insnFlags)
    138 {
    139     u4 insnsSize = dvmGetMethodInsnsSize(meth);
    140     const DexCode* pCode = dvmGetMethodCode(meth);
    141     u4 triesSize = pCode->triesSize;
    142     const DexTry* pTries;
    143     u4 idx;
    144 
    145     if (triesSize == 0) {
    146         return true;
    147     }
    148 
    149     pTries = dexGetTries(pCode);
    150 
    151     for (idx = 0; idx < triesSize; idx++) {
    152         const DexTry* pTry = &pTries[idx];
    153         u4 start = pTry->startAddr;
    154         u4 end = start + pTry->insnCount;
    155         u4 addr;
    156 
    157         if ((start >= end) || (start >= insnsSize) || (end > insnsSize)) {
    158             LOG_VFY_METH(meth,
    159                 "VFY: bad exception entry: startAddr=%d endAddr=%d (size=%d)",
    160                 start, end, insnsSize);
    161             return false;
    162         }
    163 
    164         if (dvmInsnGetWidth(insnFlags, start) == 0) {
    165             LOG_VFY_METH(meth,
    166                 "VFY: 'try' block starts inside an instruction (%d)",
    167                 start);
    168             return false;
    169         }
    170 
    171         for (addr = start; addr < end;
    172             addr += dvmInsnGetWidth(insnFlags, addr))
    173         {
    174             assert(dvmInsnGetWidth(insnFlags, addr) != 0);
    175             dvmInsnSetInTry(insnFlags, addr, true);
    176         }
    177     }
    178 
    179     /* Iterate over each of the handlers to verify target addresses. */
    180     u4 handlersSize = dexGetHandlersSize(pCode);
    181     u4 offset = dexGetFirstHandlerOffset(pCode);
    182     for (idx = 0; idx < handlersSize; idx++) {
    183         DexCatchIterator iterator;
    184         dexCatchIteratorInit(&iterator, pCode, offset);
    185 
    186         for (;;) {
    187             DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
    188             u4 addr;
    189 
    190             if (handler == NULL) {
    191                 break;
    192             }
    193 
    194             addr = handler->address;
    195             if (dvmInsnGetWidth(insnFlags, addr) == 0) {
    196                 LOG_VFY_METH(meth,
    197                     "VFY: exception handler starts at bad address (%d)",
    198                     addr);
    199                 return false;
    200             }
    201 
    202             dvmInsnSetBranchTarget(insnFlags, addr, true);
    203         }
    204 
    205         offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
    206     }
    207 
    208     return true;
    209 }
    210 
    211 /*
    212  * Perform verification on a single method.
    213  *
    214  * We do this in three passes:
    215  *  (1) Walk through all code units, determining instruction locations,
    216  *      widths, and other characteristics.
    217  *  (2) Walk through all code units, performing static checks on
    218  *      operands.
    219  *  (3) Iterate through the method, checking type safety and looking
    220  *      for code flow problems.
    221  *
    222  * Some checks may be bypassed depending on the verification mode.  We can't
    223  * turn this stuff off completely if we want to do "exact" GC.
    224  *
    225  * TODO: cite source?
    226  * Confirmed here:
    227  * - code array must not be empty
    228  * - (N/A) code_length must be less than 65536
    229  * Confirmed by computeWidthsAndCountOps():
    230  * - opcode of first instruction begins at index 0
    231  * - only documented instructions may appear
    232  * - each instruction follows the last
    233  * - last byte of last instruction is at (code_length-1)
    234  */
    235 static bool verifyMethod(Method* meth)
    236 {
    237     bool result = false;
    238 
    239     /*
    240      * Verifier state blob.  Various values will be cached here so we
    241      * can avoid expensive lookups and pass fewer arguments around.
    242      */
    243     VerifierData vdata;
    244 #if 1   // ndef NDEBUG
    245     memset(&vdata, 0x99, sizeof(vdata));
    246 #endif
    247 
    248     vdata.method = meth;
    249     vdata.insnsSize = dvmGetMethodInsnsSize(meth);
    250     vdata.insnRegCount = meth->registersSize;
    251     vdata.insnFlags = NULL;
    252     vdata.uninitMap = NULL;
    253     vdata.basicBlocks = NULL;
    254 
    255     /*
    256      * If there aren't any instructions, make sure that's expected, then
    257      * exit successfully.  Note: for native methods, meth->insns gets set
    258      * to a native function pointer on first call, so don't use that as
    259      * an indicator.
    260      */
    261     if (vdata.insnsSize == 0) {
    262         if (!dvmIsNativeMethod(meth) && !dvmIsAbstractMethod(meth)) {
    263             LOG_VFY_METH(meth,
    264                 "VFY: zero-length code in concrete non-native method");
    265             goto bail;
    266         }
    267 
    268         goto success;
    269     }
    270 
    271     /*
    272      * Sanity-check the register counts.  ins + locals = registers, so make
    273      * sure that ins <= registers.
    274      */
    275     if (meth->insSize > meth->registersSize) {
    276         LOG_VFY_METH(meth, "VFY: bad register counts (ins=%d regs=%d)",
    277             meth->insSize, meth->registersSize);
    278         goto bail;
    279     }
    280 
    281     /*
    282      * Allocate and populate an array to hold instruction data.
    283      *
    284      * TODO: Consider keeping a reusable pre-allocated array sitting
    285      * around for smaller methods.
    286      */
    287     vdata.insnFlags = (InsnFlags*) calloc(vdata.insnsSize, sizeof(InsnFlags));
    288     if (vdata.insnFlags == NULL)
    289         goto bail;
    290 
    291     /*
    292      * Compute the width of each instruction and store the result in insnFlags.
    293      * Count up the #of occurrences of certain opcodes while we're at it.
    294      */
    295     if (!computeWidthsAndCountOps(&vdata))
    296         goto bail;
    297 
    298     /*
    299      * Allocate a map to hold the classes of uninitialized instances.
    300      */
    301     vdata.uninitMap = dvmCreateUninitInstanceMap(meth, vdata.insnFlags,
    302         vdata.newInstanceCount);
    303     if (vdata.uninitMap == NULL)
    304         goto bail;
    305 
    306     /*
    307      * Set the "in try" flags for all instructions guarded by a "try" block.
    308      * Also sets the "branch target" flag on exception handlers.
    309      */
    310     if (!scanTryCatchBlocks(meth, vdata.insnFlags))
    311         goto bail;
    312 
    313     /*
    314      * Perform static instruction verification.  Also sets the "branch
    315      * target" flags.
    316      */
    317     if (!verifyInstructions(&vdata))
    318         goto bail;
    319 
    320     /*
    321      * Do code-flow analysis.
    322      *
    323      * We could probably skip this for a method with no registers, but
    324      * that's so rare that there's little point in checking.
    325      */
    326     if (!dvmVerifyCodeFlow(&vdata)) {
    327         //ALOGD("+++ %s failed code flow", meth->name);
    328         goto bail;
    329     }
    330 
    331 success:
    332     result = true;
    333 
    334 bail:
    335     dvmFreeVfyBasicBlocks(&vdata);
    336     dvmFreeUninitInstanceMap(vdata.uninitMap);
    337     free(vdata.insnFlags);
    338     return result;
    339 }
    340 
    341 
    342 /*
    343  * Verify an array data table.  "curOffset" is the offset of the
    344  * fill-array-data instruction.
    345  */
    346 static bool checkArrayData(const Method* meth, u4 curOffset)
    347 {
    348     const u4 insnCount = dvmGetMethodInsnsSize(meth);
    349     const u2* insns = meth->insns + curOffset;
    350     const u2* arrayData;
    351     u4 valueCount, valueWidth, tableSize;
    352     s4 offsetToArrayData;
    353 
    354     assert(curOffset < insnCount);
    355 
    356     /* make sure the start of the array data table is in range */
    357     offsetToArrayData = insns[1] | (((s4)insns[2]) << 16);
    358     if ((s4)curOffset + offsetToArrayData < 0 ||
    359         curOffset + offsetToArrayData + 2 >= insnCount)
    360     {
    361         LOG_VFY("VFY: invalid array data start: at %d, data offset %d, "
    362                 "count %d",
    363             curOffset, offsetToArrayData, insnCount);
    364         return false;
    365     }
    366 
    367     /* offset to array data table is a relative branch-style offset */
    368     arrayData = insns + offsetToArrayData;
    369 
    370     /* make sure the table is 32-bit aligned */
    371     if ((((u4) arrayData) & 0x03) != 0) {
    372         LOG_VFY("VFY: unaligned array data table: at %d, data offset %d",
    373             curOffset, offsetToArrayData);
    374         return false;
    375     }
    376 
    377     valueWidth = arrayData[1];
    378     valueCount = *(u4*)(&arrayData[2]);
    379 
    380     tableSize = 4 + (valueWidth * valueCount + 1) / 2;
    381 
    382     /* make sure the end of the switch is in range */
    383     if (curOffset + offsetToArrayData + tableSize > insnCount) {
    384         LOG_VFY("VFY: invalid array data end: at %d, data offset %d, end %d, "
    385                 "count %d",
    386             curOffset, offsetToArrayData,
    387             curOffset + offsetToArrayData + tableSize, insnCount);
    388         return false;
    389     }
    390 
    391     return true;
    392 }
    393 
    394 /*
    395  * Perform static checks on a "new-instance" instruction.  Specifically,
    396  * make sure the class reference isn't for an array class.
    397  *
    398  * We don't need the actual class, just a pointer to the class name.
    399  */
    400 static bool checkNewInstance(const DvmDex* pDvmDex, u4 idx)
    401 {
    402     const char* classDescriptor;
    403 
    404     if (idx >= pDvmDex->pHeader->typeIdsSize) {
    405         LOG_VFY("VFY: bad type index %d (max %d)",
    406             idx, pDvmDex->pHeader->typeIdsSize);
    407         return false;
    408     }
    409 
    410     classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
    411     if (classDescriptor[0] != 'L') {
    412         LOG_VFY("VFY: can't call new-instance on type '%s'",
    413             classDescriptor);
    414         return false;
    415     }
    416 
    417     return true;
    418 }
    419 
    420 /*
    421  * Perform static checks on a "new-array" instruction.  Specifically, make
    422  * sure they aren't creating an array of arrays that causes the number of
    423  * dimensions to exceed 255.
    424  */
    425 static bool checkNewArray(const DvmDex* pDvmDex, u4 idx)
    426 {
    427     const char* classDescriptor;
    428 
    429     if (idx >= pDvmDex->pHeader->typeIdsSize) {
    430         LOG_VFY("VFY: bad type index %d (max %d)",
    431             idx, pDvmDex->pHeader->typeIdsSize);
    432         return false;
    433     }
    434 
    435     classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
    436 
    437     int bracketCount = 0;
    438     const char* cp = classDescriptor;
    439     while (*cp++ == '[')
    440         bracketCount++;
    441 
    442     if (bracketCount == 0) {
    443         /* The given class must be an array type. */
    444         LOG_VFY("VFY: can't new-array class '%s' (not an array)",
    445             classDescriptor);
    446         return false;
    447     } else if (bracketCount > 255) {
    448         /* It is illegal to create an array of more than 255 dimensions. */
    449         LOG_VFY("VFY: can't new-array class '%s' (exceeds limit)",
    450             classDescriptor);
    451         return false;
    452     }
    453 
    454     return true;
    455 }
    456 
    457 /*
    458  * Perform static checks on an instruction that takes a class constant.
    459  * Ensure that the class index is in the valid range.
    460  */
    461 static bool checkTypeIndex(const DvmDex* pDvmDex, u4 idx)
    462 {
    463     if (idx >= pDvmDex->pHeader->typeIdsSize) {
    464         LOG_VFY("VFY: bad type index %d (max %d)",
    465             idx, pDvmDex->pHeader->typeIdsSize);
    466         return false;
    467     }
    468     return true;
    469 }
    470 
    471 /*
    472  * Perform static checks on a field get or set instruction.  All we do
    473  * here is ensure that the field index is in the valid range.
    474  */
    475 static bool checkFieldIndex(const DvmDex* pDvmDex, u4 idx)
    476 {
    477     if (idx >= pDvmDex->pHeader->fieldIdsSize) {
    478         LOG_VFY("VFY: bad field index %d (max %d)",
    479             idx, pDvmDex->pHeader->fieldIdsSize);
    480         return false;
    481     }
    482     return true;
    483 }
    484 
    485 /*
    486  * Perform static checks on a method invocation instruction.  All we do
    487  * here is ensure that the method index is in the valid range.
    488  */
    489 static bool checkMethodIndex(const DvmDex* pDvmDex, u4 idx)
    490 {
    491     if (idx >= pDvmDex->pHeader->methodIdsSize) {
    492         LOG_VFY("VFY: bad method index %d (max %d)",
    493             idx, pDvmDex->pHeader->methodIdsSize);
    494         return false;
    495     }
    496     return true;
    497 }
    498 
    499 /*
    500  * Ensure that the string index is in the valid range.
    501  */
    502 static bool checkStringIndex(const DvmDex* pDvmDex, u4 idx)
    503 {
    504     if (idx >= pDvmDex->pHeader->stringIdsSize) {
    505         LOG_VFY("VFY: bad string index %d (max %d)",
    506             idx, pDvmDex->pHeader->stringIdsSize);
    507         return false;
    508     }
    509     return true;
    510 }
    511 
    512 /*
    513  * Ensure that the register index is valid for this method.
    514  */
    515 static bool checkRegisterIndex(const Method* meth, u4 idx)
    516 {
    517     if (idx >= meth->registersSize) {
    518         LOG_VFY("VFY: register index out of range (%d >= %d)",
    519             idx, meth->registersSize);
    520         return false;
    521     }
    522     return true;
    523 }
    524 
    525 /*
    526  * Ensure that the wide register index is valid for this method.
    527  */
    528 static bool checkWideRegisterIndex(const Method* meth, u4 idx)
    529 {
    530     if (idx+1 >= meth->registersSize) {
    531         LOG_VFY("VFY: wide register index out of range (%d+1 >= %d)",
    532             idx, meth->registersSize);
    533         return false;
    534     }
    535     return true;
    536 }
    537 
    538 /*
    539  * Check the register indices used in a "vararg" instruction, such as
    540  * invoke-virtual or filled-new-array.
    541  *
    542  * vA holds word count (0-5), args[] have values.
    543  *
    544  * There are some tests we don't do here, e.g. we don't try to verify
    545  * that invoking a method that takes a double is done with consecutive
    546  * registers.  This requires parsing the target method signature, which
    547  * we will be doing later on during the code flow analysis.
    548  */
    549 static bool checkVarargRegs(const Method* meth,
    550     const DecodedInstruction* pDecInsn)
    551 {
    552     u2 registersSize = meth->registersSize;
    553     unsigned int idx;
    554 
    555     if (pDecInsn->vA > 5) {
    556         LOG_VFY("VFY: invalid arg count (%d) in non-range invoke)",
    557             pDecInsn->vA);
    558         return false;
    559     }
    560 
    561     for (idx = 0; idx < pDecInsn->vA; idx++) {
    562         if (pDecInsn->arg[idx] > registersSize) {
    563             LOG_VFY("VFY: invalid reg index (%d) in non-range invoke (> %d)",
    564                 pDecInsn->arg[idx], registersSize);
    565             return false;
    566         }
    567     }
    568 
    569     return true;
    570 }
    571 
    572 /*
    573  * Check the register indices used in a "vararg/range" instruction, such as
    574  * invoke-virtual/range or filled-new-array/range.
    575  *
    576  * vA holds word count, vC holds index of first reg.
    577  */
    578 static bool checkVarargRangeRegs(const Method* meth,
    579     const DecodedInstruction* pDecInsn)
    580 {
    581     u2 registersSize = meth->registersSize;
    582 
    583     /*
    584      * vA/vC are unsigned 8-bit/16-bit quantities for /range instructions,
    585      * so there's no risk of integer overflow when adding them here.
    586      */
    587     if (pDecInsn->vA + pDecInsn->vC > registersSize) {
    588         LOG_VFY("VFY: invalid reg index %d+%d in range invoke (> %d)",
    589             pDecInsn->vA, pDecInsn->vC, registersSize);
    590         return false;
    591     }
    592 
    593     return true;
    594 }
    595 
    596 /*
    597  * Verify a switch table.  "curOffset" is the offset of the switch
    598  * instruction.
    599  *
    600  * Updates "insnFlags", setting the "branch target" flag.
    601  */
    602 static bool checkSwitchTargets(const Method* meth, InsnFlags* insnFlags,
    603     u4 curOffset)
    604 {
    605     const u4 insnCount = dvmGetMethodInsnsSize(meth);
    606     const u2* insns = meth->insns + curOffset;
    607     const u2* switchInsns;
    608     u2 expectedSignature;
    609     u4 switchCount, tableSize;
    610     s4 offsetToSwitch, offsetToKeys, offsetToTargets;
    611     s4 offset, absOffset;
    612     u4 targ;
    613 
    614     assert(curOffset < insnCount);
    615 
    616     /* make sure the start of the switch is in range */
    617     offsetToSwitch = insns[1] | ((s4) insns[2]) << 16;
    618     if ((s4) curOffset + offsetToSwitch < 0 ||
    619         curOffset + offsetToSwitch + 2 >= insnCount)
    620     {
    621         LOG_VFY("VFY: invalid switch start: at %d, switch offset %d, "
    622                 "count %d",
    623             curOffset, offsetToSwitch, insnCount);
    624         return false;
    625     }
    626 
    627     /* offset to switch table is a relative branch-style offset */
    628     switchInsns = insns + offsetToSwitch;
    629 
    630     /* make sure the table is 32-bit aligned */
    631     if ((((u4) switchInsns) & 0x03) != 0) {
    632         LOG_VFY("VFY: unaligned switch table: at %d, switch offset %d",
    633             curOffset, offsetToSwitch);
    634         return false;
    635     }
    636 
    637     switchCount = switchInsns[1];
    638 
    639     if ((*insns & 0xff) == OP_PACKED_SWITCH) {
    640         /* 0=sig, 1=count, 2/3=firstKey */
    641         offsetToTargets = 4;
    642         offsetToKeys = -1;
    643         expectedSignature = kPackedSwitchSignature;
    644     } else {
    645         /* 0=sig, 1=count, 2..count*2 = keys */
    646         offsetToKeys = 2;
    647         offsetToTargets = 2 + 2*switchCount;
    648         expectedSignature = kSparseSwitchSignature;
    649     }
    650     tableSize = offsetToTargets + switchCount*2;
    651 
    652     if (switchInsns[0] != expectedSignature) {
    653         LOG_VFY("VFY: wrong signature for switch table (0x%04x, wanted 0x%04x)",
    654             switchInsns[0], expectedSignature);
    655         return false;
    656     }
    657 
    658     /* make sure the end of the switch is in range */
    659     if (curOffset + offsetToSwitch + tableSize > (u4) insnCount) {
    660         LOG_VFY("VFY: invalid switch end: at %d, switch offset %d, end %d, "
    661                 "count %d",
    662             curOffset, offsetToSwitch, curOffset + offsetToSwitch + tableSize,
    663             insnCount);
    664         return false;
    665     }
    666 
    667     /* for a sparse switch, verify the keys are in ascending order */
    668     if (offsetToKeys > 0 && switchCount > 1) {
    669         s4 lastKey;
    670 
    671         lastKey = switchInsns[offsetToKeys] |
    672                   (switchInsns[offsetToKeys+1] << 16);
    673         for (targ = 1; targ < switchCount; targ++) {
    674             s4 key = (s4) switchInsns[offsetToKeys + targ*2] |
    675                     (s4) (switchInsns[offsetToKeys + targ*2 +1] << 16);
    676             if (key <= lastKey) {
    677                 LOG_VFY("VFY: invalid packed switch: last key=%d, this=%d",
    678                     lastKey, key);
    679                 return false;
    680             }
    681 
    682             lastKey = key;
    683         }
    684     }
    685 
    686     /* verify each switch target */
    687     for (targ = 0; targ < switchCount; targ++) {
    688         offset = (s4) switchInsns[offsetToTargets + targ*2] |
    689                 (s4) (switchInsns[offsetToTargets + targ*2 +1] << 16);
    690         absOffset = curOffset + offset;
    691 
    692         if (absOffset < 0 || absOffset >= (s4)insnCount ||
    693             !dvmInsnIsOpcode(insnFlags, absOffset))
    694         {
    695             LOG_VFY("VFY: invalid switch target %d (-> %#x) at %#x[%d]",
    696                 offset, absOffset, curOffset, targ);
    697             return false;
    698         }
    699         dvmInsnSetBranchTarget(insnFlags, absOffset, true);
    700     }
    701 
    702     return true;
    703 }
    704 
    705 /*
    706  * Verify that the target of a branch instruction is valid.
    707  *
    708  * We don't expect code to jump directly into an exception handler, but
    709  * it's valid to do so as long as the target isn't a "move-exception"
    710  * instruction.  We verify that in a later stage.
    711  *
    712  * The VM spec doesn't forbid an instruction from branching to itself,
    713  * but the Dalvik spec declares that only certain instructions can do so.
    714  *
    715  * Updates "insnFlags", setting the "branch target" flag.
    716  */
    717 static bool checkBranchTarget(const Method* meth, InsnFlags* insnFlags,
    718     int curOffset, bool selfOkay)
    719 {
    720     const int insnCount = dvmGetMethodInsnsSize(meth);
    721     s4 offset, absOffset;
    722     bool isConditional;
    723 
    724     if (!dvmGetBranchOffset(meth, insnFlags, curOffset, &offset,
    725             &isConditional))
    726         return false;
    727 
    728     if (!selfOkay && offset == 0) {
    729         LOG_VFY_METH(meth, "VFY: branch offset of zero not allowed at %#x",
    730             curOffset);
    731         return false;
    732     }
    733 
    734     /*
    735      * Check for 32-bit overflow.  This isn't strictly necessary if we can
    736      * depend on the VM to have identical "wrap-around" behavior, but
    737      * it's unwise to depend on that.
    738      */
    739     if (((s8) curOffset + (s8) offset) != (s8)(curOffset + offset)) {
    740         LOG_VFY_METH(meth, "VFY: branch target overflow %#x +%d",
    741             curOffset, offset);
    742         return false;
    743     }
    744     absOffset = curOffset + offset;
    745     if (absOffset < 0 || absOffset >= insnCount ||
    746         !dvmInsnIsOpcode(insnFlags, absOffset))
    747     {
    748         LOG_VFY_METH(meth,
    749             "VFY: invalid branch target %d (-> %#x) at %#x",
    750             offset, absOffset, curOffset);
    751         return false;
    752     }
    753     dvmInsnSetBranchTarget(insnFlags, absOffset, true);
    754 
    755     return true;
    756 }
    757 
    758 
    759 /*
    760  * Perform static verification on instructions.
    761  *
    762  * As a side effect, this sets the "branch target" flags in InsnFlags.
    763  *
    764  * "(CF)" items are handled during code-flow analysis.
    765  *
    766  * v3 4.10.1
    767  * - target of each jump and branch instruction must be valid
    768  * - targets of switch statements must be valid
    769  * - operands referencing constant pool entries must be valid
    770  * - (CF) operands of getfield, putfield, getstatic, putstatic must be valid
    771  * - (new) verify operands of "quick" field ops
    772  * - (CF) operands of method invocation instructions must be valid
    773  * - (new) verify operands of "quick" method invoke ops
    774  * - (CF) only invoke-direct can call a method starting with '<'
    775  * - (CF) <clinit> must never be called explicitly
    776  * - operands of instanceof, checkcast, new (and variants) must be valid
    777  * - new-array[-type] limited to 255 dimensions
    778  * - can't use "new" on an array class
    779  * - (?) limit dimensions in multi-array creation
    780  * - local variable load/store register values must be in valid range
    781  *
    782  * v3 4.11.1.2
    783  * - branches must be within the bounds of the code array
    784  * - targets of all control-flow instructions are the start of an instruction
    785  * - register accesses fall within range of allocated registers
    786  * - (N/A) access to constant pool must be of appropriate type
    787  * - code does not end in the middle of an instruction
    788  * - execution cannot fall off the end of the code
    789  * - (earlier) for each exception handler, the "try" area must begin and
    790  *   end at the start of an instruction (end can be at the end of the code)
    791  * - (earlier) for each exception handler, the handler must start at a valid
    792  *   instruction
    793  */
    794 static bool verifyInstructions(VerifierData* vdata)
    795 {
    796     const Method* meth = vdata->method;
    797     const DvmDex* pDvmDex = meth->clazz->pDvmDex;
    798     InsnFlags* insnFlags = vdata->insnFlags;
    799     const u2* insns = meth->insns;
    800     unsigned int codeOffset;
    801 
    802     /* the start of the method is a "branch target" */
    803     dvmInsnSetBranchTarget(insnFlags, 0, true);
    804 
    805     for (codeOffset = 0; codeOffset < vdata->insnsSize; /**/) {
    806         /*
    807          * Pull the instruction apart.
    808          */
    809         int width = dvmInsnGetWidth(insnFlags, codeOffset);
    810         DecodedInstruction decInsn;
    811         bool okay = true;
    812 
    813         dexDecodeInstruction(meth->insns + codeOffset, &decInsn);
    814 
    815         /*
    816          * Check register, type, class, field, method, and string indices
    817          * for out-of-range values.  Do additional checks on branch targets
    818          * and some special cases like new-instance and new-array.
    819          */
    820         switch (decInsn.opcode) {
    821         case OP_NOP:
    822         case OP_RETURN_VOID:
    823             /* nothing to check */
    824             break;
    825         case OP_MOVE_RESULT:
    826         case OP_MOVE_RESULT_OBJECT:
    827         case OP_MOVE_EXCEPTION:
    828         case OP_RETURN:
    829         case OP_RETURN_OBJECT:
    830         case OP_CONST_4:
    831         case OP_CONST_16:
    832         case OP_CONST:
    833         case OP_CONST_HIGH16:
    834         case OP_MONITOR_ENTER:
    835         case OP_MONITOR_EXIT:
    836         case OP_THROW:
    837             okay &= checkRegisterIndex(meth, decInsn.vA);
    838             break;
    839         case OP_MOVE_RESULT_WIDE:
    840         case OP_RETURN_WIDE:
    841         case OP_CONST_WIDE_16:
    842         case OP_CONST_WIDE_32:
    843         case OP_CONST_WIDE:
    844         case OP_CONST_WIDE_HIGH16:
    845             okay &= checkWideRegisterIndex(meth, decInsn.vA);
    846             break;
    847         case OP_GOTO:
    848         case OP_GOTO_16:
    849             okay &= checkBranchTarget(meth, insnFlags, codeOffset, false);
    850             break;
    851         case OP_GOTO_32:
    852             okay &= checkBranchTarget(meth, insnFlags, codeOffset, true);
    853             break;
    854         case OP_MOVE:
    855         case OP_MOVE_FROM16:
    856         case OP_MOVE_16:
    857         case OP_MOVE_OBJECT:
    858         case OP_MOVE_OBJECT_FROM16:
    859         case OP_MOVE_OBJECT_16:
    860         case OP_ARRAY_LENGTH:
    861         case OP_NEG_INT:
    862         case OP_NOT_INT:
    863         case OP_NEG_FLOAT:
    864         case OP_INT_TO_FLOAT:
    865         case OP_FLOAT_TO_INT:
    866         case OP_INT_TO_BYTE:
    867         case OP_INT_TO_CHAR:
    868         case OP_INT_TO_SHORT:
    869         case OP_ADD_INT_2ADDR:
    870         case OP_SUB_INT_2ADDR:
    871         case OP_MUL_INT_2ADDR:
    872         case OP_DIV_INT_2ADDR:
    873         case OP_REM_INT_2ADDR:
    874         case OP_AND_INT_2ADDR:
    875         case OP_OR_INT_2ADDR:
    876         case OP_XOR_INT_2ADDR:
    877         case OP_SHL_INT_2ADDR:
    878         case OP_SHR_INT_2ADDR:
    879         case OP_USHR_INT_2ADDR:
    880         case OP_ADD_FLOAT_2ADDR:
    881         case OP_SUB_FLOAT_2ADDR:
    882         case OP_MUL_FLOAT_2ADDR:
    883         case OP_DIV_FLOAT_2ADDR:
    884         case OP_REM_FLOAT_2ADDR:
    885         case OP_ADD_INT_LIT16:
    886         case OP_RSUB_INT:
    887         case OP_MUL_INT_LIT16:
    888         case OP_DIV_INT_LIT16:
    889         case OP_REM_INT_LIT16:
    890         case OP_AND_INT_LIT16:
    891         case OP_OR_INT_LIT16:
    892         case OP_XOR_INT_LIT16:
    893         case OP_ADD_INT_LIT8:
    894         case OP_RSUB_INT_LIT8:
    895         case OP_MUL_INT_LIT8:
    896         case OP_DIV_INT_LIT8:
    897         case OP_REM_INT_LIT8:
    898         case OP_AND_INT_LIT8:
    899         case OP_OR_INT_LIT8:
    900         case OP_XOR_INT_LIT8:
    901         case OP_SHL_INT_LIT8:
    902         case OP_SHR_INT_LIT8:
    903         case OP_USHR_INT_LIT8:
    904             okay &= checkRegisterIndex(meth, decInsn.vA);
    905             okay &= checkRegisterIndex(meth, decInsn.vB);
    906             break;
    907         case OP_INT_TO_LONG:
    908         case OP_INT_TO_DOUBLE:
    909         case OP_FLOAT_TO_LONG:
    910         case OP_FLOAT_TO_DOUBLE:
    911         case OP_SHL_LONG_2ADDR:
    912         case OP_SHR_LONG_2ADDR:
    913         case OP_USHR_LONG_2ADDR:
    914             okay &= checkWideRegisterIndex(meth, decInsn.vA);
    915             okay &= checkRegisterIndex(meth, decInsn.vB);
    916             break;
    917         case OP_LONG_TO_INT:
    918         case OP_LONG_TO_FLOAT:
    919         case OP_DOUBLE_TO_INT:
    920         case OP_DOUBLE_TO_FLOAT:
    921             okay &= checkRegisterIndex(meth, decInsn.vA);
    922             okay &= checkWideRegisterIndex(meth, decInsn.vB);
    923             break;
    924         case OP_MOVE_WIDE:
    925         case OP_MOVE_WIDE_FROM16:
    926         case OP_MOVE_WIDE_16:
    927         case OP_DOUBLE_TO_LONG:
    928         case OP_LONG_TO_DOUBLE:
    929         case OP_NEG_DOUBLE:
    930         case OP_NEG_LONG:
    931         case OP_NOT_LONG:
    932         case OP_ADD_LONG_2ADDR:
    933         case OP_SUB_LONG_2ADDR:
    934         case OP_MUL_LONG_2ADDR:
    935         case OP_DIV_LONG_2ADDR:
    936         case OP_REM_LONG_2ADDR:
    937         case OP_AND_LONG_2ADDR:
    938         case OP_OR_LONG_2ADDR:
    939         case OP_XOR_LONG_2ADDR:
    940         case OP_ADD_DOUBLE_2ADDR:
    941         case OP_SUB_DOUBLE_2ADDR:
    942         case OP_MUL_DOUBLE_2ADDR:
    943         case OP_DIV_DOUBLE_2ADDR:
    944         case OP_REM_DOUBLE_2ADDR:
    945             okay &= checkWideRegisterIndex(meth, decInsn.vA);
    946             okay &= checkWideRegisterIndex(meth, decInsn.vB);
    947             break;
    948         case OP_CONST_STRING:
    949         case OP_CONST_STRING_JUMBO:
    950             okay &= checkRegisterIndex(meth, decInsn.vA);
    951             okay &= checkStringIndex(pDvmDex, decInsn.vB);
    952             break;
    953         case OP_CONST_CLASS:
    954         case OP_CHECK_CAST:
    955             okay &= checkRegisterIndex(meth, decInsn.vA);
    956             okay &= checkTypeIndex(pDvmDex, decInsn.vB);
    957             break;
    958         case OP_INSTANCE_OF:
    959             okay &= checkRegisterIndex(meth, decInsn.vA);
    960             okay &= checkRegisterIndex(meth, decInsn.vB);
    961             okay &= checkTypeIndex(pDvmDex, decInsn.vC);
    962             break;
    963         case OP_NEW_INSTANCE:
    964             okay &= checkRegisterIndex(meth, decInsn.vA);
    965             okay &= checkNewInstance(pDvmDex, decInsn.vB);
    966             break;
    967         case OP_NEW_ARRAY:
    968             okay &= checkRegisterIndex(meth, decInsn.vA);
    969             okay &= checkRegisterIndex(meth, decInsn.vB);
    970             okay &= checkNewArray(pDvmDex, decInsn.vC);
    971             break;
    972         case OP_FILL_ARRAY_DATA:
    973             okay &= checkRegisterIndex(meth, decInsn.vA);
    974             okay &= checkArrayData(meth, codeOffset);
    975             break;
    976         case OP_PACKED_SWITCH:
    977             okay &= checkRegisterIndex(meth, decInsn.vA);
    978             okay &= checkSwitchTargets(meth, insnFlags, codeOffset);
    979             break;
    980         case OP_SPARSE_SWITCH:
    981             okay &= checkRegisterIndex(meth, decInsn.vA);
    982             okay &= checkSwitchTargets(meth, insnFlags, codeOffset);
    983             break;
    984         case OP_CMPL_FLOAT:
    985         case OP_CMPG_FLOAT:
    986         case OP_AGET:
    987         case OP_AGET_OBJECT:
    988         case OP_AGET_BOOLEAN:
    989         case OP_AGET_BYTE:
    990         case OP_AGET_CHAR:
    991         case OP_AGET_SHORT:
    992         case OP_APUT:
    993         case OP_APUT_OBJECT:
    994         case OP_APUT_BOOLEAN:
    995         case OP_APUT_BYTE:
    996         case OP_APUT_CHAR:
    997         case OP_APUT_SHORT:
    998         case OP_ADD_INT:
    999         case OP_SUB_INT:
   1000         case OP_MUL_INT:
   1001         case OP_DIV_INT:
   1002         case OP_REM_INT:
   1003         case OP_AND_INT:
   1004         case OP_OR_INT:
   1005         case OP_XOR_INT:
   1006         case OP_SHL_INT:
   1007         case OP_SHR_INT:
   1008         case OP_USHR_INT:
   1009         case OP_ADD_FLOAT:
   1010         case OP_SUB_FLOAT:
   1011         case OP_MUL_FLOAT:
   1012         case OP_DIV_FLOAT:
   1013         case OP_REM_FLOAT:
   1014             okay &= checkRegisterIndex(meth, decInsn.vA);
   1015             okay &= checkRegisterIndex(meth, decInsn.vB);
   1016             okay &= checkRegisterIndex(meth, decInsn.vC);
   1017             break;
   1018         case OP_AGET_WIDE:
   1019         case OP_APUT_WIDE:
   1020             okay &= checkWideRegisterIndex(meth, decInsn.vA);
   1021             okay &= checkRegisterIndex(meth, decInsn.vB);
   1022             okay &= checkRegisterIndex(meth, decInsn.vC);
   1023             break;
   1024         case OP_CMPL_DOUBLE:
   1025         case OP_CMPG_DOUBLE:
   1026         case OP_CMP_LONG:
   1027             okay &= checkRegisterIndex(meth, decInsn.vA);
   1028             okay &= checkWideRegisterIndex(meth, decInsn.vB);
   1029             okay &= checkWideRegisterIndex(meth, decInsn.vC);
   1030             break;
   1031         case OP_ADD_DOUBLE:
   1032         case OP_SUB_DOUBLE:
   1033         case OP_MUL_DOUBLE:
   1034         case OP_DIV_DOUBLE:
   1035         case OP_REM_DOUBLE:
   1036         case OP_ADD_LONG:
   1037         case OP_SUB_LONG:
   1038         case OP_MUL_LONG:
   1039         case OP_DIV_LONG:
   1040         case OP_REM_LONG:
   1041         case OP_AND_LONG:
   1042         case OP_OR_LONG:
   1043         case OP_XOR_LONG:
   1044             okay &= checkWideRegisterIndex(meth, decInsn.vA);
   1045             okay &= checkWideRegisterIndex(meth, decInsn.vB);
   1046             okay &= checkWideRegisterIndex(meth, decInsn.vC);
   1047             break;
   1048         case OP_SHL_LONG:
   1049         case OP_SHR_LONG:
   1050         case OP_USHR_LONG:
   1051             okay &= checkWideRegisterIndex(meth, decInsn.vA);
   1052             okay &= checkWideRegisterIndex(meth, decInsn.vB);
   1053             okay &= checkRegisterIndex(meth, decInsn.vC);
   1054             break;
   1055         case OP_IF_EQ:
   1056         case OP_IF_NE:
   1057         case OP_IF_LT:
   1058         case OP_IF_GE:
   1059         case OP_IF_GT:
   1060         case OP_IF_LE:
   1061             okay &= checkRegisterIndex(meth, decInsn.vA);
   1062             okay &= checkRegisterIndex(meth, decInsn.vB);
   1063             okay &= checkBranchTarget(meth, insnFlags, codeOffset, false);
   1064             break;
   1065         case OP_IF_EQZ:
   1066         case OP_IF_NEZ:
   1067         case OP_IF_LTZ:
   1068         case OP_IF_GEZ:
   1069         case OP_IF_GTZ:
   1070         case OP_IF_LEZ:
   1071             okay &= checkRegisterIndex(meth, decInsn.vA);
   1072             okay &= checkBranchTarget(meth, insnFlags, codeOffset, false);
   1073             break;
   1074         case OP_IGET:
   1075         case OP_IGET_OBJECT:
   1076         case OP_IGET_BOOLEAN:
   1077         case OP_IGET_BYTE:
   1078         case OP_IGET_CHAR:
   1079         case OP_IGET_SHORT:
   1080         case OP_IPUT:
   1081         case OP_IPUT_OBJECT:
   1082         case OP_IPUT_BOOLEAN:
   1083         case OP_IPUT_BYTE:
   1084         case OP_IPUT_CHAR:
   1085         case OP_IPUT_SHORT:
   1086             okay &= checkRegisterIndex(meth, decInsn.vA);
   1087             okay &= checkRegisterIndex(meth, decInsn.vB);
   1088             okay &= checkFieldIndex(pDvmDex, decInsn.vC);
   1089             break;
   1090         case OP_IGET_WIDE:
   1091         case OP_IPUT_WIDE:
   1092             okay &= checkWideRegisterIndex(meth, decInsn.vA);
   1093             okay &= checkRegisterIndex(meth, decInsn.vB);
   1094             okay &= checkFieldIndex(pDvmDex, decInsn.vC);
   1095             break;
   1096         case OP_SGET:
   1097         case OP_SGET_OBJECT:
   1098         case OP_SGET_BOOLEAN:
   1099         case OP_SGET_BYTE:
   1100         case OP_SGET_CHAR:
   1101         case OP_SGET_SHORT:
   1102         case OP_SPUT:
   1103         case OP_SPUT_OBJECT:
   1104         case OP_SPUT_BOOLEAN:
   1105         case OP_SPUT_BYTE:
   1106         case OP_SPUT_CHAR:
   1107         case OP_SPUT_SHORT:
   1108             okay &= checkRegisterIndex(meth, decInsn.vA);
   1109             okay &= checkFieldIndex(pDvmDex, decInsn.vB);
   1110             break;
   1111         case OP_SGET_WIDE:
   1112         case OP_SPUT_WIDE:
   1113             okay &= checkWideRegisterIndex(meth, decInsn.vA);
   1114             okay &= checkFieldIndex(pDvmDex, decInsn.vB);
   1115             break;
   1116         case OP_FILLED_NEW_ARRAY:
   1117             /* decoder uses B, not C, for type ref */
   1118             okay &= checkTypeIndex(pDvmDex, decInsn.vB);
   1119             okay &= checkVarargRegs(meth, &decInsn);
   1120             break;
   1121         case OP_FILLED_NEW_ARRAY_RANGE:
   1122             okay &= checkTypeIndex(pDvmDex, decInsn.vB);
   1123             okay &= checkVarargRangeRegs(meth, &decInsn);
   1124             break;
   1125         case OP_INVOKE_VIRTUAL:
   1126         case OP_INVOKE_SUPER:
   1127         case OP_INVOKE_DIRECT:
   1128         case OP_INVOKE_STATIC:
   1129         case OP_INVOKE_INTERFACE:
   1130             /* decoder uses B, not C, for type ref */
   1131             okay &= checkMethodIndex(pDvmDex, decInsn.vB);
   1132             okay &= checkVarargRegs(meth, &decInsn);
   1133             break;
   1134         case OP_INVOKE_VIRTUAL_RANGE:
   1135         case OP_INVOKE_SUPER_RANGE:
   1136         case OP_INVOKE_DIRECT_RANGE:
   1137         case OP_INVOKE_STATIC_RANGE:
   1138         case OP_INVOKE_INTERFACE_RANGE:
   1139             okay &= checkMethodIndex(pDvmDex, decInsn.vB);
   1140             okay &= checkVarargRangeRegs(meth, &decInsn);
   1141             break;
   1142 
   1143         /* verifier/optimizer output; we should never see these */
   1144         case OP_IGET_VOLATILE:
   1145         case OP_IPUT_VOLATILE:
   1146         case OP_SGET_VOLATILE:
   1147         case OP_SPUT_VOLATILE:
   1148         case OP_IGET_OBJECT_VOLATILE:
   1149         case OP_IPUT_OBJECT_VOLATILE:
   1150         case OP_SGET_OBJECT_VOLATILE:
   1151         case OP_SPUT_OBJECT_VOLATILE:
   1152         case OP_IGET_WIDE_VOLATILE:
   1153         case OP_IPUT_WIDE_VOLATILE:
   1154         case OP_SGET_WIDE_VOLATILE:
   1155         case OP_SPUT_WIDE_VOLATILE:
   1156         case OP_BREAKPOINT:
   1157         case OP_THROW_VERIFICATION_ERROR:
   1158         case OP_EXECUTE_INLINE:
   1159         case OP_EXECUTE_INLINE_RANGE:
   1160         case OP_INVOKE_OBJECT_INIT_RANGE:
   1161         case OP_RETURN_VOID_BARRIER:
   1162         case OP_IGET_QUICK:
   1163         case OP_IGET_WIDE_QUICK:
   1164         case OP_IGET_OBJECT_QUICK:
   1165         case OP_IPUT_QUICK:
   1166         case OP_IPUT_WIDE_QUICK:
   1167         case OP_IPUT_OBJECT_QUICK:
   1168         case OP_INVOKE_VIRTUAL_QUICK:
   1169         case OP_INVOKE_VIRTUAL_QUICK_RANGE:
   1170         case OP_INVOKE_SUPER_QUICK:
   1171         case OP_INVOKE_SUPER_QUICK_RANGE:
   1172         case OP_UNUSED_3E:
   1173         case OP_UNUSED_3F:
   1174         case OP_UNUSED_40:
   1175         case OP_UNUSED_41:
   1176         case OP_UNUSED_42:
   1177         case OP_UNUSED_43:
   1178         case OP_UNUSED_73:
   1179         case OP_UNUSED_79:
   1180         case OP_UNUSED_7A:
   1181         case OP_UNUSED_FF:
   1182             ALOGE("VFY: unexpected opcode %04x", decInsn.opcode);
   1183             okay = false;
   1184             break;
   1185 
   1186         /*
   1187          * DO NOT add a "default" clause here.  Without it the compiler will
   1188          * complain if an instruction is missing (which is desirable).
   1189          */
   1190         }
   1191 
   1192         if (!okay) {
   1193             LOG_VFY_METH(meth, "VFY:  rejecting opcode 0x%02x at 0x%04x",
   1194                 decInsn.opcode, codeOffset);
   1195             return false;
   1196         }
   1197 
   1198         OpcodeFlags opFlags = dexGetFlagsFromOpcode(decInsn.opcode);
   1199         if ((opFlags & VERIFY_GC_INST_MASK) != 0) {
   1200             /*
   1201              * This instruction is a GC point.  If space is a concern,
   1202              * the set of GC points could be reduced by eliminating
   1203              * foward branches.
   1204              *
   1205              * TODO: we could also scan the targets of a "switch" statement,
   1206              * and if none of them branch backward we could ignore that
   1207              * instruction as well.
   1208              */
   1209             dvmInsnSetGcPoint(insnFlags, codeOffset, true);
   1210         }
   1211 
   1212         assert(width > 0);
   1213         codeOffset += width;
   1214         insns += width;
   1215     }
   1216 
   1217     /* make sure the last instruction ends at the end of the insn area */
   1218     if (codeOffset != vdata->insnsSize) {
   1219         LOG_VFY_METH(meth,
   1220             "VFY: code did not end when expected (end at %d, count %d)",
   1221             codeOffset, vdata->insnsSize);
   1222         return false;
   1223     }
   1224 
   1225     return true;
   1226 }
   1227