Merge "Do not hide instance field hard failure with soft failure"
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 5e691c7..135038b 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -381,10 +381,11 @@
// If the operation requests a specific type, we make sure its input is of that type.
if (type != value->GetType()) {
if (Primitive::IsFloatingPointType(type)) {
- return ssa_builder_->GetFloatOrDoubleEquivalent(value, type);
+ value = ssa_builder_->GetFloatOrDoubleEquivalent(value, type);
} else if (type == Primitive::kPrimNot) {
- return ssa_builder_->GetReferenceTypeEquivalent(value);
+ value = ssa_builder_->GetReferenceTypeEquivalent(value);
}
+ DCHECK(value != nullptr);
}
return value;
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 8ad79fb..f2ae85a 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4528,7 +4528,7 @@
ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int field_idx) {
const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
- // Check access to class
+ // Check access to class.
const RegType& klass_type = ResolveClassAndCheckAccess(field_id.class_idx_);
if (klass_type.IsConflict()) {
AppendToLastFailMessage(StringPrintf(" in attempt to access instance field %d (%s) in %s",
@@ -4549,20 +4549,11 @@
DCHECK(self_->IsExceptionPending());
self_->ClearException();
return nullptr;
- } else if (!GetDeclaringClass().CanAccessMember(field->GetDeclaringClass(),
- field->GetAccessFlags())) {
- Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot access instance field " << PrettyField(field)
- << " from " << GetDeclaringClass();
- return nullptr;
- } else if (field->IsStatic()) {
- Fail(VERIFY_ERROR_CLASS_CHANGE) << "expected field " << PrettyField(field)
- << " to not be static";
- return nullptr;
} else if (obj_type.IsZero()) {
- // Cannot infer and check type, however, access will cause null pointer exception
- return field;
+ // Cannot infer and check type, however, access will cause null pointer exception.
+ // Fall through into a few last soft failure checks below.
} else if (!obj_type.IsReferenceTypes()) {
- // Trying to read a field from something that isn't a reference
+ // Trying to read a field from something that isn't a reference.
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "instance field access on object that has "
<< "non-reference type " << obj_type;
return nullptr;
@@ -4584,7 +4575,6 @@
<< " of " << PrettyMethod(dex_method_idx_, *dex_file_);
return nullptr;
}
- return field;
} else if (!field_klass.IsAssignableFrom(obj_type)) {
// Trying to access C1.field1 using reference of type C2, which is neither C1 or a sub-class
// of C1. For resolution to occur the declared class of the field must be compatible with
@@ -4602,10 +4592,22 @@
Fail(type) << "cannot access instance field " << PrettyField(field)
<< " from object of type " << obj_type;
return nullptr;
- } else {
- return field;
}
}
+
+ // Few last soft failure checks.
+ if (!GetDeclaringClass().CanAccessMember(field->GetDeclaringClass(),
+ field->GetAccessFlags())) {
+ Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot access instance field " << PrettyField(field)
+ << " from " << GetDeclaringClass();
+ return nullptr;
+ } else if (field->IsStatic()) {
+ Fail(VERIFY_ERROR_CLASS_CHANGE) << "expected field " << PrettyField(field)
+ << " to not be static";
+ return nullptr;
+ }
+
+ return field;
}
template <MethodVerifier::FieldAccessType kAccType>
@@ -4928,6 +4930,7 @@
// Initialize them as conflicts so they don't add to GC and deoptimization information.
const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn);
AdjustReturnLine(this, ret_inst, target_line);
+ // Directly bail if a hard failure was found.
if (have_pending_hard_failure_) {
return false;
}
diff --git a/test/600-verifier-fails/expected.txt b/test/600-verifier-fails/expected.txt
index 010f1b7..8399969 100644
--- a/test/600-verifier-fails/expected.txt
+++ b/test/600-verifier-fails/expected.txt
@@ -1,3 +1,4 @@
passed A
passed B
passed C
+passed D
diff --git a/test/600-verifier-fails/info.txt b/test/600-verifier-fails/info.txt
index 677b477..f77de05 100644
--- a/test/600-verifier-fails/info.txt
+++ b/test/600-verifier-fails/info.txt
@@ -1,14 +1,18 @@
The situations in these tests were discovered by running the mutating
dexfuzz on the DEX files of fuzzingly random generated Java test.
-(1) b/28908555:
- soft verification fail (on the final field modification) should
- not hide the hard verification fail (on the type mismatch) to
+(A) b/28908555:
+ soft verification failure (on the final field modification) should
+ not hide the hard verification failure (on the type mismatch) to
avoid compiler crash later on
-(2) b/29070461:
- hard failure (not calling super in constructor) should bail
- immediately and not allow soft fails to pile up behind it to
- avoid fatal message later on
-(3) b/29068831:
+(B) b/29070461:
+ hard verification failure (not calling super in constructor) should
+ bail immediately and not allow soft verification failures to pile up
+ behind it to avoid fatal message later on
+(C) b/29068831:
access validation should occur prior to null reference check
+(D) b/29126870:
+ soft verification failure (cannot access) should not hide the hard
+ verification failure (non-reference type) to avoid a compiler crash
+ later on
diff --git a/test/600-verifier-fails/smali/iget.smali b/test/600-verifier-fails/smali/iget.smali
new file mode 100644
index 0000000..5c045e6
--- /dev/null
+++ b/test/600-verifier-fails/smali/iget.smali
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LD;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+ .registers 2
+ invoke-direct {v1}, Ljava/lang/Object;-><init>()V
+ const v0, 2
+ iget v1, v0, LMain;->privateField:I
+ return-void
+.end method
diff --git a/test/600-verifier-fails/src/Main.java b/test/600-verifier-fails/src/Main.java
index 0a8c5a1..a6a07fd 100644
--- a/test/600-verifier-fails/src/Main.java
+++ b/test/600-verifier-fails/src/Main.java
@@ -20,6 +20,8 @@
private static String staticPrivateField = null;
+ private int privateField = 0;
+
private static void test(String name) throws Exception {
try {
Class<?> a = Class.forName(name);
@@ -33,5 +35,6 @@
test("A");
test("B");
test("C");
+ test("D");
}
}