Workaround for class loader issues in verifier.

bug: 73760543
bug: 73549918
bug: 64759619

Test: 676-resolve-field-type
Change-Id: Iac30bd2dcfb7266c8ef6f5e283de5b6951ca07bf
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 63d47e6..418c01c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7957,17 +7957,18 @@
     // In case of jmvti, the dex file gets verified before being registered, so first
     // check if it's registered before checking class tables.
     const DexFile& dex_file = *dex_cache->GetDexFile();
-    CHECK(!IsDexFileRegistered(Thread::Current(), dex_file) ||
-          FindClassTable(Thread::Current(), dex_cache) == ClassTableForClassLoader(class_loader))
+    DCHECK(!IsDexFileRegistered(Thread::Current(), dex_file) ||
+           FindClassTable(Thread::Current(), dex_cache) == ClassTableForClassLoader(class_loader))
         << "DexFile referrer: " << dex_file.GetLocation()
         << " ClassLoader: " << DescribeLoaders(class_loader, "");
     // Be a good citizen and update the dex cache to speed subsequent calls.
     dex_cache->SetResolvedMethod(method_idx, resolved, image_pointer_size_);
-    const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
-    DCHECK(LookupResolvedType(method_id.class_idx_, dex_cache, class_loader) != nullptr)
-        << "Method: " << resolved->PrettyMethod() << ", "
-        << "Class: " << klass->PrettyClass() << " (" << klass->GetStatus() << "), "
-        << "DexFile referrer: " << dex_file.GetLocation();
+    // Disable the following invariant check as the verifier breaks it. b/73760543
+    // const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
+    // DCHECK(LookupResolvedType(method_id.class_idx_, dex_cache, class_loader) != nullptr)
+    //    << "Method: " << resolved->PrettyMethod() << ", "
+    //    << "Class: " << klass->PrettyClass() << " (" << klass->GetStatus() << "), "
+    //    << "DexFile referrer: " << dex_file.GetLocation();
   }
   return resolved;
 }
@@ -7999,13 +8000,9 @@
     DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
     klass = LookupResolvedType(method_id.class_idx_, dex_cache.Get(), class_loader.Get());
     if (UNLIKELY(klass == nullptr)) {
-      const char* descriptor = dex_file.StringByTypeIdx(method_id.class_idx_);
-      LOG(FATAL) << "Check failed: klass != nullptr Bug: 64759619 Method: "
-          << resolved->PrettyMethod() << ";" << resolved
-          << "/0x" << std::hex << resolved->GetAccessFlags()
-          << " ReferencedClass: " << descriptor
-          << " DexFile referrer: " << dex_file.GetLocation()
-          << " ClassLoader: " << DescribeLoaders(class_loader.Get(), descriptor);
+      // We normaly should not end up here. However the verifier currently doesn't guarantee
+      // the invariant of having the klass in the class table. b/73760543
+      klass = ResolveType(method_id.class_idx_, dex_cache, class_loader);
     }
   } else {
     // The method was not in the DexCache, resolve the declaring class.
diff --git a/test/676-resolve-field-type/expected.txt b/test/676-resolve-field-type/expected.txt
new file mode 100644
index 0000000..a965a70
--- /dev/null
+++ b/test/676-resolve-field-type/expected.txt
@@ -0,0 +1 @@
+Done
diff --git a/test/676-resolve-field-type/info.txt b/test/676-resolve-field-type/info.txt
new file mode 100644
index 0000000..a53244d
--- /dev/null
+++ b/test/676-resolve-field-type/info.txt
@@ -0,0 +1,2 @@
+Test trying to reproduce class loader issues with the verifier.
+See comments in src-ex/ChildClass.java
diff --git a/test/676-resolve-field-type/src-art/Foo.java b/test/676-resolve-field-type/src-art/Foo.java
new file mode 100644
index 0000000..3df74d3
--- /dev/null
+++ b/test/676-resolve-field-type/src-art/Foo.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 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 Foo {
+  public static Main mainObject;
+}
diff --git a/test/676-resolve-field-type/src-art/Main.java b/test/676-resolve-field-type/src-art/Main.java
new file mode 100644
index 0000000..c915df8
--- /dev/null
+++ b/test/676-resolve-field-type/src-art/Main.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+import dalvik.system.PathClassLoader;
+import java.io.File;
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    ClassLoader parentLoader = Main.class.getClassLoader();
+    ClassLoader childLoader = new PathClassLoader(DEX_CHILD, parentLoader);
+    Class.forName("ChildClass", true, childLoader).getDeclaredMethod("runTest").invoke(null);
+  }
+
+  private static final String DEX_CHILD =
+      new File(System.getenv("DEX_LOCATION"), "676-resolve-field-type-ex.jar").getAbsolutePath();
+
+  public static void staticMethod() {}
+}
diff --git a/test/676-resolve-field-type/src-ex/ChildClass.java b/test/676-resolve-field-type/src-ex/ChildClass.java
new file mode 100644
index 0000000..167d4a6
--- /dev/null
+++ b/test/676-resolve-field-type/src-ex/ChildClass.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public class ChildClass {
+  // This method being synchronized means the SIGQUIT code in ART will call
+  // FindLocksAtDexPc (we check for the presence of try blocks),
+  // which triggered a DCHECK of an invariant.
+  public static synchronized void runTest() throws Exception {
+    Main m = Foo.mainObject;
+
+    SigQuit.doKill();
+
+    // Sleep some time to get the kill while executing this method.
+    Thread.sleep(2);
+
+    // The FindLocksAtDexPc method running with the verifier would fail when
+    // resolving this call, as the verifier didn't register Main from the field
+    // access above with the current class loader.
+    Main.staticMethod();
+    System.out.println("Done");
+  }
+
+  private final static class SigQuit {
+    private final static int sigquit;
+    private final static Method kill;
+    private final static int pid;
+
+    static {
+      int pidTemp = -1;
+      int sigquitTemp = -1;
+      Method killTemp = null;
+
+      try {
+        Class<?> osClass = Class.forName("android.system.Os");
+        Method getpid = osClass.getDeclaredMethod("getpid");
+        pidTemp = (Integer)getpid.invoke(null);
+
+        Class<?> osConstants = Class.forName("android.system.OsConstants");
+        Field sigquitField = osConstants.getDeclaredField("SIGQUIT");
+        sigquitTemp = (Integer)sigquitField.get(null);
+
+        killTemp = osClass.getDeclaredMethod("kill", int.class, int.class);
+      } catch (Exception e) {
+        throw new Error(e);
+      }
+
+      pid = pidTemp;
+      sigquit = sigquitTemp;
+      kill = killTemp;
+    }
+
+    public static void doKill() throws Exception {
+      kill.invoke(null, pid, sigquit);
+    }
+  }
+}