Do not reset SirtRef pointing to a live object
ClassLinker::FindClass reset the klass SirtRef to point to the
existing Class value. However, the old value was still referenced by
the ObjectLock. In the rare case of a two thread resolving the same
class at the same time and a garbage collection happening, the
ObjectLock would point to freed memory.
Change-Id: I93dbbfe3e5d7a8922464242270ac90c71a125e47
diff --git a/src/class_linker.cc b/src/class_linker.cc
index e8700be..80dd7eb 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1251,12 +1251,10 @@
ObjectLock lock(klass.get());
klass->SetClinitThreadId(self->GetTid());
// Add the newly loaded class to the loaded classes table.
- Class* existing = InsertClass(descriptor, klass.get(), false);
- if (existing != NULL) {
+ SirtRef<Class> existing(InsertClass(descriptor, klass.get(), false));
+ if (existing.get() != NULL) {
// We failed to insert because we raced with another thread.
- klass->SetClinitThreadId(0);
- klass.reset(existing);
- return EnsureResolved(klass.get());
+ return EnsureResolved(existing.get());
}
// Finish loading (if necessary) by finding parents
CHECK(!klass->IsLoaded());
diff --git a/src/object_utils.h b/src/object_utils.h
index 99768de..59ef515 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -74,8 +74,8 @@
}
void ChangeClass(const Class* new_c) {
- CHECK(new_c != NULL) << "klass_=" << klass_ << " " << HexDump(klass_, sizeof(Class), true);
- CHECK(new_c->IsClass()) << "klass_=" << klass_ << " " << HexDump(klass_, sizeof(Class), true);
+ CHECK(new_c != NULL) << "klass_=" << klass_; // Log what we were changing from if any
+ CHECK(new_c->IsClass()) << "new_c=" << new_c;
if (dex_cache_ != NULL) {
DexCache* new_c_dex_cache = new_c->GetDexCache();
if (new_c_dex_cache != dex_cache_) {