summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/verifier/method_verifier.cc181
-rw-r--r--src/verifier/method_verifier.h25
2 files changed, 108 insertions, 98 deletions
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 87cc3286b3..74a79e0ae2 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -278,8 +278,6 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_ca
declaring_class_(NULL),
interesting_dex_pc_(-1),
monitor_enter_dex_pcs_(NULL),
- accessed_field(NULL),
- invoked_method(NULL),
have_pending_hard_failure_(false),
have_pending_runtime_throw_failure_(false),
new_instance_count_(0),
@@ -316,22 +314,26 @@ mirror::Field* MethodVerifier::FindAccessedFieldAtDexPc(mirror::AbstractMethod*
MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(),
mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(),
m, m->GetAccessFlags(), false, true);
- mirror::Field* field = NULL;
- verifier.interesting_dex_pc_ = dex_pc;
- verifier.accessed_field = &field;
- verifier.FindAccessedFieldAtDexPc();
- return field;
+ return verifier.FindAccessedFieldAtDexPc(dex_pc);
}
-void MethodVerifier::FindAccessedFieldAtDexPc() {
- CHECK(accessed_field != NULL);
+mirror::Field* MethodVerifier::FindAccessedFieldAtDexPc(uint32_t dex_pc) {
CHECK(code_item_ != NULL); // This only makes sense for methods with code.
// Strictly speaking, we ought to be able to get away with doing a subset of the full method
// verification. In practice, the phase we want relies on data structures set up by all the
// earlier passes, so we just run the full method verification and bail out early when we've
// got what we wanted.
- Verify();
+ bool success = Verify();
+ if (!success) {
+ return NULL;
+ }
+ RegisterLine* register_line = reg_table_.GetLine(dex_pc);
+ if (register_line == NULL) {
+ return NULL;
+ }
+ const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
+ return GetQuickFieldAccess(inst, register_line);
}
mirror::AbstractMethod* MethodVerifier::FindInvokedMethodAtDexPc(mirror::AbstractMethod* m,
@@ -340,22 +342,27 @@ mirror::AbstractMethod* MethodVerifier::FindInvokedMethodAtDexPc(mirror::Abstrac
MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(),
mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(),
m, m->GetAccessFlags(), false, true);
- mirror::AbstractMethod* method = NULL;
- verifier.interesting_dex_pc_ = dex_pc;
- verifier.invoked_method = &method;
- verifier.FindInvokedMethodAtDexPc();
- return method;
+ return verifier.FindInvokedMethodAtDexPc(dex_pc);
}
-void MethodVerifier::FindInvokedMethodAtDexPc() {
- CHECK(invoked_method != NULL);
+mirror::AbstractMethod* MethodVerifier::FindInvokedMethodAtDexPc(uint32_t dex_pc) {
CHECK(code_item_ != NULL); // This only makes sense for methods with code.
// Strictly speaking, we ought to be able to get away with doing a subset of the full method
// verification. In practice, the phase we want relies on data structures set up by all the
// earlier passes, so we just run the full method verification and bail out early when we've
// got what we wanted.
- Verify();
+ bool success = Verify();
+ if (!success) {
+ return NULL;
+ }
+ RegisterLine* register_line = reg_table_.GetLine(dex_pc);
+ if (register_line == NULL) {
+ return NULL;
+ }
+ const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
+ const bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
+ return GetQuickInvokedMethod(inst, register_line, is_range);
}
bool MethodVerifier::Verify() {
@@ -2964,12 +2971,12 @@ mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const Instruction*
}
}
-mirror::AbstractMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instruction* inst,
- bool is_range) {
- DCHECK(Runtime::Current()->IsStarted());
- CHECK(invoked_method != NULL || accessed_field != NULL)
- << "We should not be verifying " << inst->Name();
- const RegType& actual_arg_type = work_line_->GetInvocationThis(inst, is_range);
+mirror::AbstractMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst,
+ RegisterLine* reg_line,
+ bool is_range) {
+ DCHECK(inst->Opcode() == Instruction::INVOKE_VIRTUAL_QUICK ||
+ inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
+ const RegType& actual_arg_type = reg_line->GetInvocationThis(inst, is_range);
if (actual_arg_type.IsConflict()) { // GetInvocationThis failed.
return NULL;
}
@@ -2986,21 +2993,25 @@ mirror::AbstractMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instr
this_class = class_linker->FindClass(descriptor.c_str(), NULL);
}
}
- CHECK(this_class != NULL) << "Cannot get Class* for type " << actual_arg_type;
+ if (this_class == NULL) {
+ return NULL;
+ }
mirror::ObjectArray<mirror::AbstractMethod>* vtable = this_class->GetVTable();
CHECK(vtable != NULL);
uint16_t vtable_index = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
CHECK(vtable_index < vtable->GetLength());
mirror::AbstractMethod* res_method = vtable->Get(vtable_index);
CHECK(!Thread::Current()->IsExceptionPending());
- // TODO: we should move the code below to FindInvokedMethodAtDexPc. Once the
- // method is verified, we could access the information we need from register
- // lines for the dex pc we are looking for.
- if (invoked_method != NULL && work_insn_idx_ == interesting_dex_pc_) {
- // We've been requested to tell which method is invoked at this dex pc.
- *invoked_method = res_method;
- }
+ return res_method;
+}
+
+mirror::AbstractMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instruction* inst,
+ bool is_range) {
+ DCHECK(Runtime::Current()->IsStarted());
+ mirror::AbstractMethod* res_method = GetQuickInvokedMethod(inst, work_line_.get(),
+ is_range);
if (res_method == NULL) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer method from " << inst->Name();
return NULL;
}
CHECK(!res_method->IsDirect() && !res_method->IsStatic());
@@ -3008,6 +3019,10 @@ mirror::AbstractMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instr
// We use vAA as our expected arg count, rather than res_method->insSize, because we need to
// match the call to the signature. Also, we might be calling through an abstract method
// definition (which doesn't have register count values).
+ const RegType& actual_arg_type = work_line_->GetInvocationThis(inst, is_range);
+ if (actual_arg_type.IsConflict()) { // GetInvocationThis failed.
+ return NULL;
+ }
const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
/* caught by static verifier */
DCHECK(is_range || expected_args <= 5);
@@ -3060,7 +3075,7 @@ mirror::AbstractMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instr
mh.GetTypeDescriptorFromTypeIdx(params->GetTypeItem(param_index).type_idx_);
if (descriptor == NULL) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation of " << PrettyMethod(res_method)
- << " missing signature component";
+ << " missing signature component";
return NULL;
}
const RegType& reg_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
@@ -3443,10 +3458,10 @@ void MethodVerifier::VerifyISPut(const Instruction* inst, const RegType& insn_ty
// Look for an instance field with this offset.
// TODO: we may speed up the search if offsets are sorted by doing a quick search.
-static mirror::Field* FindInstanceFieldWithOffset(mirror::Class* klass,
+static mirror::Field* FindInstanceFieldWithOffset(const mirror::Class* klass,
uint32_t field_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ObjectArray<mirror::Field>* instance_fields = klass->GetIFields();
+ const mirror::ObjectArray<mirror::Field>* instance_fields = klass->GetIFields();
if (instance_fields != NULL) {
for (int32_t i = 0, e = instance_fields->GetLength(); i < e; ++i) {
mirror::Field* field = instance_fields->Get(i);
@@ -3455,6 +3470,7 @@ static mirror::Field* FindInstanceFieldWithOffset(mirror::Class* klass,
}
}
}
+ // We did not find field in class: look into superclass.
if (klass->GetSuperClass() != NULL) {
return FindInstanceFieldWithOffset(klass->GetSuperClass(), field_offset);
} else {
@@ -3462,12 +3478,17 @@ static mirror::Field* FindInstanceFieldWithOffset(mirror::Class* klass,
}
}
-void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& insn_type,
- bool is_primitive) {
- DCHECK(Runtime::Current()->IsStarted());
- CHECK(accessed_field != NULL || invoked_method != NULL)
- << "We should not be verifying " << inst->Name();
- const RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
+// Returns the access field of a quick field access (iget/iput-quick) or NULL
+// if it cannot be found.
+mirror::Field* MethodVerifier::GetQuickFieldAccess(const Instruction* inst,
+ RegisterLine* reg_line) {
+ DCHECK(inst->Opcode() == Instruction::IGET_QUICK ||
+ inst->Opcode() == Instruction::IGET_WIDE_QUICK ||
+ inst->Opcode() == Instruction::IGET_OBJECT_QUICK ||
+ inst->Opcode() == Instruction::IPUT_QUICK ||
+ inst->Opcode() == Instruction::IPUT_WIDE_QUICK ||
+ inst->Opcode() == Instruction::IPUT_OBJECT_QUICK);
+ const RegType& object_type = reg_line->GetRegisterType(inst->VRegB_22c());
mirror::Class* object_class = NULL;
if (!object_type.IsUnresolvedTypes()) {
object_class = object_type.GetClass();
@@ -3482,16 +3503,22 @@ void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& ins
object_class = class_linker->FindClass(descriptor.c_str(), NULL);
}
}
- CHECK(object_class != NULL) << "Cannot get Class* for type " << object_type;
+ if (object_class == NULL) {
+ // Failed to get the Class* from reg type.
+ LOG(WARNING) << "Failed to get Class* from " << object_type;
+ return NULL;
+ }
uint32_t field_offset = static_cast<uint32_t>(inst->VRegC_22c());
- mirror::Field* field = FindInstanceFieldWithOffset(object_class, field_offset);
- CHECK(field != NULL);
- // TODO: we should move the code below to FindAccessedFieldAtDexPc. Once the
- // method is verified, we could access the information we need from register
- // lines for the dex pc we are looking for.
- if (accessed_field != NULL && work_insn_idx_ == interesting_dex_pc_) {
- // We've been requested to tell which field is accessed at this dex pc.
- *accessed_field = field;
+ return FindInstanceFieldWithOffset(object_class, field_offset);
+}
+
+void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& insn_type,
+ bool is_primitive) {
+ DCHECK(Runtime::Current()->IsStarted());
+ mirror::Field* field = GetQuickFieldAccess(inst, work_line_.get());
+ if (field == NULL) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
+ return;
}
const char* descriptor = FieldHelper(field).GetTypeDescriptor();
mirror::ClassLoader* loader = field->GetDeclaringClass()->GetClassLoader();
@@ -3508,16 +3535,16 @@ void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& ins
// the descriptors for the type should have been consistent within the same file at
// compile time
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
- << " to be of type '" << insn_type
- << "' but found type '" << field_type << "' in get";
+ << " to be of type '" << insn_type
+ << "' but found type '" << field_type << "' in get";
return;
}
} else {
if (!insn_type.IsAssignableFrom(field_type)) {
Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
- << " to be compatible with type '" << insn_type
- << "' but found type '" << field_type
- << "' in get-object";
+ << " to be compatible with type '" << insn_type
+ << "' but found type '" << field_type
+ << "' in get-object";
work_line_->SetRegisterType(vregA, reg_types_.Conflict());
return;
}
@@ -3532,32 +3559,10 @@ void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& ins
void MethodVerifier::VerifyIPutQuick(const Instruction* inst, const RegType& insn_type,
bool is_primitive) {
DCHECK(Runtime::Current()->IsStarted());
- CHECK(accessed_field != NULL || invoked_method != NULL)
- << "We should not be verifying " << inst->Name();
- const RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
- mirror::Class* object_class = NULL;
- if (!object_type.IsUnresolvedTypes()) {
- object_class = object_type.GetClass();
- } else {
- // We need to resolve the class from its descriptor.
- const std::string& descriptor(object_type.GetDescriptor());
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- object_class = class_linker->FindClass(descriptor.c_str(), class_loader_);
- if (object_class == NULL) {
- Thread::Current()->ClearException();
- // Look for a system class
- object_class = class_linker->FindClass(descriptor.c_str(), NULL);
- }
- }
- CHECK(object_class != NULL) << "Cannot get Class* for type " << object_type;
- uint32_t field_offset = static_cast<uint32_t>(inst->VRegC_22c());
- mirror::Field* field = FindInstanceFieldWithOffset(object_class, field_offset);
- CHECK(field != NULL);
- // TODO: like VerifyIGetQuick, we should move the code below to
- // FindAccessedFieldAtDexPc.
- if (accessed_field != NULL && work_insn_idx_ == interesting_dex_pc_) {
- // We've been requested to tell which field is accessed at this dex pc.
- *accessed_field = field;
+ mirror::Field* field = GetQuickFieldAccess(inst, work_line_.get());
+ if (field == NULL) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
+ return;
}
const char* descriptor = FieldHelper(field).GetTypeDescriptor();
mirror::ClassLoader* loader = field->GetDeclaringClass()->GetClassLoader();
@@ -3565,7 +3570,7 @@ void MethodVerifier::VerifyIPutQuick(const Instruction* inst, const RegType& ins
if (field != NULL) {
if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
- << " from other class " << GetDeclaringClass();
+ << " from other class " << GetDeclaringClass();
return;
}
}
@@ -3596,9 +3601,9 @@ void MethodVerifier::VerifyIPutQuick(const Instruction* inst, const RegType& ins
// the descriptors for the type should have been consistent within the same file at
// compile time
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
- << " to be of type '" << insn_type
- << "' but found type '" << field_type
- << "' in put";
+ << " to be of type '" << insn_type
+ << "' but found type '" << field_type
+ << "' in put";
return;
}
if (!value_compatible) {
@@ -3611,9 +3616,9 @@ void MethodVerifier::VerifyIPutQuick(const Instruction* inst, const RegType& ins
} else {
if (!insn_type.IsAssignableFrom(field_type)) {
Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
- << " to be compatible with type '" << insn_type
- << "' but found type '" << field_type
- << "' in put-object";
+ << " to be compatible with type '" << insn_type
+ << "' but found type '" << field_type
+ << "' in put-object";
return;
}
work_line_->VerifyRegisterType(vregA, field_type);
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index da6497926d..e90f9d95b0 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -266,9 +266,11 @@ class MethodVerifier {
void FindLocksAtDexPc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void FindAccessedFieldAtDexPc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::Field* FindAccessedFieldAtDexPc(uint32_t dex_pc)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void FindInvokedMethodAtDexPc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::AbstractMethod* FindInvokedMethodAtDexPc(uint32_t dex_pc)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
* Compute the width of the instruction at each address in the instruction stream, and store it in
@@ -500,6 +502,11 @@ class MethodVerifier {
bool is_primitive, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Returns the access field of a quick field access (iget/iput-quick) or NULL
+ // if it cannot be found.
+ mirror::Field* GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Perform verification of an iget-quick instruction.
void VerifyIGetQuick(const Instruction* inst, const RegType& insn_type,
bool is_primitive)
@@ -558,6 +565,11 @@ class MethodVerifier {
bool is_range, bool is_super)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::AbstractMethod* GetQuickInvokedMethod(const Instruction* inst,
+ RegisterLine* reg_line,
+ bool is_range)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
mirror::AbstractMethod* VerifyInvokeVirtualQuickArgs(const Instruction* inst,
bool is_range)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -676,18 +688,11 @@ class MethodVerifier {
const RegType* declaring_class_; // Lazily computed reg type of the method's declaring class.
// Instruction widths and flags, one entry per code unit.
UniquePtr<InstructionFlags[]> insn_flags_;
- // The dex PC of a FindLocksAtDexPc, FindAccessedFieldAtDexPc or
- // FindInvokedMethodAtDexPc request, -1 otherwise.
+ // The dex PC of a FindLocksAtDexPc request, -1 otherwise.
uint32_t interesting_dex_pc_;
// The container into which FindLocksAtDexPc should write the registers containing held locks,
// NULL if we're not doing FindLocksAtDexPc.
std::vector<uint32_t>* monitor_enter_dex_pcs_;
- // The pointer into which FindAccessedFieldAtDexPc should write the accessed field,
- // NULL if we're not doing FindAccessedFieldAtDexPc.
- mirror::Field** accessed_field;
- // The pointer into which FindInvokedMethodAtDexPc should write the invoked method,
- // NULL if we're not doing FindInvokedMethodAtDexPc.
- mirror::AbstractMethod** invoked_method;
// The types of any error that occurs.
std::vector<VerifyError> failures_;