ART: Relax verifier aput checking

When checking on a null array, the cases of aput and aput-wide are
shared between integral and floating point types. Be careful to not
reject a valid program.

Bug: 21867457
Bug: 23201502
Change-Id: I6c54a389c06e40a2dae00995aa16ff08a089e512
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 1661534..5bcf260 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3938,7 +3938,24 @@
     if (array_type.IsZero()) {
       // Null array type; this code path will fail at runtime.
       // Still check that the given value matches the instruction's type.
-      work_line_->VerifyRegisterType(this, inst->VRegA_23x(), insn_type);
+      // Note: this is, as usual, complicated by the fact the the instruction isn't fully typed
+      //       and fits multiple register types.
+      const RegType* modified_reg_type = &insn_type;
+      if ((modified_reg_type == &reg_types_.Integer()) ||
+          (modified_reg_type == &reg_types_.LongLo())) {
+        // May be integer or float | long or double. Overwrite insn_type accordingly.
+        const RegType& value_type = work_line_->GetRegisterType(this, inst->VRegA_23x());
+        if (modified_reg_type == &reg_types_.Integer()) {
+          if (&value_type == &reg_types_.Float()) {
+            modified_reg_type = &value_type;
+          }
+        } else {
+          if (&value_type == &reg_types_.DoubleLo()) {
+            modified_reg_type = &value_type;
+          }
+        }
+      }
+      work_line_->VerifyRegisterType(this, inst->VRegA_23x(), *modified_reg_type);
     } else if (!array_type.IsArrayTypes()) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "not array type " << array_type << " with aput";
     } else {
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index e2101a6..dd37cdb 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -39,4 +39,6 @@
 b/22777307
 b/22881413
 b/20843113
+b/23201502 (float)
+b/23201502 (double)
 Done!
diff --git a/test/800-smali/smali/b_23201502.smali b/test/800-smali/smali/b_23201502.smali
new file mode 100644
index 0000000..d958938
--- /dev/null
+++ b/test/800-smali/smali/b_23201502.smali
@@ -0,0 +1,23 @@
+.class public LB23201502;
+
+.super Ljava/lang/Object;
+
+.method public static runFloat()V
+   .registers 3
+   const v0, 0             # Null array.
+   const v1, 0             # 0 index into array.
+   const v2, 0             # 0 value, will be turned into float.
+   int-to-float v2, v2     # Definitely make v2 float.
+   aput v2 , v0, v1        # Put into null array.
+   return-void
+.end method
+
+.method public static runDouble()V
+   .registers 4
+   const v0, 0             # Null array.
+   const v1, 0             # 0 index into array.
+   const v2, 0             # 0 value, will be turned into double.
+   int-to-double v2, v2    # Definitely make v2+v3 double.
+   aput-wide v2 , v0, v1   # Put into null array.
+   return-void
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 3c88040..b481a1d 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -123,6 +123,10 @@
                 null));
         testCases.add(new TestCase("b/22881413", "B22881413", "run", null, null, null));
         testCases.add(new TestCase("b/20843113", "B20843113", "run", null, null, null));
+        testCases.add(new TestCase("b/23201502 (float)", "B23201502", "runFloat", null,
+                new NullPointerException(), null));
+        testCases.add(new TestCase("b/23201502 (double)", "B23201502", "runDouble", null,
+                new NullPointerException(), null));
     }
 
     public void runTests() {