diff options
author | Hiroshi Yamauchi <yamauchi@google.com> | 2015-05-20 15:51:29 -0700 |
---|---|---|
committer | Hiroshi Yamauchi <yamauchi@google.com> | 2015-05-20 16:09:30 -0700 |
commit | a56ce5e267c9744ed99e40ae5cd9b527971e1d63 (patch) | |
tree | 4a916a7f4dc89d6444ade0d74cc64a3ad5126646 /runtime | |
parent | ce70082da8a4e63c280c2f049a67b38acc82ee1a (diff) | |
download | art-a56ce5e267c9744ed99e40ae5cd9b527971e1d63.zip art-a56ce5e267c9744ed99e40ae5cd9b527971e1d63.tar.gz art-a56ce5e267c9744ed99e40ae5cd9b527971e1d63.tar.bz2 |
Fix a cts crash around proxy class fields.
org.apache.harmony.tests.java.io.SerializationStressTest4#test_writeObject_Proxy
As the static fields of proxy classes share the dex file indices, they
shouldn't be resolved in the dex cache or else Field::GetArtField()
may return a wrong art field that belong to a different proxy class.
Bug: 20557050
Change-Id: If672c0e67bc49e672e34d75ffbe29c65f5a423b9
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/mirror/field-inl.h | 26 | ||||
-rw-r--r-- | runtime/mirror/field.cc | 14 | ||||
-rw-r--r-- | runtime/proxy_test.cc | 50 |
3 files changed, 80 insertions, 10 deletions
diff --git a/runtime/mirror/field-inl.h b/runtime/mirror/field-inl.h index 9820db7..388921b 100644 --- a/runtime/mirror/field-inl.h +++ b/runtime/mirror/field-inl.h @@ -30,10 +30,11 @@ namespace mirror { template <bool kTransactionActive> inline mirror::Field* Field::CreateFromArtField(Thread* self, ArtField* field, bool force_resolve) { + StackHandleScope<2> hs(self); // Try to resolve type before allocating since this is a thread suspension point. - mirror::Class* type = field->GetType<true>(); + Handle<mirror::Class> type = hs.NewHandle(field->GetType<true>()); - if (type == nullptr) { + if (type.Get() == nullptr) { if (force_resolve) { if (kIsDebugBuild) { self->AssertPendingException(); @@ -48,7 +49,6 @@ inline mirror::Field* Field::CreateFromArtField(Thread* self, ArtField* field, self->ClearException(); } } - StackHandleScope<1> hs(self); auto ret = hs.NewHandle(static_cast<Field*>(StaticClass()->AllocObject(self))); if (ret.Get() == nullptr) { if (kIsDebugBuild) { @@ -58,14 +58,22 @@ inline mirror::Field* Field::CreateFromArtField(Thread* self, ArtField* field, } auto dex_field_index = field->GetDexFieldIndex(); auto* resolved_field = field->GetDexCache()->GetResolvedField(dex_field_index, sizeof(void*)); - if (resolved_field != nullptr) { - DCHECK_EQ(resolved_field, field); + if (field->GetDeclaringClass()->IsProxyClass()) { + DCHECK(field->IsStatic()); + DCHECK_LT(dex_field_index, 2U); + // The two static fields (interfaces, throws) of all proxy classes + // share the same dex file indices 0 and 1. So, we can't resolve + // them in the dex cache. } else { - // We rely on the field being resolved so that we can back to the ArtField - // (i.e. FromReflectedMethod). - field->GetDexCache()->SetResolvedField(dex_field_index, field, sizeof(void*)); + if (resolved_field != nullptr) { + DCHECK_EQ(resolved_field, field); + } else { + // We rely on the field being resolved so that we can back to the ArtField + // (i.e. FromReflectedMethod). + field->GetDexCache()->SetResolvedField(dex_field_index, field, sizeof(void*)); + } } - ret->SetType<kTransactionActive>(type); + ret->SetType<kTransactionActive>(type.Get()); ret->SetDeclaringClass<kTransactionActive>(field->GetDeclaringClass()); ret->SetAccessFlags<kTransactionActive>(field->GetAccessFlags()); ret->SetDexFieldIndex<kTransactionActive>(dex_field_index); diff --git a/runtime/mirror/field.cc b/runtime/mirror/field.cc index 70311bb..933784e 100644 --- a/runtime/mirror/field.cc +++ b/runtime/mirror/field.cc @@ -54,7 +54,19 @@ void Field::VisitRoots(RootVisitor* visitor) { } ArtField* Field::GetArtField() { - mirror::DexCache* const dex_cache = GetDeclaringClass()->GetDexCache(); + mirror::Class* declaring_class = GetDeclaringClass(); + if (UNLIKELY(declaring_class->IsProxyClass())) { + DCHECK(IsStatic()); + DCHECK_EQ(declaring_class->NumStaticFields(), 2U); + // 0 == Class[] interfaces; 1 == Class[][] throws; + if (GetDexFieldIndex() == 0) { + return &declaring_class->GetSFields()[0]; + } else { + DCHECK_EQ(GetDexFieldIndex(), 1U); + return &declaring_class->GetSFields()[1]; + } + } + mirror::DexCache* const dex_cache = declaring_class->GetDexCache(); ArtField* const art_field = dex_cache->GetResolvedField(GetDexFieldIndex(), sizeof(void*)); CHECK(art_field != nullptr); return art_field; diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc index b471293..93d1f66 100644 --- a/runtime/proxy_test.cc +++ b/runtime/proxy_test.cc @@ -20,6 +20,7 @@ #include "art_field-inl.h" #include "class_linker-inl.h" #include "common_compiler_test.h" +#include "mirror/field-inl.h" #include "mirror/method.h" #include "scoped_thread_state_change.h" @@ -191,4 +192,53 @@ TEST_F(ProxyTest, ProxyFieldHelper) { EXPECT_FALSE(field->IsPrimitiveType()); } +// Creates two proxy classes and check the art/mirror fields of their static fields. +TEST_F(ProxyTest, CheckArtMirrorFieldsOfProxyStaticFields) { + ScopedObjectAccess soa(Thread::Current()); + jobject jclass_loader = LoadDex("Interfaces"); + StackHandleScope<7> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader( + hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader))); + + Handle<mirror::Class> proxyClass0; + Handle<mirror::Class> proxyClass1; + { + std::vector<mirror::Class*> interfaces; + proxyClass0 = hs.NewHandle(GenerateProxyClass(soa, jclass_loader, "$Proxy0", interfaces)); + proxyClass1 = hs.NewHandle(GenerateProxyClass(soa, jclass_loader, "$Proxy1", interfaces)); + } + + ASSERT_TRUE(proxyClass0.Get() != nullptr); + ASSERT_TRUE(proxyClass0->IsProxyClass()); + ASSERT_TRUE(proxyClass0->IsInitialized()); + ASSERT_TRUE(proxyClass1.Get() != nullptr); + ASSERT_TRUE(proxyClass1->IsProxyClass()); + ASSERT_TRUE(proxyClass1->IsInitialized()); + + ArtField* static_fields0 = proxyClass0->GetSFields(); + ASSERT_TRUE(static_fields0 != nullptr); + ASSERT_EQ(2u, proxyClass0->NumStaticFields()); + ArtField* static_fields1 = proxyClass1->GetSFields(); + ASSERT_TRUE(static_fields1 != nullptr); + ASSERT_EQ(2u, proxyClass1->NumStaticFields()); + + EXPECT_EQ(static_fields0[0].GetDeclaringClass(), proxyClass0.Get()); + EXPECT_EQ(static_fields0[1].GetDeclaringClass(), proxyClass0.Get()); + EXPECT_EQ(static_fields1[0].GetDeclaringClass(), proxyClass1.Get()); + EXPECT_EQ(static_fields1[1].GetDeclaringClass(), proxyClass1.Get()); + + Handle<mirror::Field> field00 = + hs.NewHandle(mirror::Field::CreateFromArtField(soa.Self(), &static_fields0[0], true)); + Handle<mirror::Field> field01 = + hs.NewHandle(mirror::Field::CreateFromArtField(soa.Self(), &static_fields0[1], true)); + Handle<mirror::Field> field10 = + hs.NewHandle(mirror::Field::CreateFromArtField(soa.Self(), &static_fields1[0], true)); + Handle<mirror::Field> field11 = + hs.NewHandle(mirror::Field::CreateFromArtField(soa.Self(), &static_fields1[1], true)); + EXPECT_EQ(field00->GetArtField(), &static_fields0[0]); + EXPECT_EQ(field01->GetArtField(), &static_fields0[1]); + EXPECT_EQ(field10->GetArtField(), &static_fields1[0]); + EXPECT_EQ(field11->GetArtField(), &static_fields1[1]); +} + } // namespace art |