Home | History | Annotate | Download | only in verifier
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "register_line.h"
     18 
     19 #include "base/stringprintf.h"
     20 #include "dex_instruction-inl.h"
     21 #include "method_verifier-inl.h"
     22 #include "register_line-inl.h"
     23 #include "reg_type-inl.h"
     24 
     25 namespace art {
     26 namespace verifier {
     27 
     28 bool RegisterLine::CheckConstructorReturn(MethodVerifier* verifier) const {
     29   if (kIsDebugBuild && this_initialized_) {
     30     // Ensure that there is no UninitializedThisReference type anymore if this_initialized_ is true.
     31     for (size_t i = 0; i < num_regs_; i++) {
     32       const RegType& type = GetRegisterType(verifier, i);
     33       CHECK(!type.IsUninitializedThisReference() &&
     34             !type.IsUnresolvedAndUninitializedThisReference())
     35           << i << ": " << type.IsUninitializedThisReference() << " in "
     36           << PrettyMethod(verifier->GetMethodReference().dex_method_index,
     37                           *verifier->GetMethodReference().dex_file);
     38     }
     39   }
     40   if (!this_initialized_) {
     41     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
     42         << "Constructor returning without calling superclass constructor";
     43   }
     44   return this_initialized_;
     45 }
     46 
     47 const RegType& RegisterLine::GetInvocationThis(MethodVerifier* verifier, const Instruction* inst,
     48                                                bool is_range, bool allow_failure) {
     49   const size_t args_count = is_range ? inst->VRegA_3rc() : inst->VRegA_35c();
     50   if (args_count < 1) {
     51     if (!allow_failure) {
     52       verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke lacks 'this'";
     53     }
     54     return verifier->GetRegTypeCache()->Conflict();
     55   }
     56   /* Get the element type of the array held in vsrc */
     57   const uint32_t this_reg = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
     58   const RegType& this_type = GetRegisterType(verifier, this_reg);
     59   if (!this_type.IsReferenceTypes()) {
     60     if (!allow_failure) {
     61       verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
     62           << "tried to get class from non-reference register v" << this_reg
     63           << " (type=" << this_type << ")";
     64     }
     65     return verifier->GetRegTypeCache()->Conflict();
     66   }
     67   return this_type;
     68 }
     69 
     70 bool RegisterLine::VerifyRegisterTypeWide(MethodVerifier* verifier, uint32_t vsrc,
     71                                           const RegType& check_type1,
     72                                           const RegType& check_type2) {
     73   DCHECK(check_type1.CheckWidePair(check_type2));
     74   // Verify the src register type against the check type refining the type of the register
     75   const RegType& src_type = GetRegisterType(verifier, vsrc);
     76   if (!check_type1.IsAssignableFrom(src_type)) {
     77     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register v" << vsrc << " has type " << src_type
     78                                << " but expected " << check_type1;
     79     return false;
     80   }
     81   const RegType& src_type_h = GetRegisterType(verifier, vsrc + 1);
     82   if (!src_type.CheckWidePair(src_type_h)) {
     83     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register v" << vsrc << " has type "
     84         << src_type << "/" << src_type_h;
     85     return false;
     86   }
     87   // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less
     88   // precise than the subtype in vsrc so leave it for reference types. For primitive types
     89   // if they are a defined type then they are as precise as we can get, however, for constant
     90   // types we may wish to refine them. Unfortunately constant propagation has rendered this useless.
     91   return true;
     92 }
     93 
     94 void RegisterLine::MarkRefsAsInitialized(MethodVerifier* verifier, const RegType& uninit_type) {
     95   DCHECK(uninit_type.IsUninitializedTypes());
     96   const RegType& init_type = verifier->GetRegTypeCache()->FromUninitialized(uninit_type);
     97   size_t changed = 0;
     98   for (uint32_t i = 0; i < num_regs_; i++) {
     99     if (GetRegisterType(verifier, i).Equals(uninit_type)) {
    100       line_[i] = init_type.GetId();
    101       changed++;
    102     }
    103   }
    104   // Is this initializing "this"?
    105   if (uninit_type.IsUninitializedThisReference() ||
    106       uninit_type.IsUnresolvedAndUninitializedThisReference()) {
    107     this_initialized_ = true;
    108   }
    109   DCHECK_GT(changed, 0u);
    110 }
    111 
    112 void RegisterLine::MarkAllRegistersAsConflicts(MethodVerifier* verifier) {
    113   uint16_t conflict_type_id = verifier->GetRegTypeCache()->Conflict().GetId();
    114   for (uint32_t i = 0; i < num_regs_; i++) {
    115     line_[i] = conflict_type_id;
    116   }
    117 }
    118 
    119 void RegisterLine::MarkAllRegistersAsConflictsExcept(MethodVerifier* verifier, uint32_t vsrc) {
    120   uint16_t conflict_type_id = verifier->GetRegTypeCache()->Conflict().GetId();
    121   for (uint32_t i = 0; i < num_regs_; i++) {
    122     if (i != vsrc) {
    123       line_[i] = conflict_type_id;
    124     }
    125   }
    126 }
    127 
    128 void RegisterLine::MarkAllRegistersAsConflictsExceptWide(MethodVerifier* verifier, uint32_t vsrc) {
    129   uint16_t conflict_type_id = verifier->GetRegTypeCache()->Conflict().GetId();
    130   for (uint32_t i = 0; i < num_regs_; i++) {
    131     if ((i != vsrc) && (i != (vsrc + 1))) {
    132       line_[i] = conflict_type_id;
    133     }
    134   }
    135 }
    136 
    137 std::string RegisterLine::Dump(MethodVerifier* verifier) const {
    138   std::string result;
    139   for (size_t i = 0; i < num_regs_; i++) {
    140     result += StringPrintf("%zd:[", i);
    141     result += GetRegisterType(verifier, i).Dump();
    142     result += "],";
    143   }
    144   for (const auto& monitor : monitors_) {
    145     result += StringPrintf("{%d},", monitor);
    146   }
    147   for (auto& pairs : reg_to_lock_depths_) {
    148     result += StringPrintf("<%d -> %x>", pairs.first, pairs.second);
    149   }
    150   return result;
    151 }
    152 
    153 void RegisterLine::MarkUninitRefsAsInvalid(MethodVerifier* verifier, const RegType& uninit_type) {
    154   for (size_t i = 0; i < num_regs_; i++) {
    155     if (GetRegisterType(verifier, i).Equals(uninit_type)) {
    156       line_[i] = verifier->GetRegTypeCache()->Conflict().GetId();
    157       ClearAllRegToLockDepths(i);
    158     }
    159   }
    160 }
    161 
    162 void RegisterLine::CopyResultRegister1(MethodVerifier* verifier, uint32_t vdst, bool is_reference) {
    163   const RegType& type = verifier->GetRegTypeCache()->GetFromId(result_[0]);
    164   if ((!is_reference && !type.IsCategory1Types()) ||
    165       (is_reference && !type.IsReferenceTypes())) {
    166     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
    167         << "copyRes1 v" << vdst << "<- result0"  << " type=" << type;
    168   } else {
    169     DCHECK(verifier->GetRegTypeCache()->GetFromId(result_[1]).IsUndefined());
    170     SetRegisterType<LockOp::kClear>(verifier, vdst, type);
    171     result_[0] = verifier->GetRegTypeCache()->Undefined().GetId();
    172   }
    173 }
    174 
    175 /*
    176  * Implement "move-result-wide". Copy the category-2 value from the result
    177  * register to another register, and reset the result register.
    178  */
    179 void RegisterLine::CopyResultRegister2(MethodVerifier* verifier, uint32_t vdst) {
    180   const RegType& type_l = verifier->GetRegTypeCache()->GetFromId(result_[0]);
    181   const RegType& type_h = verifier->GetRegTypeCache()->GetFromId(result_[1]);
    182   if (!type_l.IsCategory2Types()) {
    183     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
    184         << "copyRes2 v" << vdst << "<- result0"  << " type=" << type_l;
    185   } else {
    186     DCHECK(type_l.CheckWidePair(type_h));  // Set should never allow this case
    187     SetRegisterTypeWide(verifier, vdst, type_l, type_h);  // also sets the high
    188     result_[0] = verifier->GetRegTypeCache()->Undefined().GetId();
    189     result_[1] = verifier->GetRegTypeCache()->Undefined().GetId();
    190   }
    191 }
    192 
    193 void RegisterLine::CheckUnaryOp(MethodVerifier* verifier, const Instruction* inst,
    194                                 const RegType& dst_type, const RegType& src_type) {
    195   if (VerifyRegisterType(verifier, inst->VRegB_12x(), src_type)) {
    196     SetRegisterType<LockOp::kClear>(verifier, inst->VRegA_12x(), dst_type);
    197   }
    198 }
    199 
    200 void RegisterLine::CheckUnaryOpWide(MethodVerifier* verifier, const Instruction* inst,
    201                                     const RegType& dst_type1, const RegType& dst_type2,
    202                                     const RegType& src_type1, const RegType& src_type2) {
    203   if (VerifyRegisterTypeWide(verifier, inst->VRegB_12x(), src_type1, src_type2)) {
    204     SetRegisterTypeWide(verifier, inst->VRegA_12x(), dst_type1, dst_type2);
    205   }
    206 }
    207 
    208 void RegisterLine::CheckUnaryOpToWide(MethodVerifier* verifier, const Instruction* inst,
    209                                       const RegType& dst_type1, const RegType& dst_type2,
    210                                       const RegType& src_type) {
    211   if (VerifyRegisterType(verifier, inst->VRegB_12x(), src_type)) {
    212     SetRegisterTypeWide(verifier, inst->VRegA_12x(), dst_type1, dst_type2);
    213   }
    214 }
    215 
    216 void RegisterLine::CheckUnaryOpFromWide(MethodVerifier* verifier, const Instruction* inst,
    217                                         const RegType& dst_type,
    218                                         const RegType& src_type1, const RegType& src_type2) {
    219   if (VerifyRegisterTypeWide(verifier, inst->VRegB_12x(), src_type1, src_type2)) {
    220     SetRegisterType<LockOp::kClear>(verifier, inst->VRegA_12x(), dst_type);
    221   }
    222 }
    223 
    224 void RegisterLine::CheckBinaryOp(MethodVerifier* verifier, const Instruction* inst,
    225                                  const RegType& dst_type,
    226                                  const RegType& src_type1, const RegType& src_type2,
    227                                  bool check_boolean_op) {
    228   const uint32_t vregB = inst->VRegB_23x();
    229   const uint32_t vregC = inst->VRegC_23x();
    230   if (VerifyRegisterType(verifier, vregB, src_type1) &&
    231       VerifyRegisterType(verifier, vregC, src_type2)) {
    232     if (check_boolean_op) {
    233       DCHECK(dst_type.IsInteger());
    234       if (GetRegisterType(verifier, vregB).IsBooleanTypes() &&
    235           GetRegisterType(verifier, vregC).IsBooleanTypes()) {
    236         SetRegisterType<LockOp::kClear>(verifier,
    237                                         inst->VRegA_23x(),
    238                                         verifier->GetRegTypeCache()->Boolean());
    239         return;
    240       }
    241     }
    242     SetRegisterType<LockOp::kClear>(verifier, inst->VRegA_23x(), dst_type);
    243   }
    244 }
    245 
    246 void RegisterLine::CheckBinaryOpWide(MethodVerifier* verifier, const Instruction* inst,
    247                                      const RegType& dst_type1, const RegType& dst_type2,
    248                                      const RegType& src_type1_1, const RegType& src_type1_2,
    249                                      const RegType& src_type2_1, const RegType& src_type2_2) {
    250   if (VerifyRegisterTypeWide(verifier, inst->VRegB_23x(), src_type1_1, src_type1_2) &&
    251       VerifyRegisterTypeWide(verifier, inst->VRegC_23x(), src_type2_1, src_type2_2)) {
    252     SetRegisterTypeWide(verifier, inst->VRegA_23x(), dst_type1, dst_type2);
    253   }
    254 }
    255 
    256 void RegisterLine::CheckBinaryOpWideShift(MethodVerifier* verifier, const Instruction* inst,
    257                                           const RegType& long_lo_type, const RegType& long_hi_type,
    258                                           const RegType& int_type) {
    259   if (VerifyRegisterTypeWide(verifier, inst->VRegB_23x(), long_lo_type, long_hi_type) &&
    260       VerifyRegisterType(verifier, inst->VRegC_23x(), int_type)) {
    261     SetRegisterTypeWide(verifier, inst->VRegA_23x(), long_lo_type, long_hi_type);
    262   }
    263 }
    264 
    265 void RegisterLine::CheckBinaryOp2addr(MethodVerifier* verifier, const Instruction* inst,
    266                                       const RegType& dst_type, const RegType& src_type1,
    267                                       const RegType& src_type2, bool check_boolean_op) {
    268   const uint32_t vregA = inst->VRegA_12x();
    269   const uint32_t vregB = inst->VRegB_12x();
    270   if (VerifyRegisterType(verifier, vregA, src_type1) &&
    271       VerifyRegisterType(verifier, vregB, src_type2)) {
    272     if (check_boolean_op) {
    273       DCHECK(dst_type.IsInteger());
    274       if (GetRegisterType(verifier, vregA).IsBooleanTypes() &&
    275           GetRegisterType(verifier, vregB).IsBooleanTypes()) {
    276         SetRegisterType<LockOp::kClear>(verifier,
    277                                         vregA,
    278                                         verifier->GetRegTypeCache()->Boolean());
    279         return;
    280       }
    281     }
    282     SetRegisterType<LockOp::kClear>(verifier, vregA, dst_type);
    283   }
    284 }
    285 
    286 void RegisterLine::CheckBinaryOp2addrWide(MethodVerifier* verifier, const Instruction* inst,
    287                                           const RegType& dst_type1, const RegType& dst_type2,
    288                                           const RegType& src_type1_1, const RegType& src_type1_2,
    289                                           const RegType& src_type2_1, const RegType& src_type2_2) {
    290   const uint32_t vregA = inst->VRegA_12x();
    291   const uint32_t vregB = inst->VRegB_12x();
    292   if (VerifyRegisterTypeWide(verifier, vregA, src_type1_1, src_type1_2) &&
    293       VerifyRegisterTypeWide(verifier, vregB, src_type2_1, src_type2_2)) {
    294     SetRegisterTypeWide(verifier, vregA, dst_type1, dst_type2);
    295   }
    296 }
    297 
    298 void RegisterLine::CheckBinaryOp2addrWideShift(MethodVerifier* verifier, const Instruction* inst,
    299                                                const RegType& long_lo_type, const RegType& long_hi_type,
    300                                                const RegType& int_type) {
    301   const uint32_t vregA = inst->VRegA_12x();
    302   const uint32_t vregB = inst->VRegB_12x();
    303   if (VerifyRegisterTypeWide(verifier, vregA, long_lo_type, long_hi_type) &&
    304       VerifyRegisterType(verifier, vregB, int_type)) {
    305     SetRegisterTypeWide(verifier, vregA, long_lo_type, long_hi_type);
    306   }
    307 }
    308 
    309 void RegisterLine::CheckLiteralOp(MethodVerifier* verifier, const Instruction* inst,
    310                                   const RegType& dst_type, const RegType& src_type,
    311                                   bool check_boolean_op, bool is_lit16) {
    312   const uint32_t vregA = is_lit16 ? inst->VRegA_22s() : inst->VRegA_22b();
    313   const uint32_t vregB = is_lit16 ? inst->VRegB_22s() : inst->VRegB_22b();
    314   if (VerifyRegisterType(verifier, vregB, src_type)) {
    315     if (check_boolean_op) {
    316       DCHECK(dst_type.IsInteger());
    317       /* check vB with the call, then check the constant manually */
    318       const uint32_t val = is_lit16 ? inst->VRegC_22s() : inst->VRegC_22b();
    319       if (GetRegisterType(verifier, vregB).IsBooleanTypes() && (val == 0 || val == 1)) {
    320         SetRegisterType<LockOp::kClear>(verifier,
    321                                         vregA,
    322                                         verifier->GetRegTypeCache()->Boolean());
    323         return;
    324       }
    325     }
    326     SetRegisterType<LockOp::kClear>(verifier, vregA, dst_type);
    327   }
    328 }
    329 
    330 static constexpr uint32_t kVirtualNullRegister = std::numeric_limits<uint32_t>::max();
    331 
    332 void RegisterLine::PushMonitor(MethodVerifier* verifier, uint32_t reg_idx, int32_t insn_idx) {
    333   const RegType& reg_type = GetRegisterType(verifier, reg_idx);
    334   if (!reg_type.IsReferenceTypes()) {
    335     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-enter on non-object ("
    336         << reg_type << ")";
    337   } else if (monitors_.size() >= 32) {
    338     verifier->Fail(VERIFY_ERROR_LOCKING);
    339     if (kDumpLockFailures) {
    340       VLOG(verifier) << "monitor-enter stack overflow while verifying "
    341                      << PrettyMethod(verifier->GetMethodReference().dex_method_index,
    342                                      *verifier->GetMethodReference().dex_file);
    343     }
    344   } else {
    345     if (SetRegToLockDepth(reg_idx, monitors_.size())) {
    346       // Null literals can establish aliases that we can't easily track. As such, handle the zero
    347       // case as the 2^32-1 register (which isn't available in dex bytecode).
    348       if (reg_type.IsZero()) {
    349         SetRegToLockDepth(kVirtualNullRegister, monitors_.size());
    350       }
    351 
    352       monitors_.push_back(insn_idx);
    353     } else {
    354       verifier->Fail(VERIFY_ERROR_LOCKING);
    355       if (kDumpLockFailures) {
    356         VLOG(verifier) << "unexpected monitor-enter on register v" <<  reg_idx << " in "
    357                        << PrettyMethod(verifier->GetMethodReference().dex_method_index,
    358                                        *verifier->GetMethodReference().dex_file);
    359       }
    360     }
    361   }
    362 }
    363 
    364 void RegisterLine::PopMonitor(MethodVerifier* verifier, uint32_t reg_idx) {
    365   const RegType& reg_type = GetRegisterType(verifier, reg_idx);
    366   if (!reg_type.IsReferenceTypes()) {
    367     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-exit on non-object (" << reg_type << ")";
    368   } else if (monitors_.empty()) {
    369     verifier->Fail(VERIFY_ERROR_LOCKING);
    370     if (kDumpLockFailures) {
    371       VLOG(verifier) << "monitor-exit stack underflow while verifying "
    372                      << PrettyMethod(verifier->GetMethodReference().dex_method_index,
    373                                      *verifier->GetMethodReference().dex_file);
    374     }
    375   } else {
    376     monitors_.pop_back();
    377 
    378     bool success = IsSetLockDepth(reg_idx, monitors_.size());
    379 
    380     if (!success && reg_type.IsZero()) {
    381       // Null literals can establish aliases that we can't easily track. As such, handle the zero
    382       // case as the 2^32-1 register (which isn't available in dex bytecode).
    383       success = IsSetLockDepth(kVirtualNullRegister, monitors_.size());
    384       if (success) {
    385         reg_idx = kVirtualNullRegister;
    386       }
    387     }
    388 
    389     if (!success) {
    390       verifier->Fail(VERIFY_ERROR_LOCKING);
    391       if (kDumpLockFailures) {
    392         VLOG(verifier) << "monitor-exit not unlocking the top of the monitor stack while verifying "
    393                        << PrettyMethod(verifier->GetMethodReference().dex_method_index,
    394                                        *verifier->GetMethodReference().dex_file);
    395       }
    396     } else {
    397       // Record the register was unlocked. This clears all aliases, thus it will also clear the
    398       // null lock, if necessary.
    399       ClearRegToLockDepth(reg_idx, monitors_.size());
    400     }
    401   }
    402 }
    403 
    404 bool FindLockAliasedRegister(uint32_t src,
    405                              const RegisterLine::RegToLockDepthsMap& src_map,
    406                              const RegisterLine::RegToLockDepthsMap& search_map) {
    407   auto it = src_map.find(src);
    408   if (it == src_map.end()) {
    409     // "Not locked" is trivially aliased.
    410     return true;
    411   }
    412   uint32_t src_lock_levels = it->second;
    413   if (src_lock_levels == 0) {
    414     // "Not locked" is trivially aliased.
    415     return true;
    416   }
    417 
    418   // Scan the map for the same value.
    419   for (const std::pair<uint32_t, uint32_t>& pair : search_map) {
    420     if (pair.first != src && pair.second == src_lock_levels) {
    421       return true;
    422     }
    423   }
    424 
    425   // Nothing found, no alias.
    426   return false;
    427 }
    428 
    429 bool RegisterLine::MergeRegisters(MethodVerifier* verifier, const RegisterLine* incoming_line) {
    430   bool changed = false;
    431   DCHECK(incoming_line != nullptr);
    432   for (size_t idx = 0; idx < num_regs_; idx++) {
    433     if (line_[idx] != incoming_line->line_[idx]) {
    434       const RegType& incoming_reg_type = incoming_line->GetRegisterType(verifier, idx);
    435       const RegType& cur_type = GetRegisterType(verifier, idx);
    436       const RegType& new_type = cur_type.Merge(incoming_reg_type, verifier->GetRegTypeCache());
    437       changed = changed || !cur_type.Equals(new_type);
    438       line_[idx] = new_type.GetId();
    439     }
    440   }
    441   if (monitors_.size() > 0 || incoming_line->monitors_.size() > 0) {
    442     if (monitors_.size() != incoming_line->monitors_.size()) {
    443       verifier->Fail(VERIFY_ERROR_LOCKING);
    444       if (kDumpLockFailures) {
    445         VLOG(verifier) << "mismatched stack depths (depth=" << MonitorStackDepth()
    446                        << ", incoming depth=" << incoming_line->MonitorStackDepth() << ") in "
    447                        << PrettyMethod(verifier->GetMethodReference().dex_method_index,
    448                                        *verifier->GetMethodReference().dex_file);
    449       }
    450     } else if (reg_to_lock_depths_ != incoming_line->reg_to_lock_depths_) {
    451       for (uint32_t idx = 0; idx < num_regs_; idx++) {
    452         size_t depths = reg_to_lock_depths_.count(idx);
    453         size_t incoming_depths = incoming_line->reg_to_lock_depths_.count(idx);
    454         if (depths != incoming_depths) {
    455           // Stack levels aren't matching. This is potentially bad, as we don't do a
    456           // flow-sensitive analysis.
    457           // However, this could be an alias of something locked in one path, and the alias was
    458           // destroyed in another path. It is fine to drop this as long as there's another alias
    459           // for the lock around. The last vanishing alias will then report that things would be
    460           // left unlocked. We need to check for aliases for both lock levels.
    461           //
    462           // Example (lock status in curly braces as pair of register and lock leels):
    463           //
    464           //                            lock v1 {v1=1}
    465           //                        |                    |
    466           //              v0 = v1 {v0=1, v1=1}       v0 = v2 {v1=1}
    467           //                        |                    |
    468           //                                 {v1=1}
    469           //                                         // Dropping v0, as the status can't be merged
    470           //                                         // but the lock info ("locked at depth 1" and)
    471           //                                         // "not locked at all") is available.
    472           if (!FindLockAliasedRegister(idx,
    473                                        reg_to_lock_depths_,
    474                                        reg_to_lock_depths_) ||
    475               !FindLockAliasedRegister(idx,
    476                                        incoming_line->reg_to_lock_depths_,
    477                                        reg_to_lock_depths_)) {
    478             verifier->Fail(VERIFY_ERROR_LOCKING);
    479             if (kDumpLockFailures) {
    480               VLOG(verifier) << "mismatched stack depths for register v" << idx
    481                              << ": " << depths  << " != " << incoming_depths << " in "
    482                              << PrettyMethod(verifier->GetMethodReference().dex_method_index,
    483                                              *verifier->GetMethodReference().dex_file);
    484             }
    485             break;
    486           }
    487           // We found aliases, set this to zero.
    488           reg_to_lock_depths_.erase(idx);
    489         } else if (depths > 0) {
    490           // Check whether they're actually the same levels.
    491           uint32_t locked_levels = reg_to_lock_depths_.find(idx)->second;
    492           uint32_t incoming_locked_levels = incoming_line->reg_to_lock_depths_.find(idx)->second;
    493           if (locked_levels != incoming_locked_levels) {
    494             // Lock levels aren't matching. This is potentially bad, as we don't do a
    495             // flow-sensitive analysis.
    496             // However, this could be an alias of something locked in one path, and the alias was
    497             // destroyed in another path. It is fine to drop this as long as there's another alias
    498             // for the lock around. The last vanishing alias will then report that things would be
    499             // left unlocked. We need to check for aliases for both lock levels.
    500             //
    501             // Example (lock status in curly braces as pair of register and lock leels):
    502             //
    503             //                          lock v1 {v1=1}
    504             //                          lock v2 {v1=1, v2=2}
    505             //                        |                      |
    506             //         v0 = v1 {v0=1, v1=1, v2=2}  v0 = v2 {v0=2, v1=1, v2=2}
    507             //                        |                      |
    508             //                             {v1=1, v2=2}
    509             //                                           // Dropping v0, as the status can't be
    510             //                                           // merged but the lock info ("locked at
    511             //                                           // depth 1" and "locked at depth 2") is
    512             //                                           // available.
    513             if (!FindLockAliasedRegister(idx,
    514                                          reg_to_lock_depths_,
    515                                          reg_to_lock_depths_) ||
    516                 !FindLockAliasedRegister(idx,
    517                                          incoming_line->reg_to_lock_depths_,
    518                                          reg_to_lock_depths_)) {
    519               // No aliases for both current and incoming, we'll lose information.
    520               verifier->Fail(VERIFY_ERROR_LOCKING);
    521               if (kDumpLockFailures) {
    522                 VLOG(verifier) << "mismatched lock levels for register v" << idx << ": "
    523                                << std::hex << locked_levels << std::dec  << " != "
    524                                << std::hex << incoming_locked_levels << std::dec << " in "
    525                                << PrettyMethod(verifier->GetMethodReference().dex_method_index,
    526                                                *verifier->GetMethodReference().dex_file);
    527               }
    528               break;
    529             }
    530             // We found aliases, set this to zero.
    531             reg_to_lock_depths_.erase(idx);
    532           }
    533         }
    534       }
    535     }
    536   }
    537 
    538   // Check whether "this" was initialized in both paths.
    539   if (this_initialized_ && !incoming_line->this_initialized_) {
    540     this_initialized_ = false;
    541     changed = true;
    542   }
    543   return changed;
    544 }
    545 
    546 }  // namespace verifier
    547 }  // namespace art
    548