ART: Allow to set and copy conflicts in the verifier
As long as conflicts are not actively being used, it is OK to set
them in a register line or copy them around.
Bug: 22331663
(cherry picked from commit 38536287f61c9c0fc3bab8c1950cf8c74881482a)
Change-Id: I61999e2d9c92f9bdedcb0a5dea54df3c5bb130ca
diff --git a/runtime/verifier/register_line-inl.h b/runtime/verifier/register_line-inl.h
index 244deed..9cd2bdf 100644
--- a/runtime/verifier/register_line-inl.h
+++ b/runtime/verifier/register_line-inl.h
@@ -38,10 +38,9 @@
verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Expected category1 register type not '"
<< new_type << "'";
return false;
- } else if (new_type.IsConflict()) { // should only be set during a merge
- verifier->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Set register to unknown type " << new_type;
- return false;
} else {
+ // Note: previously we failed when asked to set a conflict. However, conflicts are OK as long
+ // as they are not accessed, and our backends can handle this nowadays.
line_[vdst] = new_type.GetId();
}
// Clear the monitor entry bits for this register.
@@ -93,8 +92,9 @@
if (!SetRegisterType(verifier, vdst, type)) {
return;
}
- if ((cat == kTypeCategory1nr && !type.IsCategory1Types()) ||
- (cat == kTypeCategoryRef && !type.IsReferenceTypes())) {
+ if (!type.IsConflict() && // Allow conflicts to be copied around.
+ ((cat == kTypeCategory1nr && !type.IsCategory1Types()) ||
+ (cat == kTypeCategoryRef && !type.IsReferenceTypes()))) {
verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "copy1 v" << vdst << "<-v" << vsrc << " type=" << type
<< " cat=" << static_cast<int>(cat);
} else if (cat == kTypeCategoryRef) {
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index c32bfc2..aa997a6 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -24,4 +24,5 @@
b/22080519
b/21645819
b/22244733
+b/22331663
Done!
diff --git a/test/800-smali/smali/b_22331663.smali b/test/800-smali/smali/b_22331663.smali
new file mode 100644
index 0000000..af99152
--- /dev/null
+++ b/test/800-smali/smali/b_22331663.smali
@@ -0,0 +1,35 @@
+.class public LB22331663;
+.super Ljava/lang/Object;
+
+
+.method public static run(Z)V
+.registers 6
+ if-eqz v5, :Label2
+
+:Label1
+ # Construct a java.lang.Object completely, and throw a new exception.
+ new-instance v4, Ljava/lang/Object;
+ invoke-direct {v4}, Ljava/lang/Object;-><init>()V
+
+ new-instance v3, Ljava/lang/RuntimeException;
+ invoke-direct {v3}, Ljava/lang/RuntimeException;-><init>()V
+ throw v3
+
+:Label2
+ # Allocate a java.lang.Object (do not initialize), and throw a new exception.
+ new-instance v4, Ljava/lang/Object;
+
+ new-instance v3, Ljava/lang/RuntimeException;
+ invoke-direct {v3}, Ljava/lang/RuntimeException;-><init>()V
+ throw v3
+
+:Label3
+ # Catch handler. Here we had to merge the uninitialized with the initialized reference,
+ # which creates a conflict. Copy the conflict, and then return. This should not make the
+ # verifier fail the method.
+ move-object v0, v4
+
+ return-void
+
+.catchall {:Label1 .. :Label3} :Label3
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index a7f30d0..e0872c3 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -95,6 +95,8 @@
null, null));
testCases.add(new TestCase("b/22244733", "B22244733", "run", new Object[] { "abc" },
null, "abc"));
+ testCases.add(new TestCase("b/22331663", "B22331663", "run", new Object[] { false },
+ null, null));
}
public void runTests() {