summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/verifier/method_verifier.cc311
1 files changed, 227 insertions, 84 deletions
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 06b95428cc..05fb9b39b6 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -957,18 +957,21 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
* "dst_type" is stored into vA, and "src_type" is verified against vB.
*/
ALWAYS_INLINE
- void CheckUnaryOp(const Instruction* inst,
+ bool CheckUnaryOp(const Instruction* inst,
uint16_t inst_data,
RegType::Kind dst_kind,
RegType::Kind src_kind)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (VerifyRegisterType(inst->VRegB_12x(inst_data), src_kind)) {
work_line_->SetRegisterType(inst->VRegA_12x(inst_data), dst_kind);
+ return true;
+ } else {
+ return false;
}
}
ALWAYS_INLINE
- void CheckUnaryOpWide(const Instruction* inst,
+ bool CheckUnaryOpWide(const Instruction* inst,
uint16_t inst_data,
RegType::Kind dst_kind,
RegType::Kind src_kind)
@@ -976,11 +979,14 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
if (VerifyRegisterTypeWide(inst->VRegB_12x(inst_data), src_kind)) {
work_line_->SetRegisterTypeWide(
inst->VRegA_12x(inst_data), dst_kind, RegType::ToHighHalf(dst_kind));
+ return true;
+ } else {
+ return false;
}
}
ALWAYS_INLINE
- void CheckUnaryOpToWide(const Instruction* inst,
+ bool CheckUnaryOpToWide(const Instruction* inst,
uint16_t inst_data,
RegType::Kind dst_kind,
RegType::Kind src_kind)
@@ -988,17 +994,23 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
if (VerifyRegisterType(inst->VRegB_12x(inst_data), src_kind)) {
work_line_->SetRegisterTypeWide(
inst->VRegA_12x(inst_data), dst_kind, RegType::ToHighHalf(dst_kind));
+ return true;
+ } else {
+ return false;
}
}
ALWAYS_INLINE
- void CheckUnaryOpFromWide(const Instruction* inst,
+ bool CheckUnaryOpFromWide(const Instruction* inst,
uint16_t inst_data,
RegType::Kind dst_kind,
RegType::Kind src_kind)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (VerifyRegisterTypeWide(inst->VRegB_12x(inst_data), src_kind)) {
work_line_->SetRegisterType(inst->VRegA_12x(inst_data), dst_kind);
+ return true;
+ } else {
+ return false;
}
}
@@ -1008,7 +1020,7 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
* against vB/vC.
*/
ALWAYS_INLINE
- void CheckBinaryOp(const Instruction* inst,
+ bool CheckBinaryOp(const Instruction* inst,
uint16_t inst_data,
RegType::Kind dst_kind,
RegType::Kind src_kind1,
@@ -1026,16 +1038,18 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
RegTypeCache::RegKindForId(work_line_->GetRegisterTypeId(vregB))) &&
RegType::IsBooleanTypes(
RegTypeCache::RegKindForId(work_line_->GetRegisterTypeId(vregC)))) {
- work_line_->SetRegisterType(vregA, RegType::Kind::kBoolean);
- return;
+ dst_kind = RegType::Kind::kBoolean;
}
}
work_line_->SetRegisterType(vregA, dst_kind);
+ return true;
+ } else {
+ return false;
}
}
ALWAYS_INLINE
- void CheckBinaryOpWide(const Instruction* inst,
+ bool CheckBinaryOpWide(const Instruction* inst,
uint16_t inst_data,
RegType::Kind dst_kind,
RegType::Kind src_kind1,
@@ -1045,11 +1059,14 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
VerifyRegisterTypeWide(inst->VRegC_23x(), src_kind2)) {
work_line_->SetRegisterTypeWide(
inst->VRegA_23x(inst_data), dst_kind, RegType::ToHighHalf(dst_kind));
+ return true;
+ } else {
+ return false;
}
}
ALWAYS_INLINE
- void CheckBinaryOpWideCmp(const Instruction* inst,
+ bool CheckBinaryOpWideCmp(const Instruction* inst,
uint16_t inst_data,
RegType::Kind dst_kind,
RegType::Kind src_kind1,
@@ -1058,11 +1075,14 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
if (VerifyRegisterTypeWide(inst->VRegB_23x(), src_kind1) &&
VerifyRegisterTypeWide(inst->VRegC_23x(), src_kind2)) {
work_line_->SetRegisterType(inst->VRegA_23x(inst_data), dst_kind);
+ return true;
+ } else {
+ return false;
}
}
ALWAYS_INLINE
- void CheckBinaryOpWideShift(const Instruction* inst,
+ bool CheckBinaryOpWideShift(const Instruction* inst,
uint16_t inst_data,
RegType::Kind long_lo_kind,
RegType::Kind int_kind)
@@ -1071,6 +1091,9 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
VerifyRegisterType(inst->VRegC_23x(), int_kind)) {
RegType::Kind long_hi_kind = RegType::ToHighHalf(long_lo_kind);
work_line_->SetRegisterTypeWide(inst->VRegA_23x(inst_data), long_lo_kind, long_hi_kind);
+ return true;
+ } else {
+ return false;
}
}
@@ -1079,7 +1102,7 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
* are verified against vA/vB, then "dst_type" is stored into vA.
*/
ALWAYS_INLINE
- void CheckBinaryOp2addr(const Instruction* inst,
+ bool CheckBinaryOp2addr(const Instruction* inst,
uint16_t inst_data,
RegType::Kind dst_kind,
RegType::Kind src_kind1,
@@ -1096,16 +1119,18 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
RegTypeCache::RegKindForId(work_line_->GetRegisterTypeId(vregA))) &&
RegType::IsBooleanTypes(
RegTypeCache::RegKindForId(work_line_->GetRegisterTypeId(vregB)))) {
- work_line_->SetRegisterType(vregA, RegType::Kind::kBoolean);
- return;
+ dst_kind = RegType::Kind::kBoolean;
}
}
work_line_->SetRegisterType(vregA, dst_kind);
+ return true;
+ } else {
+ return false;
}
}
ALWAYS_INLINE
- void CheckBinaryOp2addrWide(const Instruction* inst,
+ bool CheckBinaryOp2addrWide(const Instruction* inst,
uint16_t inst_data,
RegType::Kind dst_kind,
RegType::Kind src_kind1,
@@ -1116,11 +1141,14 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
if (VerifyRegisterTypeWide(vregA, src_kind1) &&
VerifyRegisterTypeWide(vregB, src_kind2)) {
work_line_->SetRegisterTypeWide(vregA, dst_kind, RegType::ToHighHalf(dst_kind));
+ return true;
+ } else {
+ return false;
}
}
ALWAYS_INLINE
- void CheckBinaryOp2addrWideShift(const Instruction* inst,
+ bool CheckBinaryOp2addrWideShift(const Instruction* inst,
uint16_t inst_data,
RegType::Kind long_lo_kind,
RegType::Kind int_kind)
@@ -1131,6 +1159,9 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
VerifyRegisterType(vregB, int_kind)) {
RegType::Kind long_hi_kind = RegType::ToHighHalf(long_lo_kind);
work_line_->SetRegisterTypeWide(vregA, long_lo_kind, long_hi_kind);
+ return true;
+ } else {
+ return false;
}
}
@@ -1140,27 +1171,29 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier {
*
* If "check_boolean_op" is set, we use the constant value in vC.
*/
+ template <bool kIsLit16>
ALWAYS_INLINE
- void CheckLiteralOp(const Instruction* inst,
+ bool CheckLiteralOp(const Instruction* inst,
uint16_t inst_data,
RegType::Kind dst_kind,
RegType::Kind src_kind,
- bool check_boolean_op,
- bool is_lit16)
+ bool check_boolean_op)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const uint32_t vregA = is_lit16 ? inst->VRegA_22s(inst_data) : inst->VRegA_22b(inst_data);
- const uint32_t vregB = is_lit16 ? inst->VRegB_22s(inst_data) : inst->VRegB_22b();
+ const uint32_t vregA = kIsLit16 ? inst->VRegA_22s(inst_data) : inst->VRegA_22b(inst_data);
+ const uint32_t vregB = kIsLit16 ? inst->VRegB_22s(inst_data) : inst->VRegB_22b();
if (VerifyRegisterType(vregB, src_kind)) {
if (check_boolean_op) {
DCHECK_EQ(dst_kind, RegType::Kind::kInteger);
/* check vB with the call, then check the constant manually */
- const uint32_t val = is_lit16 ? inst->VRegC_22s() : inst->VRegC_22b();
+ const uint32_t val = kIsLit16 ? inst->VRegC_22s() : inst->VRegC_22b();
if (work_line_->GetRegisterType(this, vregB).IsBooleanTypes() && (val == 0 || val == 1)) {
- work_line_->SetRegisterType(vregA, RegType::Kind::kBoolean);
- return;
+ dst_kind = RegType::Kind::kBoolean;
}
}
work_line_->SetRegisterType(vregA, dst_kind);
+ return true;
+ } else {
+ return false;
}
}
@@ -2626,6 +2659,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
*/
if (inst->VRegA_10x(inst_data) != 0) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "encountered data table in instruction stream";
+ return false;
}
break;
@@ -2699,6 +2733,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
if (!IsInstanceConstructor() || work_line_->CheckConstructorReturn(this)) {
if (!GetMethodReturnType().IsConflict()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-void not expected";
+ return false;
}
}
break;
@@ -2709,6 +2744,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
if (!return_type.IsCategory1Types()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected non-category 1 return type "
<< return_type;
+ return false;
} else {
// Compilers may generate synthetic functions that write byte values into boolean fields.
// Also, it may use integer values for boolean, byte, short, and character return types.
@@ -2732,6 +2768,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
const RegType& return_type = GetMethodReturnType();
if (!return_type.IsCategory2Types()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-wide not expected";
+ return false;
} else {
/* check the register contents */
const uint32_t vregA = inst->VRegA_11x(inst_data);
@@ -2747,6 +2784,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
const RegType& return_type = GetMethodReturnType();
if (!return_type.IsReferenceTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-object not expected";
+ return false;
} else {
/* return_type is the *expected* return type, not register value */
DCHECK(!return_type.IsZeroOrNull());
@@ -2757,15 +2795,19 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
// reference in vAA is an instance of the "return_type."
if (reg_type.IsUndefined()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning undefined register";
+ return false;
} else if (reg_type.IsConflict()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning register with conflict";
+ return false;
} else if (reg_type.IsUninitializedTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning uninitialized object '"
<< reg_type << "'";
+ return false;
} else if (!reg_type.IsReferenceTypes()) {
// We really do expect a reference here.
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-object returns a non-reference type "
<< reg_type;
+ return false;
} else if (!IsAssignableFrom(return_type, reg_type)) {
if (reg_type.IsUnresolvedTypes() || return_type.IsUnresolvedTypes()) {
Fail(VERIFY_ERROR_UNRESOLVED_TYPE_CHECK)
@@ -2773,6 +2815,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
} else {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning '" << reg_type
<< "', but expected from declaration '" << return_type << "'";
+ return false;
}
}
}
@@ -2951,7 +2994,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "using primitive type "
<< dex_file_->GetTypeDescriptorView(type_idx) << " in instanceof in "
<< GetDeclaringClass();
- break;
+ return false;
}
DCHECK_NE(failures_.size(), 0U);
@@ -2966,11 +3009,14 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
const RegType& orig_type = work_line_->GetRegisterType(this, orig_type_reg);
if (!res_type.IsNonZeroReferenceTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << opcode << " on unexpected class " << res_type;
+ return false;
} else if (!orig_type.IsReferenceTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << opcode << " on non-reference in v" << orig_type_reg;
+ return false;
} else if (orig_type.IsUninitializedTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << opcode << " on uninitialized reference in v"
<< orig_type_reg;
+ return false;
} else {
if (is_checkcast) {
work_line_->SetRegisterType<LockOp::kKeep>(inst->VRegA_21c(inst_data), res_type);
@@ -2986,11 +3032,13 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
if (!res_type.IsArrayTypes() && !res_type.IsZeroOrNull()) {
// ie not an array or null
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type;
+ return false;
} else {
work_line_->SetRegisterType(inst->VRegA_12x(inst_data), kInteger);
}
} else {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type;
+ return false;
}
break;
}
@@ -3029,26 +3077,37 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
break;
case Instruction::CMPL_FLOAT:
case Instruction::CMPG_FLOAT:
- CheckBinaryOp(inst, inst_data, kInteger, kFloat, kFloat, /*check_boolean_op=*/ false);
+ if (!CheckBinaryOp(inst, inst_data, kInteger, kFloat, kFloat, /*check_boolean_op=*/ false)) {
+ return false;
+ }
break;
case Instruction::CMPL_DOUBLE:
case Instruction::CMPG_DOUBLE:
- CheckBinaryOpWideCmp(inst, inst_data, kInteger, kDoubleLo, kDoubleLo);
+ if (!CheckBinaryOpWideCmp(inst, inst_data, kInteger, kDoubleLo, kDoubleLo)) {
+ return false;
+ }
break;
case Instruction::CMP_LONG:
- CheckBinaryOpWideCmp(inst, inst_data, kInteger, kLongLo, kLongLo);
+ if (!CheckBinaryOpWideCmp(inst, inst_data, kInteger, kLongLo, kLongLo)) {
+ return false;
+ }
break;
case Instruction::THROW: {
const RegType& res_type = work_line_->GetRegisterType(this, inst->VRegA_11x(inst_data));
if (!IsAssignableFrom(reg_types_.JavaLangThrowable(), res_type)) {
if (res_type.IsUninitializedTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "thrown exception not initialized";
+ return false;
} else if (!res_type.IsReferenceTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "thrown value of non-reference type " << res_type;
+ return false;
} else {
- Fail(res_type.IsUnresolvedTypes()
- ? VERIFY_ERROR_UNRESOLVED_TYPE_CHECK : VERIFY_ERROR_BAD_CLASS_HARD)
+ bool unresolved = res_type.IsUnresolvedTypes();
+ Fail(unresolved ? VERIFY_ERROR_UNRESOLVED_TYPE_CHECK : VERIFY_ERROR_BAD_CLASS_HARD)
<< "thrown class " << res_type << " not instanceof Throwable";
+ if (!unresolved) {
+ return false;
+ }
}
}
break;
@@ -3073,16 +3132,19 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
if (!array_type.IsArrayTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data with array type "
<< array_type;
+ return false;
} else if (array_type.IsUnresolvedTypes()) {
// If it's an unresolved array type, it must be non-primitive.
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data for array of type "
<< array_type;
+ return false;
} else {
const RegType& component_type = reg_types_.GetComponentType(array_type);
DCHECK(!component_type.IsConflict());
if (component_type.IsNonZeroReferenceTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data with component type "
<< component_type;
+ return false;
} else {
// Now verify if the element width in the table matches the element width declared in
// the array. The signature has been verified by `CheckArrayData()`.
@@ -3095,6 +3157,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
if (array_data[1] != elem_width) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-data size mismatch (" << array_data[1]
<< " vs " << elem_width << ")";
+ return false;
}
}
}
@@ -3116,6 +3179,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
if (mismatch) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "args to if-eq/if-ne (" << reg_type1 << ","
<< reg_type2 << ") must both be references or integral";
+ return false;
}
break;
}
@@ -3128,6 +3192,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
if (!reg_type1.IsIntegralTypes() || !reg_type2.IsIntegralTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "args to 'if' (" << reg_type1 << ","
<< reg_type2 << ") must be integral";
+ return false;
}
break;
}
@@ -3137,6 +3202,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
if (!reg_type.IsReferenceTypes() && !reg_type.IsIntegralTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type
<< " unexpected as arg to if-eqz/if-nez";
+ return false;
}
// Find previous instruction - its existence is a precondition to peephole optimization.
@@ -3247,6 +3313,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
if (!reg_type.IsIntegralTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type
<< " unexpected as arg to if-ltz/if-gez/if-gtz/if-lez";
+ return false;
}
break;
}
@@ -3429,20 +3496,21 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
* this method (which implies that we're in a constructor ourselves).
*/
const RegType& this_type = GetInvocationThis(inst);
- if (this_type.IsConflict()) // failure.
- break;
+ if (this_type.IsConflict()) { // failure.
+ return false;
+ }
/* no null refs allowed (?) */
if (this_type.IsZeroOrNull()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unable to initialize null ref";
- break;
+ return false;
}
/* arg must be an uninitialized reference */
if (!this_type.IsUninitializedTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Expected initialization on uninitialized reference "
<< this_type;
- break;
+ return false;
}
// Note: According to JLS, constructors are never inherited. Therefore the target
@@ -3511,7 +3579,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
if (this_type.IsUninitializedTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface call on uninitialized object "
<< this_type;
- break;
+ return false;
}
// In the past we have tried to assert that "called_interface" is assignable
// from "this_type.GetClass()", however, as we do an imprecise Join
@@ -3546,13 +3614,12 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_POLYMORPHIC, is_range);
if (called_method == nullptr) {
// Convert potential soft failures in VerifyInvocationArgs() to hard errors.
- if (failures_.size() > 0) {
- std::string_view message = failures_.back().message.view();
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << message;
- } else {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke-polymorphic verification failure.";
- }
- break;
+ std::string_view message = failures_.empty() ? "invoke-polymorphic verification failure."
+ : failures_.back().message.view();
+ // Note: Adding another failure to `failures_` does not invalidate the view of
+ // the previous message (if any) - the list node holding it is not even moved.
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << message;
+ return false;
}
if (!CheckSignaturePolymorphicMethod(called_method) ||
!CheckSignaturePolymorphicReceiver(inst)) {
@@ -3603,62 +3670,100 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
}
case Instruction::NEG_INT:
case Instruction::NOT_INT:
- CheckUnaryOp(inst, inst_data, kInteger, kInteger);
+ if (!CheckUnaryOp(inst, inst_data, kInteger, kInteger)) {
+ return false;
+ }
break;
case Instruction::NEG_LONG:
case Instruction::NOT_LONG:
- CheckUnaryOpWide(inst, inst_data, kLongLo, kLongLo);
+ if (!CheckUnaryOpWide(inst, inst_data, kLongLo, kLongLo)) {
+ return false;
+ }
break;
case Instruction::NEG_FLOAT:
- CheckUnaryOp(inst, inst_data, kFloat, kFloat);
+ if (!CheckUnaryOp(inst, inst_data, kFloat, kFloat)) {
+ return false;
+ }
break;
case Instruction::NEG_DOUBLE:
- CheckUnaryOpWide(inst, inst_data, kDoubleLo, kDoubleLo);
+ if (!CheckUnaryOpWide(inst, inst_data, kDoubleLo, kDoubleLo)) {
+ return false;
+ }
break;
case Instruction::INT_TO_LONG:
- CheckUnaryOpToWide(inst, inst_data, kLongLo, kInteger);
+ if (!CheckUnaryOpToWide(inst, inst_data, kLongLo, kInteger)) {
+ return false;
+ }
break;
case Instruction::INT_TO_FLOAT:
- CheckUnaryOp(inst, inst_data, kFloat, kInteger);
+ if (!CheckUnaryOp(inst, inst_data, kFloat, kInteger)) {
+ return false;
+ }
break;
case Instruction::INT_TO_DOUBLE:
- CheckUnaryOpToWide(inst, inst_data, kDoubleLo, kInteger);
+ if (!CheckUnaryOpToWide(inst, inst_data, kDoubleLo, kInteger)) {
+ return false;
+ }
break;
case Instruction::LONG_TO_INT:
- CheckUnaryOpFromWide(inst, inst_data, kInteger, kLongLo);
+ if (!CheckUnaryOpFromWide(inst, inst_data, kInteger, kLongLo)) {
+ return false;
+ }
break;
case Instruction::LONG_TO_FLOAT:
- CheckUnaryOpFromWide(inst, inst_data, kFloat, kLongLo);
+ if (!CheckUnaryOpFromWide(inst, inst_data, kFloat, kLongLo)) {
+ return false;
+ }
break;
case Instruction::LONG_TO_DOUBLE:
- CheckUnaryOpWide(inst, inst_data, kDoubleLo, kLongLo);
+ if (!CheckUnaryOpWide(inst, inst_data, kDoubleLo, kLongLo)) {
+ return false;
+ }
break;
case Instruction::FLOAT_TO_INT:
- CheckUnaryOp(inst, inst_data, kInteger, kFloat);
+ if (!CheckUnaryOp(inst, inst_data, kInteger, kFloat)) {
+ return false;
+ }
break;
case Instruction::FLOAT_TO_LONG:
- CheckUnaryOpToWide(inst, inst_data, kLongLo, kFloat);
+ if (!CheckUnaryOpToWide(inst, inst_data, kLongLo, kFloat)) {
+ return false;
+ }
break;
case Instruction::FLOAT_TO_DOUBLE:
- CheckUnaryOpToWide(inst, inst_data, kDoubleLo, kFloat);
+ if (!CheckUnaryOpToWide(inst, inst_data, kDoubleLo, kFloat)) {
+ return false;
+ }
break;
case Instruction::DOUBLE_TO_INT:
- CheckUnaryOpFromWide(inst, inst_data, kInteger, kDoubleLo);
+ if (!CheckUnaryOpFromWide(inst, inst_data, kInteger, kDoubleLo)) {
+ return false;
+ }
break;
case Instruction::DOUBLE_TO_LONG:
- CheckUnaryOpWide(inst, inst_data, kLongLo, kDoubleLo);
+ if (!CheckUnaryOpWide(inst, inst_data, kLongLo, kDoubleLo)) {
+ return false;
+ }
break;
case Instruction::DOUBLE_TO_FLOAT:
- CheckUnaryOpFromWide(inst, inst_data, kFloat, kDoubleLo);
+ if (!CheckUnaryOpFromWide(inst, inst_data, kFloat, kDoubleLo)) {
+ return false;
+ }
break;
case Instruction::INT_TO_BYTE:
- CheckUnaryOp(inst, inst_data, kByte, kInteger);
+ if (!CheckUnaryOp(inst, inst_data, kByte, kInteger)) {
+ return false;
+ }
break;
case Instruction::INT_TO_CHAR:
- CheckUnaryOp(inst, inst_data, kChar, kInteger);
+ if (!CheckUnaryOp(inst, inst_data, kChar, kInteger)) {
+ return false;
+ }
break;
case Instruction::INT_TO_SHORT:
- CheckUnaryOp(inst, inst_data, kShort, kInteger);
+ if (!CheckUnaryOp(inst, inst_data, kShort, kInteger)) {
+ return false;
+ }
break;
case Instruction::ADD_INT:
@@ -3669,12 +3774,18 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
case Instruction::SHL_INT:
case Instruction::SHR_INT:
case Instruction::USHR_INT:
- CheckBinaryOp(inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false);
+ if (!CheckBinaryOp(
+ inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false)) {
+ return false;
+ }
break;
case Instruction::AND_INT:
case Instruction::OR_INT:
case Instruction::XOR_INT:
- CheckBinaryOp(inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ true);
+ if (!CheckBinaryOp(
+ inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ true)) {
+ return false;
+ }
break;
case Instruction::ADD_LONG:
case Instruction::SUB_LONG:
@@ -3684,27 +3795,35 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
case Instruction::AND_LONG:
case Instruction::OR_LONG:
case Instruction::XOR_LONG:
- CheckBinaryOpWide(inst, inst_data, kLongLo, kLongLo, kLongLo);
+ if (!CheckBinaryOpWide(inst, inst_data, kLongLo, kLongLo, kLongLo)) {
+ return false;
+ }
break;
case Instruction::SHL_LONG:
case Instruction::SHR_LONG:
case Instruction::USHR_LONG:
/* shift distance is Int, making these different from other binary operations */
- CheckBinaryOpWideShift(inst, inst_data, kLongLo, kInteger);
+ if (!CheckBinaryOpWideShift(inst, inst_data, kLongLo, kInteger)) {
+ return false;
+ }
break;
case Instruction::ADD_FLOAT:
case Instruction::SUB_FLOAT:
case Instruction::MUL_FLOAT:
case Instruction::DIV_FLOAT:
case Instruction::REM_FLOAT:
- CheckBinaryOp(inst, inst_data, kFloat, kFloat, kFloat, /*check_boolean_op=*/ false);
+ if (!CheckBinaryOp(inst, inst_data, kFloat, kFloat, kFloat, /*check_boolean_op=*/ false)) {
+ return false;
+ }
break;
case Instruction::ADD_DOUBLE:
case Instruction::SUB_DOUBLE:
case Instruction::MUL_DOUBLE:
case Instruction::DIV_DOUBLE:
case Instruction::REM_DOUBLE:
- CheckBinaryOpWide(inst, inst_data, kDoubleLo, kDoubleLo, kDoubleLo);
+ if (!CheckBinaryOpWide(inst, inst_data, kDoubleLo, kDoubleLo, kDoubleLo)) {
+ return false;
+ }
break;
case Instruction::ADD_INT_2ADDR:
case Instruction::SUB_INT_2ADDR:
@@ -3713,17 +3832,24 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
case Instruction::SHL_INT_2ADDR:
case Instruction::SHR_INT_2ADDR:
case Instruction::USHR_INT_2ADDR:
- CheckBinaryOp2addr(
- inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false);
+ if (!CheckBinaryOp2addr(
+ inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false)) {
+ return false;
+ }
break;
case Instruction::AND_INT_2ADDR:
case Instruction::OR_INT_2ADDR:
case Instruction::XOR_INT_2ADDR:
- CheckBinaryOp2addr(inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ true);
+ if (!CheckBinaryOp2addr(
+ inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ true)) {
+ return false;
+ }
break;
case Instruction::DIV_INT_2ADDR:
- CheckBinaryOp2addr(
- inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false);
+ if (!CheckBinaryOp2addr(
+ inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false)) {
+ return false;
+ }
break;
case Instruction::ADD_LONG_2ADDR:
case Instruction::SUB_LONG_2ADDR:
@@ -3733,40 +3859,53 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
case Instruction::AND_LONG_2ADDR:
case Instruction::OR_LONG_2ADDR:
case Instruction::XOR_LONG_2ADDR:
- CheckBinaryOp2addrWide(inst, inst_data, kLongLo, kLongLo, kLongLo);
+ if (!CheckBinaryOp2addrWide(inst, inst_data, kLongLo, kLongLo, kLongLo)) {
+ return false;
+ }
break;
case Instruction::SHL_LONG_2ADDR:
case Instruction::SHR_LONG_2ADDR:
case Instruction::USHR_LONG_2ADDR:
- CheckBinaryOp2addrWideShift(inst, inst_data, kLongLo, kInteger);
+ if (!CheckBinaryOp2addrWideShift(inst, inst_data, kLongLo, kInteger)) {
+ return false;
+ }
break;
case Instruction::ADD_FLOAT_2ADDR:
case Instruction::SUB_FLOAT_2ADDR:
case Instruction::MUL_FLOAT_2ADDR:
case Instruction::DIV_FLOAT_2ADDR:
case Instruction::REM_FLOAT_2ADDR:
- CheckBinaryOp2addr(inst, inst_data, kFloat, kFloat, kFloat, /*check_boolean_op=*/ false);
+ if (!CheckBinaryOp2addr(
+ inst, inst_data, kFloat, kFloat, kFloat, /*check_boolean_op=*/ false)) {
+ return false;
+ }
break;
case Instruction::ADD_DOUBLE_2ADDR:
case Instruction::SUB_DOUBLE_2ADDR:
case Instruction::MUL_DOUBLE_2ADDR:
case Instruction::DIV_DOUBLE_2ADDR:
case Instruction::REM_DOUBLE_2ADDR:
- CheckBinaryOp2addrWide(inst, inst_data, kDoubleLo, kDoubleLo, kDoubleLo);
+ if (!CheckBinaryOp2addrWide(inst, inst_data, kDoubleLo, kDoubleLo, kDoubleLo)) {
+ return false;
+ }
break;
case Instruction::ADD_INT_LIT16:
case Instruction::RSUB_INT_LIT16:
case Instruction::MUL_INT_LIT16:
case Instruction::DIV_INT_LIT16:
case Instruction::REM_INT_LIT16:
- CheckLiteralOp(
- inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ false, /*is_lit16=*/ true);
+ if (!CheckLiteralOp</*kIsLit16=*/ true>(
+ inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ false)) {
+ return false;
+ }
break;
case Instruction::AND_INT_LIT16:
case Instruction::OR_INT_LIT16:
case Instruction::XOR_INT_LIT16:
- CheckLiteralOp(
- inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ true, /*is_lit16=*/ true);
+ if (!CheckLiteralOp</*kIsLit16=*/ true>(
+ inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ true)) {
+ return false;
+ }
break;
case Instruction::ADD_INT_LIT8:
case Instruction::RSUB_INT_LIT8:
@@ -3776,14 +3915,18 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
case Instruction::SHL_INT_LIT8:
case Instruction::SHR_INT_LIT8:
case Instruction::USHR_INT_LIT8:
- CheckLiteralOp(
- inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ false, /*is_lit16=*/ false);
+ if (!CheckLiteralOp</*kIsLit16=*/ false>(
+ inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ false)) {
+ return false;
+ }
break;
case Instruction::AND_INT_LIT8:
case Instruction::OR_INT_LIT8:
case Instruction::XOR_INT_LIT8:
- CheckLiteralOp(
- inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ true, /*is_lit16=*/ false);
+ if (!CheckLiteralOp</*kIsLit16=*/ false>(
+ inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ true)) {
+ return false;
+ }
break;
/* These should never appear during verification. */
@@ -3793,7 +3936,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
case Instruction::UNUSED_79:
case Instruction::UNUSED_7A:
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Unexpected opcode " << inst->DumpString(dex_file_);
- break;
+ return false;
/*
* DO NOT add a "default" clause here. Without it the compiler will