diff options
| author | 2012-02-01 09:18:34 -0800 | |
|---|---|---|
| committer | 2012-02-01 10:42:11 -0800 | |
| commit | 1c5eb704b61511cdc649cad032d29940857c9fe9 (patch) | |
| tree | 9950f70d497a58cb1d07712a90b72ce19d783eb5 /src | |
| parent | 02fbef0e356ca43b2032044f870d59de4a4ae92a (diff) | |
Move super class verification to class linker
Verify super classes in the class linker and chain exceptions when super
class verification fails. Add support for dumping chained exceptions to
Throwable::Dump. Improve verifier error detail messages.
Fixes problem where super class verification would leave a pending
exception that would be tripped over elsewhere.
Change-Id: I3ca850fc66674c8601132d7ec40bebbf9c108ae3
Diffstat (limited to 'src')
| -rw-r--r-- | src/class_linker.cc | 42 | ||||
| -rw-r--r-- | src/dex_verifier.cc | 40 | ||||
| -rw-r--r-- | src/dex_verifier.h | 2 | ||||
| -rw-r--r-- | src/dex_verifier_test.cc | 6 | ||||
| -rw-r--r-- | src/object.cc | 12 | ||||
| -rw-r--r-- | src/object.h | 4 |
6 files changed, 76 insertions, 30 deletions
diff --git a/src/class_linker.cc b/src/class_linker.cc index cccf0f65c5..51e5f3c2ec 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -1889,9 +1889,41 @@ void ClassLinker::VerifyClass(Class* klass) { CHECK_EQ(klass->GetStatus(), Class::kStatusResolved) << PrettyClass(klass); klass->SetStatus(Class::kStatusVerifying); + // Verify super class + Class* super = klass->GetSuperClass(); + std::string error_msg; + if (super != NULL) { + // Acquire lock to prevent races on verifying the super class + ObjectLock lock(super); + + if (!super->IsVerified() && !super->IsErroneous()) { + Runtime::Current()->GetClassLinker()->VerifyClass(super); + } + if (!super->IsVerified()) { + error_msg = "Rejecting class "; + error_msg += PrettyDescriptor(klass); + error_msg += " that attempts to sub-class erroneous class "; + error_msg += PrettyDescriptor(super); + LOG(ERROR) << error_msg << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8(); + Thread* self = Thread::Current(); + SirtRef<Throwable> cause(self->GetException()); + if (cause.get() != NULL) { + self->ClearException(); + } + self->ThrowNewException("Ljava/lang/VerifyError;", error_msg.c_str()); + if (cause.get() != NULL) { + self->GetException()->SetCause(cause.get()); + } + CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying) << PrettyDescriptor(klass); + klass->SetStatus(Class::kStatusError); + return; + } + } + // Try to use verification information from oat file, otherwise do runtime verification const DexFile& dex_file = FindDexFile(klass->GetDexCache()); - if (VerifyClassUsingOatFile(dex_file, klass) || verifier::DexVerifier::VerifyClass(klass)) { + if (VerifyClassUsingOatFile(dex_file, klass) || + verifier::DexVerifier::VerifyClass(klass, error_msg)) { // Make sure all classes referenced by catch blocks are resolved ResolveClassExceptionHandlerTypes(dex_file, klass); klass->SetStatus(Class::kStatusVerified); @@ -1899,12 +1931,12 @@ void ClassLinker::VerifyClass(Class* klass) { CheckMethodsHaveGcMaps(klass); } else { LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass) - << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8(); + << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8() + << " because: " << error_msg; Thread* self = Thread::Current(); CHECK(!self->IsExceptionPending()) << self->GetException()->Dump(); - self->ThrowNewExceptionF("Ljava/lang/VerifyError;", "Verification of %s failed", - PrettyDescriptor(klass).c_str()); - CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying) << PrettyClass(klass); + self->ThrowNewException("Ljava/lang/VerifyError;", error_msg.c_str()); + CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying) << PrettyDescriptor(klass); klass->SetStatus(Class::kStatusError); } } diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc index 31c2697b5c..8776458b67 100644 --- a/src/dex_verifier.cc +++ b/src/dex_verifier.cc @@ -922,45 +922,41 @@ void PcToRegisterLineTable::Init(RegisterTrackingMode mode, InsnFlags* flags, } } -bool DexVerifier::VerifyClass(const Class* klass) { +bool DexVerifier::VerifyClass(const Class* klass, std::string& error) { if (klass->IsVerified()) { return true; } Class* super = klass->GetSuperClass(); if (super == NULL && StringPiece(ClassHelper(klass).GetDescriptor()) != "Ljava/lang/Object;") { - LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass) << " that has no super class"; + error = "Verifier rejected class "; + error += PrettyDescriptor(klass); + error += " that has no super class"; return false; } - if (super != NULL) { - // Acquire lock to prevent races on verifying the super class - ObjectLock lock(super); - - if (!super->IsVerified() && !super->IsErroneous()) { - Runtime::Current()->GetClassLinker()->VerifyClass(super); - } - if (!super->IsVerified()) { - LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass) - << " that attempts to sub-class corrupt class " << PrettyClass(super); - return false; - } else if (super->IsFinal()) { - LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass) - << " that attempts to sub-class final class " << PrettyClass(super); - return false; - } + if (super != NULL && super->IsFinal()) { + error = "Verifier rejected class "; + error += PrettyDescriptor(klass); + error += " that attempts to sub-class final class "; + error += PrettyDescriptor(super); + return false; } for (size_t i = 0; i < klass->NumDirectMethods(); ++i) { Method* method = klass->GetDirectMethod(i); if (!VerifyMethod(method)) { - LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass) << " due to bad method " - << PrettyMethod(method, true); + error = "Verifier rejected class "; + error += PrettyDescriptor(klass); + error += " due to bad method "; + error += PrettyMethod(method, true); return false; } } for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) { Method* method = klass->GetVirtualMethod(i); if (!VerifyMethod(method)) { - LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass) << " due to bad method " - << PrettyMethod(method, true); + error = "Verifier rejected class "; + error += PrettyDescriptor(klass); + error += " due to bad method "; + error += PrettyMethod(method, true); return false; } } diff --git a/src/dex_verifier.h b/src/dex_verifier.h index cbdc7fd1ca..0488ba37c4 100644 --- a/src/dex_verifier.h +++ b/src/dex_verifier.h @@ -826,7 +826,7 @@ class PcToRegisterLineTable { class DexVerifier { public: /* Verify a class. Returns "true" on success. */ - static bool VerifyClass(const Class* klass); + static bool VerifyClass(const Class* klass, std::string& error); /* * Perform verification on a single method. * diff --git a/src/dex_verifier_test.cc b/src/dex_verifier_test.cc index 379e8c4eb6..51fb1bc0e4 100644 --- a/src/dex_verifier_test.cc +++ b/src/dex_verifier_test.cc @@ -33,7 +33,8 @@ class DexVerifierTest : public CommonTest { Class* klass = class_linker_->FindSystemClass(descriptor.c_str()); // Verify the class - ASSERT_TRUE(DexVerifier::VerifyClass(klass)); + std::string error_msg; + ASSERT_TRUE(DexVerifier::VerifyClass(klass, error_msg)) << error_msg; } void VerifyDexFile(const DexFile* dex, ClassLoader* class_loader) { @@ -55,7 +56,8 @@ TEST_F(DexVerifierTest, LibCore) { TEST_F(DexVerifierTest, IntMath) { SirtRef<ClassLoader> class_loader(LoadDex("IntMath")); Class* klass = class_linker_->FindClass("LIntMath;", class_loader.get()); - ASSERT_TRUE(DexVerifier::VerifyClass(klass)); + std::string error_msg; + ASSERT_TRUE(DexVerifier::VerifyClass(klass, error_msg)) << error_msg; } TEST_F(DexVerifierTest, RegTypes_Primitives) { diff --git a/src/object.cc b/src/object.cc index 7f6e451241..f90031a976 100644 --- a/src/object.cc +++ b/src/object.cc @@ -1337,6 +1337,13 @@ std::string String::ToModifiedUtf8() const { return result; } +void Throwable::SetCause(Throwable* cause) { + CHECK(cause != NULL); + CHECK(cause != this); + CHECK(GetFieldObject<Throwable*>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), false) == NULL); + SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), cause, false); +} + bool Throwable::IsCheckedException() const { Class* error = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/Error;"); if (InstanceOf(error)) { @@ -1367,6 +1374,11 @@ std::string Throwable::Dump() const { result += "\n"; } } + Throwable* cause = GetFieldObject<Throwable*>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), false); + if (cause != NULL) { + result += "Caused by: "; + result += cause->Dump(); + } return result; } diff --git a/src/object.h b/src/object.h index 1841042b11..e9556eff67 100644 --- a/src/object.h +++ b/src/object.h @@ -2273,6 +2273,10 @@ class MANAGED Throwable : public Object { } std::string Dump() const; + // This is a runtime version of initCause, you shouldn't use it if initCause may have been + // overridden. Also it asserts rather than throwing exceptions. Currently this is only used + // in cases like the verifier where the checks cannot fail and initCause isn't overridden. + void SetCause(Throwable* cause); bool IsCheckedException() const; private: Object* GetStackState() const { |