summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
author Ian Rogers <irogers@google.com> 2012-02-01 09:18:34 -0800
committer Ian Rogers <irogers@google.com> 2012-02-01 10:42:11 -0800
commit1c5eb704b61511cdc649cad032d29940857c9fe9 (patch)
tree9950f70d497a58cb1d07712a90b72ce19d783eb5 /src
parent02fbef0e356ca43b2032044f870d59de4a4ae92a (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.cc42
-rw-r--r--src/dex_verifier.cc40
-rw-r--r--src/dex_verifier.h2
-rw-r--r--src/dex_verifier_test.cc6
-rw-r--r--src/object.cc12
-rw-r--r--src/object.h4
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 {