ART: Fix RegTypeCache for instance field declaring class
For bytecode instruction:
iget(-*) ClassB->field:type
where the resolved field is actually declared in ClassA (ClassB
extends ClassA), MethodVerifier would create a RegType representing
ClassA but cache it under the descriptor "ClassB".
This is a bug but does not have any implications on correctness
because earlier resolution of ClassB (part of IGET handling) creates
another cache entry with the "ClassB" descriptor. Because the latter,
wrong entry is always imprecise (ClassA cannot be final because ClassB
extends it), either the earlier entry will be discovered or neither
of them will be a match.
Descriptor was replaced with the correct one and a DCHECK added when
creating a RegType to make sure the descriptor matches.
Bug: 30458218
Change-Id: I19e1bdd5dd79e5eac558122a06b9128d0a5c021f
Test: m test-art-host-run-test
Test: art/test/run-test --host 800-smali
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index f2ae85a..7d058f5 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4558,10 +4558,10 @@
<< "non-reference type " << obj_type;
return nullptr;
} else {
+ std::string temp;
mirror::Class* klass = field->GetDeclaringClass();
const RegType& field_klass =
- FromClass(dex_file_->GetFieldDeclaringClassDescriptor(field_id),
- klass, klass->CannotBeAssignedFromOtherTypes());
+ FromClass(klass->GetDescriptor(&temp), klass, klass->CannotBeAssignedFromOtherTypes());
if (obj_type.IsUninitializedTypes()) {
// Field accesses through uninitialized references are only allowable for constructors where
// the field is declared in this class.
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 308c2aa..85daba9 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -773,6 +773,8 @@
}
if (!klass_.IsNull()) {
CHECK(!descriptor_.empty()) << *this;
+ std::string temp;
+ CHECK_EQ(descriptor_.ToString(), klass_.Read()->GetDescriptor(&temp)) << *this;
}
}
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index 8473e06..3bb3725 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -69,4 +69,5 @@
b/28187158
b/29778499 (1)
b/29778499 (2)
+b/30458218
Done!
diff --git a/test/800-smali/smali/B30458218.smali b/test/800-smali/smali/B30458218.smali
new file mode 100644
index 0000000..67b882a
--- /dev/null
+++ b/test/800-smali/smali/B30458218.smali
@@ -0,0 +1,27 @@
+# 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 LB30458218;
+.super Ljava/io/InterruptedIOException;
+
+.method public static run()V
+ .registers 2
+ new-instance v0, LB30458218;
+ invoke-direct {v0}, LB30458218;-><init>()V
+
+ # IGET used to wrongly cache 'InterruptedIOException' class under the key 'LB30458218;'
+ iget v1, v0, LB30458218;->bytesTransferred:I
+
+ return-void
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index bf50879..34f2580 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -180,6 +180,7 @@
new IncompatibleClassChangeError(), null));
testCases.add(new TestCase("b/29778499 (2)", "B29778499_2", "run", null,
new IncompatibleClassChangeError(), null));
+ testCases.add(new TestCase("b/30458218", "B30458218", "run", null, null, null));
}
public void runTests() {