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