From c92a7a14ce44c4bb7e63e4c447a008b558bc0bca Mon Sep 17 00:00:00 2001 From: Jeff Hao Date: Mon, 6 Jun 2016 11:09:20 -0700 Subject: [PATCH] Wrap certain exception types when loading an erroneous class. Bug: 28787733 (cherry-picked from commit 7c8aa8357196781c811a73d2eb66aaaa1681ce36) Change-Id: Iea55486c4b95ee16e1f19c8ba2d24c18b9100c97 --- runtime/class_linker.h | 12 ++++++------ runtime/native/java_lang_VMClassLoader.cc | 17 +++++++++++++++++ runtime/well_known_classes.cc | 6 ++++++ runtime/well_known_classes.h | 3 +++ test/142-classloader2/smali/B.smali | 10 ++++++++++ test/142-classloader2/src/Main.java | 15 +++++++++++++++ 6 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 test/142-classloader2/smali/B.smali diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 0715babdb..cd1ca7f15 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -641,6 +641,12 @@ class ClassLinker { REQUIRES(!Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + // Throw the class initialization failure recorded when first trying to initialize the given + // class. + void ThrowEarlierClassFailure(mirror::Class* c, bool wrap_in_no_class_def = false) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); + struct DexCacheData { // Weak root to the DexCache. Note: Do not decode this unnecessarily or else class unloading may // not work properly. @@ -1057,12 +1063,6 @@ class ClassLinker { // Return the quick generic JNI stub for testing. const void* GetRuntimeQuickGenericJniStub() const; - // Throw the class initialization failure recorded when first trying to initialize the given - // class. - void ThrowEarlierClassFailure(mirror::Class* c, bool wrap_in_no_class_def = false) - SHARED_REQUIRES(Locks::mutator_lock_) - REQUIRES(!dex_lock_); - bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics, bool can_init_parents) SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc index 15156301c..6f735aa6d 100644 --- a/runtime/native/java_lang_VMClassLoader.cc +++ b/runtime/native/java_lang_VMClassLoader.cc @@ -41,6 +41,23 @@ static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoa if (c != nullptr && c->IsResolved()) { return soa.AddLocalReference(c); } + // If class is erroneous, throw the earlier failure, wrapped in certain cases. See b/28787733. + if (c != nullptr && c->IsErroneous()) { + cl->ThrowEarlierClassFailure(c); + Thread* self = soa.Self(); + mirror::Class* eiie_class = + self->DecodeJObject(WellKnownClasses::java_lang_ExceptionInInitializerError)->AsClass(); + mirror::Class* iae_class = + self->DecodeJObject(WellKnownClasses::java_lang_IllegalAccessError)->AsClass(); + mirror::Class* ncdfe_class = + self->DecodeJObject(WellKnownClasses::java_lang_NoClassDefFoundError)->AsClass(); + mirror::Class* exception = self->GetException()->GetClass(); + if (exception == eiie_class || exception == iae_class || exception == ncdfe_class) { + self->ThrowNewWrappedException("Ljava/lang/ClassNotFoundException;", + PrettyDescriptor(c).c_str()); + } + return nullptr; + } if (loader != nullptr) { // Try the common case. StackHandleScope<1> hs(soa.Self()); diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index d28894352..355d552b0 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -41,6 +41,9 @@ jclass WellKnownClasses::java_lang_ClassLoader; jclass WellKnownClasses::java_lang_ClassNotFoundException; jclass WellKnownClasses::java_lang_Daemons; jclass WellKnownClasses::java_lang_Error; +jclass WellKnownClasses::java_lang_ExceptionInInitializerError; +jclass WellKnownClasses::java_lang_IllegalAccessError; +jclass WellKnownClasses::java_lang_NoClassDefFoundError; jclass WellKnownClasses::java_lang_Object; jclass WellKnownClasses::java_lang_OutOfMemoryError; jclass WellKnownClasses::java_lang_reflect_AbstractMethod; @@ -228,6 +231,9 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_Object = CacheClass(env, "java/lang/Object"); java_lang_OutOfMemoryError = CacheClass(env, "java/lang/OutOfMemoryError"); java_lang_Error = CacheClass(env, "java/lang/Error"); + java_lang_ExceptionInInitializerError = CacheClass(env, "java/lang/ExceptionInInitializerError"); + java_lang_IllegalAccessError = CacheClass(env, "java/lang/IllegalAccessError"); + java_lang_NoClassDefFoundError = CacheClass(env, "java/lang/NoClassDefFoundError"); java_lang_reflect_AbstractMethod = CacheClass(env, "java/lang/reflect/AbstractMethod"); java_lang_reflect_Constructor = CacheClass(env, "java/lang/reflect/Constructor"); java_lang_reflect_Field = CacheClass(env, "java/lang/reflect/Field"); diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index 482ff0a8f..cc60b4d89 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -52,6 +52,9 @@ struct WellKnownClasses { static jclass java_lang_ClassNotFoundException; static jclass java_lang_Daemons; static jclass java_lang_Error; + static jclass java_lang_ExceptionInInitializerError; + static jclass java_lang_IllegalAccessError; + static jclass java_lang_NoClassDefFoundError; static jclass java_lang_Object; static jclass java_lang_OutOfMemoryError; static jclass java_lang_reflect_AbstractMethod; diff --git a/test/142-classloader2/smali/B.smali b/test/142-classloader2/smali/B.smali new file mode 100644 index 000000000..01bd593e0 --- /dev/null +++ b/test/142-classloader2/smali/B.smali @@ -0,0 +1,10 @@ +.class public LB; + +.super Ljava/lang/Object; + +.method public constructor ()V + .registers 1 + invoke-direct {p1}, Ljava/lang/Object;->()V + return-void +.end method + diff --git a/test/142-classloader2/src/Main.java b/test/142-classloader2/src/Main.java index 86c61ebc3..89dadcee6 100644 --- a/test/142-classloader2/src/Main.java +++ b/test/142-classloader2/src/Main.java @@ -71,6 +71,21 @@ public class Main { throw new IllegalStateException("Expected Ex-A, found " + exValue); } + // Try to load a dex file with bad dex code. Use new instance to force verification. + try { + Class badClass = Main.class.getClassLoader().loadClass("B"); + badClass.newInstance(); + System.out.println("Should not be able to load class from bad dex file."); + } catch (VerifyError e) { + } + + // Make sure the same error is rethrown when reloading the bad class. + try { + Class badClass = Main.class.getClassLoader().loadClass("B"); + System.out.println("Should not be able to load class from bad dex file."); + } catch (VerifyError e) { + } + System.out.println("Everything OK."); } } -- 2.11.0