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);
+ }
+ }
+}