Revert^2 "Throw ClassFormatError for unsupported default methods."

This reverts commit 09261a8c5cd36a8c7a1ae5107da554dd35008b97.

Fixed redefine-stress failures. Worked around CTS failures
by reducing the cases where we throw the ClassFormatError.

Test: 180-native-default-method.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: aosp_taimen-userdebug boots.
Test: testrunner.py --host --optimizing --redefine-stress \
      --debug --debugggable --cdex-fast
Test: cts-tradefed run cts --m vm-tests-tf
Bug: 157170505
Bug: 157718952
Change-Id: I95264af9041836fd6bc54e85263e2a405e877d30
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index 268abe4..7f05ae8 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -794,8 +794,11 @@
   StandardDexFile::Header header;
   if (CompactDexFile::IsMagicValid(header_->Magic())) {
     StandardDexFile::WriteMagic(header.magic_);
-    // TODO: Should we write older versions based on the feature flags?
-    StandardDexFile::WriteCurrentVersion(header.magic_);
+    if (header_->SupportDefaultMethods()) {
+      StandardDexFile::WriteCurrentVersion(header.magic_);
+    } else {
+      StandardDexFile::WriteVersionBeforeDefaultMethods(header.magic_);
+    }
   } else {
     // Standard dex -> standard dex, just reuse the same header.
     static constexpr size_t kMagicAndVersionLen =
diff --git a/libdexfile/dex/standard_dex_file.cc b/libdexfile/dex/standard_dex_file.cc
index 9c4cb45..1f1bc19 100644
--- a/libdexfile/dex/standard_dex_file.cc
+++ b/libdexfile/dex/standard_dex_file.cc
@@ -32,9 +32,9 @@
   {'0', '3', '7', '\0'},
   // Dex version 038: Android "O" and beyond.
   {'0', '3', '8', '\0'},
-  // Dex verion 039: Android "P" and beyond.
+  // Dex version 039: Android "P" and beyond.
   {'0', '3', '9', '\0'},
-  // Dex verion 040: beyond Android "10" (previously known as Android "Q").
+  // Dex version 040: beyond Android "10" (previously known as Android "Q").
   {'0', '4', '0', '\0'},
 };
 
@@ -48,6 +48,11 @@
               magic + kDexMagicSize);
 }
 
+
+void StandardDexFile::WriteVersionBeforeDefaultMethods(uint8_t* magic) {
+  std::copy_n(kDexMagicVersions[0u], kDexVersionLen, magic + kDexMagicSize);
+}
+
 bool StandardDexFile::IsMagicValid(const uint8_t* magic) {
   return (memcmp(magic, kDexMagic, sizeof(kDexMagic)) == 0);
 }
diff --git a/libdexfile/dex/standard_dex_file.h b/libdexfile/dex/standard_dex_file.h
index 3af36f6..25cf62a 100644
--- a/libdexfile/dex/standard_dex_file.h
+++ b/libdexfile/dex/standard_dex_file.h
@@ -83,6 +83,10 @@
   // Write the current version, note that the input is the address of the magic.
   static void WriteCurrentVersion(uint8_t* magic);
 
+  // Write the last version before default method support,
+  // note that the input is the address of the magic.
+  static void WriteVersionBeforeDefaultMethods(uint8_t* magic);
+
   static const uint8_t kDexMagic[kDexMagicSize];
   static constexpr size_t kNumDexVersions = 5;
   static const uint8_t kDexMagicVersions[kNumDexVersions][kDexVersionLen];
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c8d4d63..4b8a94f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -6432,6 +6432,19 @@
       ArtMethod* m = klass->GetVirtualMethodDuringLinking(i, image_pointer_size_);
       m->SetMethodIndex(i);
       if (!m->IsAbstract()) {
+        // If the dex file does not support default methods, throw ClassFormatError.
+        // This check is necessary to protect from odd cases, such as native default
+        // methods, that the dex file verifier permits for old dex file versions. b/157170505
+        // FIXME: This should be `if (!m->GetDexFile()->SupportsDefaultMethods())` but we're
+        // currently running CTS tests for default methods with dex file version 035 which
+        // does not support default methods. So, we limit this to native methods. b/157718952
+        if (m->IsNative()) {
+          DCHECK(!m->GetDexFile()->SupportsDefaultMethods());
+          ThrowClassFormatError(klass.Get(),
+                                "Dex file does not support default method '%s'",
+                                m->PrettyMethod().c_str());
+          return false;
+        }
         m->SetAccessFlags(m->GetAccessFlags() | kAccDefault);
         has_defaults = true;
       }
diff --git a/test/180-native-default-method/build b/test/180-native-default-method/build
new file mode 100644
index 0000000..3963fd3
--- /dev/null
+++ b/test/180-native-default-method/build
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Copyright 2020 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.
+
+# make us exit on a failure
+set -e
+
+./default-build "$@"
+
+if [[ $@ != *"--jvm"* ]]; then
+  # Change the generated dex file to have a v35 magic number if it is version 39
+  if test -f classes.dex && head -c 7 classes.dex | grep -q 039; then
+    # place ascii value '035' into the classes.dex file starting at byte 4.
+    printf '035' | dd status=none conv=notrunc of=classes.dex bs=1 seek=4 count=3
+    rm -f $TEST_NAME.jar
+    zip $TEST_NAME.jar classes.dex
+  fi
+fi
diff --git a/test/180-native-default-method/expected.txt b/test/180-native-default-method/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/180-native-default-method/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/180-native-default-method/info.txt b/test/180-native-default-method/info.txt
new file mode 100644
index 0000000..0cba4eb
--- /dev/null
+++ b/test/180-native-default-method/info.txt
@@ -0,0 +1,3 @@
+Regression test for DCHECK() failure for copying a default native method from
+an interface to a class implementing that interface. The default native method
+should result in ClassFormatError before we reach that DCHECK().
diff --git a/test/180-native-default-method/jasmin/TestClass.j b/test/180-native-default-method/jasmin/TestClass.j
new file mode 100644
index 0000000..fddd99b
--- /dev/null
+++ b/test/180-native-default-method/jasmin/TestClass.j
@@ -0,0 +1,25 @@
+; Copyright (C) 2020 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 TestClass
+.super                   java/lang/Object
+.implements              TestInterface
+
+.method                  public <init>()V
+   .limit stack          1
+   .limit locals         1
+   aload_0
+   invokespecial         java/lang/Object/<init>()V
+   return
+.end method
diff --git a/test/180-native-default-method/jasmin/TestInterface.j b/test/180-native-default-method/jasmin/TestInterface.j
new file mode 100644
index 0000000..080474e
--- /dev/null
+++ b/test/180-native-default-method/jasmin/TestInterface.j
@@ -0,0 +1,19 @@
+; Copyright (C) 2020 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.
+
+.interface               public TestInterface
+.super                   java/lang/Object
+
+.method                  public native foo()V
+.end method
diff --git a/test/180-native-default-method/src/Main.java b/test/180-native-default-method/src/Main.java
new file mode 100644
index 0000000..4b2704b
--- /dev/null
+++ b/test/180-native-default-method/src/Main.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+public class Main {
+  public static void main(String args[]) {
+    try {
+      // Regression test for default native methods that should cause ClassFormatException
+      // if they pass the dex file verification, i.e. for old dex file versions.
+      // We previously did not handle this case properly and failed a DCHECK() for
+      // a non-interface class creating a copied method that was native. b/157170505
+      Class.forName("TestClass");
+      throw new Error("UNREACHABLE");
+    } catch (ClassFormatError expected) {
+      System.out.println("passed");
+    } catch (Throwable unexpected) {
+      unexpected.printStackTrace();
+    }
+  }
+}