diff options
| -rw-r--r-- | compiler/driver/compiler_driver.cc | 15 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 11 | ||||
| -rw-r--r-- | runtime/class_linker.h | 6 | ||||
| -rw-r--r-- | runtime/generated/asm_support_gen.h | 2 | ||||
| -rw-r--r-- | runtime/mirror/class.h | 7 | ||||
| -rw-r--r-- | runtime/oat.h | 4 | ||||
| -rw-r--r-- | runtime/oat_file_assistant_test.cc | 7 | ||||
| -rw-r--r-- | runtime/oat_file_manager.cc | 5 | ||||
| -rw-r--r-- | test/138-duplicate-classes-check2/src/FancyLoader.java | 228 | ||||
| -rw-r--r-- | test/138-duplicate-classes-check2/src/Main.java | 37 |
10 files changed, 70 insertions, 252 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index c04e45d334..ff92ac43b8 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -2246,7 +2246,7 @@ class InitializeClassVisitor : public CompilationVisitor { const bool is_boot_image = manager_->GetCompiler()->GetCompilerOptions().IsBootImage(); const bool is_app_image = manager_->GetCompiler()->GetCompilerOptions().IsAppImage(); - mirror::Class::Status old_status = klass->GetStatus();; + mirror::Class::Status old_status = klass->GetStatus(); // Only try to initialize classes that were successfully verified. if (klass->IsVerified()) { // Don't initialize classes in boot space when compiling app image @@ -2364,6 +2364,14 @@ class InitializeClassVisitor : public CompilationVisitor { } } } + // If the class still isn't initialized, at least try some checks that initialization + // would do so they can be skipped at runtime. + if (!klass->IsInitialized() && + manager_->GetClassLinker()->ValidateSuperClassDescriptors(klass)) { + old_status = mirror::Class::kStatusSuperclassValidated; + } else { + soa.Self()->ClearException(); + } soa.Self()->AssertNoPendingException(); } } @@ -2861,13 +2869,14 @@ bool CompilerDriver::GetCompiledClass(ClassReference ref, mirror::Class::Status* void CompilerDriver::RecordClassStatus(ClassReference ref, mirror::Class::Status status) { switch (status) { - case mirror::Class::kStatusNotReady: case mirror::Class::kStatusErrorResolved: case mirror::Class::kStatusErrorUnresolved: + case mirror::Class::kStatusNotReady: + case mirror::Class::kStatusResolved: case mirror::Class::kStatusRetryVerificationAtRuntime: case mirror::Class::kStatusVerified: + case mirror::Class::kStatusSuperclassValidated: case mirror::Class::kStatusInitialized: - case mirror::Class::kStatusResolved: break; // Expected states. default: LOG(FATAL) << "Unexpected class status for class " diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index a5d4540f88..1c3375c93a 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -4405,8 +4405,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, uint16_t class_def_index = klass->GetDexClassDefIndex(); oat_file_class_status = oat_dex_file->GetOatClass(class_def_index).GetStatus(); - if (oat_file_class_status == mirror::Class::kStatusVerified || - oat_file_class_status == mirror::Class::kStatusInitialized) { + if (oat_file_class_status >= mirror::Class::kStatusVerified) { return true; } // If we only verified a subset of the classes at compile time, we can end up with classes that @@ -4885,7 +4884,13 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, return WaitForInitializeClass(klass, self, lock); } - if (!ValidateSuperClassDescriptors(klass)) { + bool has_oat_class = false; + const OatFile::OatClass oat_class = + (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler()) + ? OatFile::FindOatClass(klass->GetDexFile(), klass->GetDexClassDefIndex(), &has_oat_class) + : OatFile::OatClass::Invalid(); + if (oat_class.GetStatus() < mirror::Class::kStatusSuperclassValidated && + !ValidateSuperClassDescriptors(klass)) { mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); return false; } diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 8b8a6fd420..864d37fa89 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -675,6 +675,10 @@ class ClassLinker { void VisitClassLoaders(ClassLoaderVisitor* visitor) const REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_); + // Checks that a class and its superclass from another class loader have the same virtual methods. + bool ValidateSuperClassDescriptors(Handle<mirror::Class> klass) + REQUIRES_SHARED(Locks::mutator_lock_); + struct DexCacheData { // Construct an invalid data object. DexCacheData() @@ -907,8 +911,6 @@ class ClassLinker { bool WaitForInitializeClass(Handle<mirror::Class> klass, Thread* self, ObjectLock<mirror::Class>& lock); - bool ValidateSuperClassDescriptors(Handle<mirror::Class> klass) - REQUIRES_SHARED(Locks::mutator_lock_); bool IsSameDescriptorInDifferentClassContexts(Thread* self, const char* descriptor, diff --git a/runtime/generated/asm_support_gen.h b/runtime/generated/asm_support_gen.h index 3a7f21de67..06e4704c1c 100644 --- a/runtime/generated/asm_support_gen.h +++ b/runtime/generated/asm_support_gen.h @@ -48,7 +48,7 @@ DEFINE_CHECK_EQ(static_cast<int32_t>(CODEITEM_INSNS_OFFSET), (static_cast<int32_ DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_OBJECT_CLASS_OFFSET), (static_cast<int32_t>(art::mirror::Object:: ClassOffset().Int32Value()))) #define MIRROR_OBJECT_LOCK_WORD_OFFSET 4 DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_OBJECT_LOCK_WORD_OFFSET), (static_cast<int32_t>(art::mirror::Object:: MonitorOffset().Int32Value()))) -#define MIRROR_CLASS_STATUS_INITIALIZED 0xa +#define MIRROR_CLASS_STATUS_INITIALIZED 0xb DEFINE_CHECK_EQ(static_cast<uint32_t>(MIRROR_CLASS_STATUS_INITIALIZED), (static_cast<uint32_t>((art::mirror::Class::kStatusInitialized)))) #define ACCESS_FLAGS_CLASS_IS_FINALIZABLE 0x80000000 DEFINE_CHECK_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE), (static_cast<uint32_t>((art::kAccClassIsFinalizable)))) diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index b60ddcf60c..e516a0636b 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -138,9 +138,10 @@ class MANAGED Class FINAL : public Object { kStatusRetryVerificationAtRuntime = 6, // Compile time verification failed, retry at runtime. kStatusVerifyingAtRuntime = 7, // Retrying verification at runtime. kStatusVerified = 8, // Logically part of linking; done pre-init. - kStatusInitializing = 9, // Class init in progress. - kStatusInitialized = 10, // Ready to go. - kStatusMax = 11, + kStatusSuperclassValidated = 9, // Superclass validation part of init done. + kStatusInitializing = 10, // Class init in progress. + kStatusInitialized = 11, // Ready to go. + kStatusMax = 12, }; template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> diff --git a/runtime/oat.h b/runtime/oat.h index 5e61907d82..f4edb16bce 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,8 +32,8 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - // Last oat version changed reason: update classpath key format. - static constexpr uint8_t kOatVersion[] = { '1', '2', '8', '\0' }; + // Last oat version changed reason: add new class status to skip superclass validation. + static constexpr uint8_t kOatVersion[] = { '1', '2', '9', '\0' }; static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 3619129718..1ecdd0d77e 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -23,6 +23,7 @@ #include "art_field-inl.h" #include "class_linker-inl.h" +#include "common_runtime_test.h" #include "dexopt_test.h" #include "oat_file_assistant.h" #include "oat_file_manager.h" @@ -1059,7 +1060,7 @@ class RaceGenerateTask : public Task { const OatFile* oat_file = nullptr; dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat( dex_location_.c_str(), - /*class_loader*/nullptr, + Runtime::Current()->GetSystemClassLoader(), /*dex_elements*/nullptr, &oat_file, &error_msgs); @@ -1089,6 +1090,10 @@ TEST_F(OatFileAssistantTest, RaceToGenerate) { std::string dex_location = GetScratchDir() + "/RaceToGenerate.jar"; std::string oat_location = GetOdexDir() + "/RaceToGenerate.oat"; + // Start the runtime to initialize the system's class loader. + Thread::Current()->TransitionFromSuspendedToRunnable(); + runtime_->Start(); + // We use the lib core dex file, because it's large, and hopefully should // take a while to generate. Copy(GetLibCoreDexFileNames()[0], dex_location); diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index b166961795..dc542d46d9 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -665,7 +665,10 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( // Get the oat file on disk. std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release()); - if (oat_file != nullptr) { + // Prevent oat files from being loaded if no class_loader or dex_elements are provided. + // This can happen when the deprecated DexFile.<init>(String) is called directly, and it + // could load oat files without checking the classpath, which would be incorrect. + if ((class_loader != nullptr || dex_elements != nullptr) && oat_file != nullptr) { // Take the file only if it has no collisions, or we must take it because of preopting. bool accept_oat_file = !HasCollisions(oat_file.get(), class_loader, dex_elements, /*out*/ &error_msg); diff --git a/test/138-duplicate-classes-check2/src/FancyLoader.java b/test/138-duplicate-classes-check2/src/FancyLoader.java deleted file mode 100644 index 58b7ec49d3..0000000000 --- a/test/138-duplicate-classes-check2/src/FancyLoader.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2008 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.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; - -/** - * A class loader with atypical behavior: we try to load a private - * class implementation before asking the system or boot loader. This - * is used to create multiple classes with identical names in a single VM. - * - * If DexFile is available, we use that; if not, we assume we're not in - * Dalvik and instantiate the class with defineClass(). - * - * The location of the DEX files and class data is dependent upon the - * test framework. - */ -public class FancyLoader extends ClassLoader { - /* this is where the "alternate" .class files live */ - static final String CLASS_PATH = "classes-ex/"; - - /* this is the "alternate" DEX/Jar file */ - static final String DEX_FILE = System.getenv("DEX_LOCATION") + - "/138-duplicate-classes-check2-ex.jar"; - - /* on Dalvik, this is a DexFile; otherwise, it's null */ - private Class<?> mDexClass; - - private Object mDexFile; - - /** - * Construct FancyLoader, grabbing a reference to the DexFile class - * if we're running under Dalvik. - */ - public FancyLoader(ClassLoader parent) { - super(parent); - - try { - mDexClass = parent.loadClass("dalvik.system.DexFile"); - } catch (ClassNotFoundException cnfe) { - // ignore -- not running Dalvik - } - } - - /** - * Finds the class with the specified binary name. - * - * We search for a file in CLASS_PATH or pull an entry from DEX_FILE. - * If we don't find a match, we throw an exception. - */ - protected Class<?> findClass(String name) throws ClassNotFoundException - { - if (mDexClass != null) { - return findClassDalvik(name); - } else { - return findClassNonDalvik(name); - } - } - - /** - * Finds the class with the specified binary name, from a DEX file. - */ - private Class<?> findClassDalvik(String name) - throws ClassNotFoundException { - - if (mDexFile == null) { - synchronized (FancyLoader.class) { - Constructor<?> ctor; - /* - * Construct a DexFile object through reflection. - */ - try { - ctor = mDexClass.getConstructor(String.class); - } catch (NoSuchMethodException nsme) { - throw new ClassNotFoundException("getConstructor failed", - nsme); - } - - try { - mDexFile = ctor.newInstance(DEX_FILE); - } catch (InstantiationException ie) { - throw new ClassNotFoundException("newInstance failed", ie); - } catch (IllegalAccessException iae) { - throw new ClassNotFoundException("newInstance failed", iae); - } catch (InvocationTargetException ite) { - throw new ClassNotFoundException("newInstance failed", ite); - } - } - } - - /* - * Call DexFile.loadClass(String, ClassLoader). - */ - Method meth; - - try { - meth = mDexClass.getMethod("loadClass", String.class, ClassLoader.class); - } catch (NoSuchMethodException nsme) { - throw new ClassNotFoundException("getMethod failed", nsme); - } - - try { - meth.invoke(mDexFile, name, this); - } catch (IllegalAccessException iae) { - throw new ClassNotFoundException("loadClass failed", iae); - } catch (InvocationTargetException ite) { - throw new ClassNotFoundException("loadClass failed", - ite.getCause()); - } - - return null; - } - - /** - * Finds the class with the specified binary name, from .class files. - */ - private Class<?> findClassNonDalvik(String name) - throws ClassNotFoundException { - - String pathName = CLASS_PATH + name + ".class"; - //System.out.println("--- Fancy: looking for " + pathName); - - File path = new File(pathName); - RandomAccessFile raf; - - try { - raf = new RandomAccessFile(path, "r"); - } catch (FileNotFoundException fnfe) { - throw new ClassNotFoundException("Not found: " + pathName); - } - - /* read the entire file in */ - byte[] fileData; - try { - fileData = new byte[(int) raf.length()]; - raf.readFully(fileData); - } catch (IOException ioe) { - throw new ClassNotFoundException("Read error: " + pathName); - } finally { - try { - raf.close(); - } catch (IOException ioe) { - // drop - } - } - - /* create the class */ - //System.out.println("--- Fancy: defining " + name); - try { - return defineClass(name, fileData, 0, fileData.length); - } catch (Throwable th) { - throw new ClassNotFoundException("defineClass failed", th); - } - } - - /** - * Load a class. - * - * Normally a class loader wouldn't override this, but we want our - * version of the class to take precedence over an already-loaded - * version. - * - * We still want the system classes (e.g. java.lang.Object) from the - * bootstrap class loader. - */ - protected Class<?> loadClass(String name, boolean resolve) - throws ClassNotFoundException - { - Class<?> res; - - /* - * 1. Invoke findLoadedClass(String) to check if the class has - * already been loaded. - * - * This doesn't change. - */ - res = findLoadedClass(name); - if (res != null) { - System.out.println("FancyLoader.loadClass: " - + name + " already loaded"); - if (resolve) - resolveClass(res); - return res; - } - - /* - * 3. Invoke the findClass(String) method to find the class. - */ - try { - res = findClass(name); - if (resolve) - resolveClass(res); - } - catch (ClassNotFoundException e) { - // we couldn't find it, so eat the exception and keep going - } - - /* - * 2. Invoke the loadClass method on the parent class loader. If - * the parent loader is null the class loader built-in to the - * virtual machine is used, instead. - * - * (Since we're not in java.lang, we can't actually invoke the - * parent's loadClass() method, but we passed our parent to the - * super-class which can take care of it for us.) - */ - res = super.loadClass(name, resolve); // returns class or throws - return res; - } -} diff --git a/test/138-duplicate-classes-check2/src/Main.java b/test/138-duplicate-classes-check2/src/Main.java index faf8b5d337..588e5eb4f5 100644 --- a/test/138-duplicate-classes-check2/src/Main.java +++ b/test/138-duplicate-classes-check2/src/Main.java @@ -15,12 +15,30 @@ */ import java.io.File; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; /** * Structural hazard test. */ public class Main { + public static String TEST_NAME = "138-duplicate-classes-check2"; + + public static ClassLoader getClassLoaderFor(String location) throws Exception { + try { + Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader"); + Constructor<?> ctor = + class_loader_class.getConstructor(String.class, ClassLoader.class); + /* on Dalvik, this is a DexFile; otherwise, it's null */ + return (ClassLoader) ctor.newInstance(location + "/" + TEST_NAME + "-ex.jar", + Main.class.getClassLoader()); + } catch (ClassNotFoundException e) { + // Running on RI. Use URLClassLoader. + return new java.net.URLClassLoader( + new java.net.URL[] { new java.net.URL("file://" + location + "/classes-ex/") }); + } + } + public static void main(String[] args) { new Main().run(); } @@ -29,15 +47,18 @@ public class Main { System.out.println(new A().i); // Now run the class from the -ex file. - - FancyLoader loader = new FancyLoader(getClass().getClassLoader()); - try { - Class<?> testEx = loader.loadClass("TestEx"); - Method test = testEx.getDeclaredMethod("test"); - test.invoke(null); - } catch (Exception exc) { - exc.printStackTrace(System.out); + /* this is the "alternate" DEX/Jar file */ + ClassLoader new_loader = getClassLoaderFor(System.getenv("DEX_LOCATION")); + Class<?> klass = (Class<?>) new_loader.loadClass("TestEx"); + if (klass == null) { + throw new AssertionError("loadClass failed"); + } + Method run_test = klass.getMethod("test"); + run_test.invoke(null); + } catch (Exception e) { + System.out.println(e.toString()); + e.printStackTrace(System.out); } } } |