Prevent exception bugs in class linker
There were some places that could throw exceptions but still succeed.
This caused the allocation entrypoints to occasionally allocate a
heap object with a pending exception.
Also added some additional AssertNoExceptionPending.
Bug: 17164348
Change-Id: Ic6dd3b0cce9955349176503dd7f6c3da7ab0a6f1
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c2a3ab7..e7a645e 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2065,6 +2065,7 @@
}
return nullptr;
}
+ self->AssertNoPendingException();
CHECK(new_class != nullptr) << descriptor;
CHECK(new_class->IsResolved()) << descriptor;
@@ -3808,6 +3809,8 @@
CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
}
return false;
+ } else {
+ self->AssertNoPendingException();
}
}
@@ -3817,6 +3820,10 @@
// invocation of InitializeClass will not be responsible for
// running <clinit> and will return.
if (klass->GetStatus() == mirror::Class::kStatusInitializing) {
+ // Could have got an exception during verification.
+ if (self->IsExceptionPending()) {
+ return false;
+ }
// We caught somebody else in the act; was it us?
if (klass->GetClinitThreadId() == self->GetTid()) {
// Yes. That's fine. Return so we can continue initializing.
@@ -4018,9 +4025,17 @@
bool ClassLinker::EnsureInitialized(Handle<mirror::Class> c, bool can_init_fields,
bool can_init_parents) {
DCHECK(c.Get() != nullptr);
- const bool success = c->IsInitialized() || InitializeClass(c, can_init_fields, can_init_parents);
- if (!success && can_init_fields && can_init_parents) {
- CHECK(Thread::Current()->IsExceptionPending()) << PrettyClass(c.Get());
+ if (c->IsInitialized()) {
+ return true;
+ }
+ const bool success = InitializeClass(c, can_init_fields, can_init_parents);
+ Thread* self = Thread::Current();
+ if (!success) {
+ if (can_init_fields && can_init_parents) {
+ CHECK(self->IsExceptionPending()) << PrettyClass(c.Get());
+ }
+ } else {
+ self->AssertNoPendingException();
}
return success;
}