summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/verifier/method_verifier.cc27
1 files changed, 22 insertions, 5 deletions
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 63a1fe5f3b..de611e1ca6 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2156,15 +2156,12 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
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 +3034,26 @@ mirror::ArtMethod* MethodVerifier::VerifyInvocationArgs(const Instruction* inst,
// 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;