diff options
author | 2012-01-30 01:49:33 -0800 | |
---|---|---|
committer | 2012-01-31 12:01:50 -0800 | |
commit | 4d9716c19cc25911e639272048abd0d6702bb082 (patch) | |
tree | fdd9d47f7ebb3bcbb19224a34eb7216f3d212821 | |
parent | 0f09676a8f61809c474e71b4a677093615bfba19 (diff) |
Class::SetStatus(kStatusError) now checks that an exception is pending and uses it to SetVerifyErrorClass
Change-Id: I02f4adc51ac6da88d4969655fa828f93941c4c0a
-rw-r--r-- | src/class_linker.cc | 37 | ||||
-rw-r--r-- | src/object.cc | 24 | ||||
-rw-r--r-- | src/object.h | 9 | ||||
-rw-r--r-- | test/068-classloader/src/FancyLoader.java | 6 | ||||
-rw-r--r-- | test/068-classloader/src/Main.java | 4 |
5 files changed, 52 insertions, 28 deletions
diff --git a/src/class_linker.cc b/src/class_linker.cc index ac2f4f1647..5687453448 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -121,6 +121,7 @@ void ThrowEarlierClassFailure(Class* c) { */ LOG(INFO) << "Rejecting re-init on previously-failed class " << PrettyClass(c); + CHECK(c->IsErroneous()) << PrettyClass(c); if (c->GetVerifyErrorClass() != NULL) { // TODO: change the verifier to store an _instance_, with a useful detail message? ClassHelper ve_ch(c->GetVerifyErrorClass()); @@ -1079,6 +1080,7 @@ Class* EnsureResolved(Class* klass) { if (!klass->IsResolved() && klass->GetClinitThreadId() == self->GetTid()) { self->ThrowNewException("Ljava/lang/ClassCircularityError;", PrettyDescriptor(klass).c_str()); + klass->SetStatus(Class::kStatusError); return NULL; } // Wait for the pending initialization to complete. @@ -1159,7 +1161,7 @@ Class* ClassLinker::FindClass(const char* descriptor, const ClassLoader* class_l ScopedLocalRef<jobject> class_loader_object(env, AddLocalReference<jobject>(env, class_loader)); ScopedLocalRef<jobject> result(env, env->CallObjectMethod(class_loader_object.get(), mid, class_name_object.get())); - if (env->ExceptionOccurred()) { + if (env->ExceptionCheck()) { // If the ClassLoader threw, pass that exception up. return NULL; } else if (result.get() == NULL) { @@ -1208,6 +1210,7 @@ Class* ClassLinker::DefineClass(const StringPiece& descriptor, // Check for a pending exception during load Thread* self = Thread::Current(); if (self->IsExceptionPending()) { + klass->SetStatus(Class::kStatusError); return NULL; } ObjectLock lock(klass.get()); @@ -1224,7 +1227,6 @@ Class* ClassLinker::DefineClass(const StringPiece& descriptor, CHECK(!klass->IsLoaded()); if (!LoadSuperAndInterfaces(klass, dex_file)) { // Loading failed. - CHECK(self->IsExceptionPending()); klass->SetStatus(Class::kStatusError); lock.NotifyAll(); return NULL; @@ -1234,7 +1236,6 @@ Class* ClassLinker::DefineClass(const StringPiece& descriptor, CHECK(!klass->IsResolved()); if (!LinkClass(klass, NULL)) { // Linking failed. - CHECK(self->IsExceptionPending()); klass->SetStatus(Class::kStatusError); lock.NotifyAll(); return NULL; @@ -1902,8 +1903,9 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, Class* klass) CHECK(oat_class.get() != NULL) << descriptor; Class::Status status = oat_class->GetStatus(); if (status == Class::kStatusError) { - ThrowEarlierClassFailure(klass); - klass->SetVerifyErrorClass(Thread::Current()->GetException()->GetClass()); + // TODO: include appropriate verify_error_class_ information in oat file for use here. + ThrowNoClassDefFoundError("Class failed compile-time verification: %s", + PrettyDescriptor(klass).c_str()); klass->SetStatus(Class::kStatusError); return true; } @@ -2002,7 +2004,7 @@ Class* ClassLinker::CreateProxyClass(String* name, ObjectArray<Class>* interface // Link the fields and virtual methods, creating vtable and iftables if (!LinkClass(klass, interfaces)) { - DCHECK(Thread::Current()->IsExceptionPending()); + klass->SetStatus(Class::kStatusError); return NULL; } sfield->SetObject(NULL, throws); // initialize throws field @@ -2156,7 +2158,6 @@ bool ClassLinker::InitializeClass(Class* klass, bool can_run_clinit) { } if (!ValidateSuperClassDescriptors(klass)) { - CHECK(self->IsExceptionPending()); klass->SetStatus(Class::kStatusError); return false; } @@ -2170,7 +2171,7 @@ bool ClassLinker::InitializeClass(Class* klass, bool can_run_clinit) { uint64_t t0 = NanoTime(); if (!InitializeSuperClass(klass, can_run_clinit)) { - CHECK(self->IsExceptionPending()); + CHECK(klass->IsErroneous()); return false; } @@ -2346,10 +2347,10 @@ bool ClassLinker::InitializeSuperClass(Class* klass, bool can_run_clinit) { // TODO: check for a pending exception if (!super_initialized) { if (!can_run_clinit) { - // Don't set status to error when we can't run <clinit>. - CHECK_EQ(klass->GetStatus(), Class::kStatusInitializing) << PrettyClass(klass); - klass->SetStatus(Class::kStatusVerified); - return false; + // Don't set status to error when we can't run <clinit>. + CHECK_EQ(klass->GetStatus(), Class::kStatusInitializing) << PrettyClass(klass); + klass->SetStatus(Class::kStatusVerified); + return false; } klass->SetStatus(Class::kStatusError); klass->NotifyAll(); @@ -2370,7 +2371,7 @@ bool ClassLinker::EnsureInitialized(Class* c, bool can_run_clinit) { ScopedThreadStateChange tsc(self, Thread::kRunnable); bool success = InitializeClass(c, can_run_clinit); if (!success) { - CHECK(self->IsExceptionPending()); + CHECK(self->IsExceptionPending()) << PrettyClass(c); } return success; } @@ -2496,13 +2497,12 @@ bool ClassLinker::LinkSuperClass(SirtRef<Class>& klass) { } // Verify if (super->IsFinal() || super->IsInterface()) { - Thread* thread = Thread::Current(); - thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;", + Thread* self = Thread::Current(); + self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;", "Superclass %s of %s is %s", PrettyDescriptor(super).c_str(), PrettyDescriptor(klass.get()).c_str(), super->IsFinal() ? "declared final" : "an interface"); - klass->SetVerifyErrorClass(thread->GetException()->GetClass()); return false; } if (!klass->CanAccess(super)) { @@ -2663,12 +2663,11 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<Class>& klass, ObjectArray<Class> DCHECK(interface != NULL); if (!interface->IsInterface()) { ClassHelper ih(interface); - Thread* thread = Thread::Current(); - thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;", + Thread* self = Thread::Current(); + self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;", "Class %s implements non-interface class %s", PrettyDescriptor(klass.get()).c_str(), PrettyDescriptor(ih.GetDescriptor()).c_str()); - klass->SetVerifyErrorClass(thread->GetException()->GetClass()); return false; } // Check if interface is already in iftable diff --git a/src/object.cc b/src/object.cc index 7ead4ab7a3..c16cdb0123 100644 --- a/src/object.cc +++ b/src/object.cc @@ -597,6 +597,30 @@ void Class::SetStatus(Status new_status) { CHECK(new_status > GetStatus() || new_status == kStatusError || !Runtime::Current()->IsStarted()) << PrettyClass(this) << " " << GetStatus() << " -> " << new_status; CHECK(sizeof(Status) == sizeof(uint32_t)) << PrettyClass(this); + if (new_status == kStatusError) { + CHECK_NE(GetStatus(), kStatusError) << PrettyClass(this); + + // stash current exception + Thread* self = Thread::Current(); + SirtRef<Throwable> exception(self->GetException()); + CHECK(exception.get() != NULL); + + // clear exception to call FindSystemClass + self->ClearException(); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Class* eiie_class = class_linker->FindSystemClass("Ljava/lang/ExceptionInInitializerError;"); + CHECK(!self->IsExceptionPending()); + + // only verification errors, not initialization problems, should set a verify error. + // this is to ensure that ThrowEarlierClassFailure will throw NoClassDefFoundError in that case. + Class* exception_class = exception->GetClass(); + if (!eiie_class->IsAssignableFrom(exception_class)) { + SetVerifyErrorClass(exception_class); + } + + // restore exception + self->SetException(exception.get()); + } return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false); } diff --git a/src/object.h b/src/object.h index 3cbe9d6572..1841042b11 100644 --- a/src/object.h +++ b/src/object.h @@ -1708,10 +1708,6 @@ class MANAGED Class : public StaticStorageBase { return GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), false); } - void SetVerifyErrorClass(Class* klass) { - SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), klass, false); - } - uint16_t GetDexTypeIndex() const { return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), false); } @@ -1721,6 +1717,11 @@ class MANAGED Class : public StaticStorageBase { } private: + void SetVerifyErrorClass(Class* klass) { + CHECK(klass != NULL) << PrettyClass(this); + SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), klass, false); + } + bool Implements(const Class* klass) const; bool IsArrayAssignableFromArray(const Class* klass) const; bool IsAssignableFromArray(const Class* klass) const; diff --git a/test/068-classloader/src/FancyLoader.java b/test/068-classloader/src/FancyLoader.java index 28c17a814c..2c6fcde81d 100644 --- a/test/068-classloader/src/FancyLoader.java +++ b/test/068-classloader/src/FancyLoader.java @@ -35,10 +35,10 @@ import java.lang.reflect.InvocationTargetException; */ public class FancyLoader extends ClassLoader { /* this is where the "alternate" .class files live */ - static final String CLASS_PATH = "/data/art-test"; + static final String CLASS_PATH = "classes-ex/"; /* this is the "alternate" DEX/Jar file */ - static final String DEX_FILE = "068-classloader-ex.jar"; + static final String DEX_FILE = "/data/art-test/068-classloader-ex.jar"; /* on Dalvik, this is a DexFile; otherwise, it's null */ private Class mDexClass; @@ -94,7 +94,7 @@ public class FancyLoader extends ClassLoader { } try { - mDexFile = ctor.newInstance(CLASS_PATH + File.separator + DEX_FILE); + mDexFile = ctor.newInstance(DEX_FILE); } catch (InstantiationException ie) { throw new ClassNotFoundException("newInstance failed", ie); } catch (IllegalAccessException iae) { diff --git a/test/068-classloader/src/Main.java b/test/068-classloader/src/Main.java index 1bc7b04c5c..7dfb6f507d 100644 --- a/test/068-classloader/src/Main.java +++ b/test/068-classloader/src/Main.java @@ -99,7 +99,7 @@ public class Main { try { altClass = loader.loadClass("Inaccessible2"); - System.err.println("ERROR: Inaccessible2 was accessible"); + System.err.println("ERROR: Inaccessible2 was accessible: " + altClass); } catch (ClassNotFoundException cnfe) { Throwable cause = cnfe.getCause(); if (cause instanceof IllegalAccessError) { @@ -119,7 +119,7 @@ public class Main { try { altClass = loader.loadClass("Inaccessible3"); - System.err.println("ERROR: Inaccessible3 was accessible"); + System.err.println("ERROR: Inaccessible3 was accessible: " + altClass); } catch (ClassNotFoundException cnfe) { Throwable cause = cnfe.getCause(); if (cause instanceof IllegalAccessError) { |