Merge "Don't use signal handlers in interpreter only mode"
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index dd8e221..d704788 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1288,8 +1288,8 @@
*/
TWO_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_RESULT_IS_NON_ZERO
-UNIMPLEMENTED art_quick_initialize_type
-UNIMPLEMENTED art_quick_initialize_type_and_verify_access
+TWO_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO
+TWO_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO
ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
ONE_ARG_REF_DOWNCALL art_quick_get64_static, artGet64StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 59311bc..7785bc3 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -1784,9 +1784,87 @@
ASSERT_FALSE(self->IsExceptionPending());
EXPECT_EQ(static_cast<size_t>(JNI_TRUE), result);
#else
- LOG(INFO) << "Skipping memcpy as I don't know how to do that on " << kRuntimeISA;
+ LOG(INFO) << "Skipping imt as I don't know how to do that on " << kRuntimeISA;
// Force-print to std::cout so it's also outside the logcat.
- std::cout << "Skipping memcpy as I don't know how to do that on " << kRuntimeISA << std::endl;
+ std::cout << "Skipping imt as I don't know how to do that on " << kRuntimeISA << std::endl;
+#endif
+}
+
+#if defined(__arm__) || defined(__aarch64__)
+extern "C" void art_quick_indexof(void);
+#endif
+
+TEST_F(StubTest, StringIndexOf) {
+#if defined(__arm__) || defined(__aarch64__)
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+ // garbage is created during ClassLinker::Init
+
+ // Create some strings
+ // Use array so we can index into it and use a matrix for expected results
+ // Setup: The first half is standard. The second half uses a non-zero offset.
+ // TODO: Shared backing arrays.
+ static constexpr size_t kStringCount = 7;
+ const char* c_str[kStringCount] = { "", "a", "ba", "cba", "dcba", "edcba", "asdfghjkl" };
+ static constexpr size_t kCharCount = 5;
+ const char c_char[kCharCount] = { 'a', 'b', 'c', 'd', 'e' };
+
+ StackHandleScope<kStringCount> hs(self);
+ Handle<mirror::String> s[kStringCount];
+
+ for (size_t i = 0; i < kStringCount; ++i) {
+ s[i] = hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), c_str[i]));
+ }
+
+ // Matrix of expectations. First component is first parameter. Note we only check against the
+ // sign, not the value. As we are testing random offsets, we need to compute this and need to
+ // rely on String::CompareTo being correct.
+ static constexpr size_t kMaxLen = 9;
+ DCHECK_LE(strlen(c_str[kStringCount-1]), kMaxLen) << "Please fix the indexof test.";
+
+ // Last dimension: start, offset by 1.
+ int32_t expected[kStringCount][kCharCount][kMaxLen + 3];
+ for (size_t x = 0; x < kStringCount; ++x) {
+ for (size_t y = 0; y < kCharCount; ++y) {
+ for (size_t z = 0; z <= kMaxLen + 2; ++z) {
+ expected[x][y][z] = s[x]->FastIndexOf(c_char[y], static_cast<int32_t>(z) - 1);
+ }
+ }
+ }
+
+ // Play with it...
+
+ for (size_t x = 0; x < kStringCount; ++x) {
+ for (size_t y = 0; y < kCharCount; ++y) {
+ for (size_t z = 0; z <= kMaxLen + 2; ++z) {
+ int32_t start = static_cast<int32_t>(z) - 1;
+
+ // Test string_compareto x y
+ size_t result = Invoke3(reinterpret_cast<size_t>(s[x].Get()), c_char[y], start,
+ reinterpret_cast<uintptr_t>(&art_quick_indexof), self);
+
+ EXPECT_FALSE(self->IsExceptionPending());
+
+ // The result is a 32b signed integer
+ union {
+ size_t r;
+ int32_t i;
+ } conv;
+ conv.r = result;
+
+ EXPECT_EQ(expected[x][y][z], conv.i) << "Wrong result for " << c_str[x] << " / " <<
+ c_char[y] << " @ " << start;
+ }
+ }
+ }
+
+ // TODO: Deallocate things.
+
+ // Tests done.
+#else
+ LOG(INFO) << "Skipping indexof as I don't know how to do that on " << kRuntimeISA;
+ // Force-print to std::cout so it's also outside the logcat.
+ std::cout << "Skipping indexof as I don't know how to do that on " << kRuntimeISA << std::endl;
#endif
}
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 61ea870..3000217 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -111,17 +111,17 @@
}
// Helper macro to load method id. Return last parameter on error.
-#define LOAD_METHOD(var, idx, error_string, error_val) \
+#define LOAD_METHOD(var, idx, error_string, error_stmt) \
const DexFile::MethodId* var = CheckLoadMethodId(idx, error_string); \
if (UNLIKELY(var == nullptr)) { \
- return error_val; \
+ error_stmt; \
}
// Helper macro to load method id. Return last parameter on error.
-#define LOAD_FIELD(var, idx, fmt, error_val) \
+#define LOAD_FIELD(var, idx, fmt, error_stmt) \
const DexFile::FieldId* var = CheckLoadFieldId(idx, fmt); \
if (UNLIKELY(var == nullptr)) { \
- return error_val; \
+ error_stmt; \
}
bool DexFileVerifier::Verify(const DexFile* dex_file, const byte* begin, size_t size,
@@ -1378,42 +1378,48 @@
return true;
}
-uint32_t DexFileVerifier::FindFirstClassDataDefiner(const byte* ptr) {
+uint16_t DexFileVerifier::FindFirstClassDataDefiner(const byte* ptr, bool* success) {
ClassDataItemIterator it(*dex_file_, ptr);
+ *success = true;
if (it.HasNextStaticField() || it.HasNextInstanceField()) {
- LOAD_FIELD(field, it.GetMemberIndex(), "first_class_data_definer field_id", 0x10000U)
+ LOAD_FIELD(field, it.GetMemberIndex(), "first_class_data_definer field_id",
+ *success = false; return DexFile::kDexNoIndex16)
return field->class_idx_;
}
if (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
- LOAD_METHOD(method, it.GetMemberIndex(), "first_class_data_definer method_id", 0x10000U)
+ LOAD_METHOD(method, it.GetMemberIndex(), "first_class_data_definer method_id",
+ *success = false; return DexFile::kDexNoIndex16)
return method->class_idx_;
}
return DexFile::kDexNoIndex16;
}
-uint32_t DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const byte* ptr) {
+uint16_t DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const byte* ptr, bool* success) {
const DexFile::AnnotationsDirectoryItem* item =
reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr);
+ *success = true;
+
if (item->fields_size_ != 0) {
DexFile::FieldAnnotationsItem* field_items = (DexFile::FieldAnnotationsItem*) (item + 1);
- LOAD_FIELD(field, field_items[0].field_idx_, "first_annotations_dir_definer field_id", 0x10000U)
+ LOAD_FIELD(field, field_items[0].field_idx_, "first_annotations_dir_definer field_id",
+ *success = false; return DexFile::kDexNoIndex16)
return field->class_idx_;
}
if (item->methods_size_ != 0) {
DexFile::MethodAnnotationsItem* method_items = (DexFile::MethodAnnotationsItem*) (item + 1);
LOAD_METHOD(method, method_items[0].method_idx_, "first_annotations_dir_definer method id",
- 0x10000U)
+ *success = false; return DexFile::kDexNoIndex16)
return method->class_idx_;
}
if (item->parameters_size_ != 0) {
DexFile::ParameterAnnotationsItem* parameter_items = (DexFile::ParameterAnnotationsItem*) (item + 1);
LOAD_METHOD(method, parameter_items[0].method_idx_, "first_annotations_dir_definer method id",
- 0x10000U)
+ *success = false; return DexFile::kDexNoIndex16)
return method->class_idx_;
}
@@ -1699,8 +1705,9 @@
// Check that references in class_data_item are to the right class.
if (item->class_data_off_ != 0) {
const byte* data = begin_ + item->class_data_off_;
- uint32_t data_definer = FindFirstClassDataDefiner(data);
- if (data_definer >= 0x10000U) {
+ bool success;
+ uint16_t data_definer = FindFirstClassDataDefiner(data, &success);
+ if (!success) {
return false;
}
if (UNLIKELY((data_definer != item->class_idx_) && (data_definer != DexFile::kDexNoIndex16))) {
@@ -1712,8 +1719,9 @@
// Check that references in annotations_directory_item are to right class.
if (item->annotations_off_ != 0) {
const byte* data = begin_ + item->annotations_off_;
- uint32_t annotations_definer = FindFirstAnnotationsDirectoryDefiner(data);
- if (annotations_definer >= 0x10000U) {
+ bool success;
+ uint16_t annotations_definer = FindFirstAnnotationsDirectoryDefiner(data, &success);
+ if (!success) {
return false;
}
if (UNLIKELY((annotations_definer != item->class_idx_) &&
@@ -1777,13 +1785,14 @@
bool DexFileVerifier::CheckInterClassDataItem() {
ClassDataItemIterator it(*dex_file_, ptr_);
- uint32_t defining_class = FindFirstClassDataDefiner(ptr_);
- if (defining_class >= 0x10000U) {
+ bool success;
+ uint16_t defining_class = FindFirstClassDataDefiner(ptr_, &success);
+ if (!success) {
return false;
}
for (; it.HasNextStaticField() || it.HasNextInstanceField(); it.Next()) {
- LOAD_FIELD(field, it.GetMemberIndex(), "inter_class_data_item field_id", false)
+ LOAD_FIELD(field, it.GetMemberIndex(), "inter_class_data_item field_id", return false)
if (UNLIKELY(field->class_idx_ != defining_class)) {
ErrorStringPrintf("Mismatched defining class for class_data_item field");
return false;
@@ -1794,7 +1803,7 @@
if (code_off != 0 && !CheckOffsetToTypeMap(code_off, DexFile::kDexTypeCodeItem)) {
return false;
}
- LOAD_METHOD(method, it.GetMemberIndex(), "inter_class_data_item method_id", false)
+ LOAD_METHOD(method, it.GetMemberIndex(), "inter_class_data_item method_id", return false)
if (UNLIKELY(method->class_idx_ != defining_class)) {
ErrorStringPrintf("Mismatched defining class for class_data_item method");
return false;
@@ -1808,8 +1817,9 @@
bool DexFileVerifier::CheckInterAnnotationsDirectoryItem() {
const DexFile::AnnotationsDirectoryItem* item =
reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr_);
- uint32_t defining_class = FindFirstAnnotationsDirectoryDefiner(ptr_);
- if (defining_class >= 0x10000U) {
+ bool success;
+ uint16_t defining_class = FindFirstAnnotationsDirectoryDefiner(ptr_, &success);
+ if (!success) {
return false;
}
@@ -1823,7 +1833,8 @@
reinterpret_cast<const DexFile::FieldAnnotationsItem*>(item + 1);
uint32_t field_count = item->fields_size_;
for (uint32_t i = 0; i < field_count; i++) {
- LOAD_FIELD(field, field_item->field_idx_, "inter_annotations_directory_item field_id", false)
+ LOAD_FIELD(field, field_item->field_idx_, "inter_annotations_directory_item field_id",
+ return false)
if (UNLIKELY(field->class_idx_ != defining_class)) {
ErrorStringPrintf("Mismatched defining class for field_annotation");
return false;
@@ -1840,7 +1851,7 @@
uint32_t method_count = item->methods_size_;
for (uint32_t i = 0; i < method_count; i++) {
LOAD_METHOD(method, method_item->method_idx_, "inter_annotations_directory_item method_id",
- false)
+ return false)
if (UNLIKELY(method->class_idx_ != defining_class)) {
ErrorStringPrintf("Mismatched defining class for method_annotation");
return false;
@@ -1857,7 +1868,7 @@
uint32_t parameter_count = item->parameters_size_;
for (uint32_t i = 0; i < parameter_count; i++) {
LOAD_METHOD(parameter_method, parameter_item->method_idx_,
- "inter_annotations_directory_item parameter method_id", false)
+ "inter_annotations_directory_item parameter method_id", return false)
if (UNLIKELY(parameter_method->class_idx_ != defining_class)) {
ErrorStringPrintf("Mismatched defining class for parameter_annotation");
return false;
diff --git a/runtime/dex_file_verifier.h b/runtime/dex_file_verifier.h
index 7489dcd..f845993 100644
--- a/runtime/dex_file_verifier.h
+++ b/runtime/dex_file_verifier.h
@@ -72,10 +72,10 @@
bool CheckOffsetToTypeMap(size_t offset, uint16_t type);
- // Note: the result type of the following methods is wider than that of the underlying index
- // (16b vs 32b). This is so that we can define an error value (anything >= 2^16).
- uint32_t FindFirstClassDataDefiner(const byte* ptr);
- uint32_t FindFirstAnnotationsDirectoryDefiner(const byte* ptr);
+ // Note: as sometimes kDexNoIndex16, being 0xFFFF, is a valid return value, we need an
+ // additional out parameter to signal any errors loading an index.
+ uint16_t FindFirstClassDataDefiner(const byte* ptr, bool* success);
+ uint16_t FindFirstAnnotationsDirectoryDefiner(const byte* ptr, bool* success);
bool CheckInterStringIdItem();
bool CheckInterTypeIdItem();
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index 1ff5c19..edba502 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -145,27 +145,28 @@
};
enum VerifyFlag {
- kVerifyNone = 0x00000,
- kVerifyRegA = 0x00001,
- kVerifyRegAWide = 0x00002,
- kVerifyRegB = 0x00004,
- kVerifyRegBField = 0x00008,
- kVerifyRegBMethod = 0x00010,
- kVerifyRegBNewInstance = 0x00020,
- kVerifyRegBString = 0x00040,
- kVerifyRegBType = 0x00080,
- kVerifyRegBWide = 0x00100,
- kVerifyRegC = 0x00200,
- kVerifyRegCField = 0x00400,
- kVerifyRegCNewArray = 0x00800,
- kVerifyRegCType = 0x01000,
- kVerifyRegCWide = 0x02000,
- kVerifyArrayData = 0x04000,
- kVerifyBranchTarget = 0x08000,
- kVerifySwitchTargets = 0x10000,
- kVerifyVarArg = 0x20000,
- kVerifyVarArgRange = 0x40000,
- kVerifyError = 0x80000,
+ kVerifyNone = 0x000000,
+ kVerifyRegA = 0x000001,
+ kVerifyRegAWide = 0x000002,
+ kVerifyRegB = 0x000004,
+ kVerifyRegBField = 0x000008,
+ kVerifyRegBMethod = 0x000010,
+ kVerifyRegBNewInstance = 0x000020,
+ kVerifyRegBString = 0x000040,
+ kVerifyRegBType = 0x000080,
+ kVerifyRegBWide = 0x000100,
+ kVerifyRegC = 0x000200,
+ kVerifyRegCField = 0x000400,
+ kVerifyRegCNewArray = 0x000800,
+ kVerifyRegCType = 0x001000,
+ kVerifyRegCWide = 0x002000,
+ kVerifyArrayData = 0x004000,
+ kVerifyBranchTarget = 0x008000,
+ kVerifySwitchTargets = 0x010000,
+ kVerifyVarArg = 0x020000,
+ kVerifyVarArgRange = 0x040000,
+ kVerifyRuntimeOnly = 0x080000,
+ kVerifyError = 0x100000,
};
static constexpr uint32_t kMaxVarArgRegs = 5;
@@ -493,18 +494,23 @@
}
int GetVerifyTypeArgumentB() const {
- return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegB | kVerifyRegBField | kVerifyRegBMethod |
- kVerifyRegBNewInstance | kVerifyRegBString | kVerifyRegBType | kVerifyRegBWide));
+ return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegB | kVerifyRegBField |
+ kVerifyRegBMethod | kVerifyRegBNewInstance | kVerifyRegBString | kVerifyRegBType |
+ kVerifyRegBWide));
}
int GetVerifyTypeArgumentC() const {
return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegC | kVerifyRegCField |
- kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide));
+ kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide));
}
int GetVerifyExtraFlags() const {
return (kInstructionVerifyFlags[Opcode()] & (kVerifyArrayData | kVerifyBranchTarget |
- kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgRange | kVerifyError));
+ kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgRange | kVerifyError));
+ }
+
+ bool GetVerifyIsRuntimeOnly() const {
+ return (kInstructionVerifyFlags[Opcode()] & kVerifyRuntimeOnly) != 0;
}
// Get the dex PC of this instruction as a offset in code units from the beginning of insns.
diff --git a/runtime/dex_instruction_list.h b/runtime/dex_instruction_list.h
index f43e42f..4cda58b 100644
--- a/runtime/dex_instruction_list.h
+++ b/runtime/dex_instruction_list.h
@@ -245,14 +245,14 @@
V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kNone, kContinue | kShl | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kNone, kContinue | kShr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kNone, kContinue | kUshr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xE3, IGET_QUICK, "iget-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB) \
- V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xE6, IPUT_QUICK, "iput-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB) \
- V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArg) \
- V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgRange) \
+ V(0xE3, IGET_QUICK, "iget-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+ V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
+ V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+ V(0xE6, IPUT_QUICK, "iput-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+ V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
+ V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+ V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArg | kVerifyRuntimeOnly) \
+ V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgRange | kVerifyRuntimeOnly) \
V(0xEB, UNUSED_EB, "unused-eb", k10x, false, kUnknown, 0, kVerifyError) \
V(0xEC, UNUSED_EC, "unused-ec", k10x, false, kUnknown, 0, kVerifyError) \
V(0xED, UNUSED_ED, "unused-ed", k10x, false, kUnknown, 0, kVerifyError) \
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 63a1fe5..1d04151 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -731,6 +731,10 @@
result = false;
break;
}
+ if (inst->GetVerifyIsRuntimeOnly() && Runtime::Current()->IsCompiler()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "opcode only expected at runtime " << inst->Name();
+ result = false;
+ }
return result;
}
@@ -1334,31 +1338,6 @@
insn_flags_[insn_idx].ClearChanged();
}
- // When we're in compiler mode, do not accept quickened instructions.
- // We explicitly iterate over *all* instructions to check code that may be unreachable and
- // missed by the loop above.
- if (Runtime::Current() != nullptr && Runtime::Current()->IsCompiler()) {
- uint32_t insn_idx = 0;
- for (; insn_idx < insns_size; insn_idx += insn_flags_[insn_idx].GetLengthInCodeUnits()) {
- const Instruction* inst = Instruction::At(insns + insn_idx);
- switch (inst->Opcode()) {
- case Instruction::IGET_QUICK:
- case Instruction::IGET_WIDE_QUICK:
- case Instruction::IGET_OBJECT_QUICK:
- case Instruction::IPUT_QUICK:
- case Instruction::IPUT_WIDE_QUICK:
- case Instruction::IPUT_OBJECT_QUICK:
- case Instruction::INVOKE_VIRTUAL_QUICK:
- case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Quickened instructions not allowed. ";
- return false;
-
- default:
- break;
- }
- }
- }
-
if (gDebugVerify) {
/*
* Scan for dead code. There's nothing "evil" about dead code
@@ -2156,15 +2135,12 @@
case Instruction::INVOKE_VIRTUAL_RANGE:
case Instruction::INVOKE_SUPER:
case Instruction::INVOKE_SUPER_RANGE: {
- if (inst->VRegA() == 0) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke_virtual/super needs at least receiver";
- }
bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE ||
inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
bool is_super = (inst->Opcode() == Instruction::INVOKE_SUPER ||
inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
- mirror::ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_VIRTUAL,
- is_range, is_super);
+ mirror::ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_VIRTUAL, is_range,
+ is_super);
const RegType* return_type = nullptr;
if (called_method != nullptr) {
Thread* self = Thread::Current();
@@ -3037,6 +3013,26 @@
// Resolve the method. This could be an abstract or concrete method depending on what sort of call
// we're making.
const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+
+ // As the method may not have been resolved, make this static check against what we expect.
+ const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
+ uint32_t shorty_idx = dex_file_->GetProtoId(method_id.proto_idx_).shorty_idx_;
+ uint32_t shorty_len;
+ const char* descriptor = dex_file_->StringDataAndUtf16LengthByIdx(shorty_idx, &shorty_len);
+ int32_t sig_registers = method_type == METHOD_STATIC ? 0 : 1;
+ for (size_t i = 1; i < shorty_len; i++) {
+ if (descriptor[i] == 'J' || descriptor[i] == 'D') {
+ sig_registers += 2;
+ } else {
+ sig_registers++;
+ }
+ }
+ if (inst->VRegA() != sig_registers) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation, expected " << inst->VRegA() <<
+ " arguments, found " << sig_registers;
+ return nullptr;
+ }
+
mirror::ArtMethod* res_method = ResolveMethodAndCheckAccess(method_idx, method_type);
if (res_method == NULL) { // error or class is unresolved
return NULL;