ART: Correctly hard-fail method with undefined register

In case a return-object gets an undefined return value register
and an unresolved return type, the "undefined" must take precedence
and lead to a hard fail of the method.

Bug: 22045582
Change-Id: Id5595a72331cd6272aa9ebc8ff3b9cea046294a2
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 5d685da..3c808de 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -1790,9 +1790,13 @@
           DCHECK(!return_type.IsUninitializedReference());
           const uint32_t vregA = inst->VRegA_11x();
           const RegType& reg_type = work_line_->GetRegisterType(this, vregA);
-          // Disallow returning uninitialized values and verify that the reference in vAA is an
-          // instance of the "return_type"
-          if (reg_type.IsUninitializedTypes()) {
+          // Disallow returning undefined, conflict & uninitialized values and verify that the
+          // reference in vAA is an instance of the "return_type."
+          if (reg_type.IsUndefined()) {
+            Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning undefined register";
+          } else if (reg_type.IsConflict()) {
+            Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning register with conflict";
+          } else if (reg_type.IsUninitializedTypes()) {
             Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "returning uninitialized object '"
                                               << reg_type << "'";
           } else if (!return_type.IsAssignableFrom(reg_type)) {
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index c762603..9413c13 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -21,4 +21,7 @@
 b/21873167
 b/21614284
 b/21902684
+b/22045582
+b/22045582 (int)
+b/22045582 (wide)
 Done!
diff --git a/test/800-smali/smali/b_22045582.smali b/test/800-smali/smali/b_22045582.smali
new file mode 100644
index 0000000..3cb661a
--- /dev/null
+++ b/test/800-smali/smali/b_22045582.smali
@@ -0,0 +1,13 @@
+.class public LB22045582;
+
+# Fail verification of a method that returns an undefined register even if the return type
+# is unresolved.
+
+.super Ljava/lang/Object;
+
+.method public static run()La/b/c/d/e/nonexistant;
+    .registers 4
+    # v1 is undefined, and the return type cannot be resolved. The Undefined should take
+    # precedence here.
+    return-object v1
+.end method
diff --git a/test/800-smali/smali/b_22045582_int.smali b/test/800-smali/smali/b_22045582_int.smali
new file mode 100644
index 0000000..c79bb30
--- /dev/null
+++ b/test/800-smali/smali/b_22045582_int.smali
@@ -0,0 +1,11 @@
+.class public LB22045582Int;
+
+# Fail verification of a method that returns an undefined integral register.
+
+.super Ljava/lang/Object;
+
+.method public static run()I
+    .registers 4
+    # v1 is undefined here.
+    return v1
+.end method
diff --git a/test/800-smali/smali/b_22045582_wide.smali b/test/800-smali/smali/b_22045582_wide.smali
new file mode 100644
index 0000000..1485000
--- /dev/null
+++ b/test/800-smali/smali/b_22045582_wide.smali
@@ -0,0 +1,11 @@
+.class public LB22045582Wide;
+
+# Fail verification of a method that returns an undefined wide register.
+
+.super Ljava/lang/Object;
+
+.method public static run()J
+    .registers 4
+    # v0/v1 is undefined here.
+    return-wide v0
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 7280d45..28954f8 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -89,6 +89,12 @@
         testCases.add(new TestCase("b/21614284", "B21614284", "test", new Object[] { null },
             new NullPointerException(), null));
         testCases.add(new TestCase("b/21902684", "B21902684", "test", null, null, null));
+        testCases.add(new TestCase("b/22045582", "B22045582", "run", null, new VerifyError(),
+                0));
+        testCases.add(new TestCase("b/22045582 (int)", "B22045582Int", "run", null,
+                new VerifyError(), 0));
+        testCases.add(new TestCase("b/22045582 (wide)", "B22045582Wide", "run", null,
+                new VerifyError(), 0));
     }
 
     public void runTests() {