diff options
| author | 2016-11-02 09:06:42 +0000 | |
|---|---|---|
| committer | 2016-11-02 09:06:43 +0000 | |
| commit | dd7c25e5af5b88a1bc58ed7de076037e593b176d (patch) | |
| tree | e96ccdf507164d12f5ca785b3b88bc793276fffc /compiler | |
| parent | 12fc3df93a5cee8025b0207aac487752f6754357 (diff) | |
| parent | 8904b6f0e496ab389551e960426069c9deff4101 (diff) | |
Merge "Add VerifierDeps::Verify."
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/verifier_deps_test.cc | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc index 3a53998e17..8d2a0e7860 100644 --- a/compiler/verifier_deps_test.cc +++ b/compiler/verifier_deps_test.cc @@ -399,6 +399,18 @@ class VerifierDepsTest : public CommonCompilerTest { has_unverified_classes; } + static std::set<VerifierDeps::MethodResolution>* GetMethods( + VerifierDeps::DexFileDeps* deps, MethodResolutionKind resolution_kind) { + if (resolution_kind == kDirectMethodResolution) { + return &deps->direct_methods_; + } else if (resolution_kind == kVirtualMethodResolution) { + return &deps->virtual_methods_; + } else { + DCHECK_EQ(resolution_kind, kInterfaceMethodResolution); + return &deps->interface_methods_; + } + } + std::unique_ptr<verifier::VerifierDeps> verifier_deps_; std::vector<const DexFile*> dex_files_; const DexFile* primary_dex_file_; @@ -1121,5 +1133,311 @@ TEST_F(VerifierDepsTest, UnverifiedClasses) { ASSERT_TRUE(HasUnverifiedClass("LMyClassWithNoSuperButFailures;")); } +// Returns the next resolution kind in the enum. +static MethodResolutionKind GetNextResolutionKind(MethodResolutionKind resolution_kind) { + if (resolution_kind == kDirectMethodResolution) { + return kVirtualMethodResolution; + } else if (resolution_kind == kVirtualMethodResolution) { + return kInterfaceMethodResolution; + } else { + DCHECK_EQ(resolution_kind, kInterfaceMethodResolution); + return kDirectMethodResolution; + } +} + +TEST_F(VerifierDepsTest, VerifyDeps) { + VerifyDexFile(); + + ASSERT_EQ(1u, NumberOfCompiledDexFiles()); + ASSERT_TRUE(HasEachKindOfRecord()); + + // When validating, we create a new class loader, as + // the existing `class_loader_` may contain erroneous classes, + // that ClassLinker::FindClass won't return. + + ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<1> hs(soa.Self()); + MutableHandle<mirror::ClassLoader> new_class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr)); + { + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_TRUE(verifier_deps_->Verify(new_class_loader, soa.Self())); + } + + std::vector<uint8_t> buffer; + verifier_deps_->Encode(dex_files_, &buffer); + ASSERT_FALSE(buffer.empty()); + + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_TRUE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + // Fiddle with the dependencies to make sure we catch any change and fail to verify. + + { + // Mess up with the assignable_types. + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + deps->assignable_types_.insert(*deps->unassignable_types_.begin()); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + { + // Mess up with the unassignable_types. + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + deps->unassignable_types_.insert(*deps->assignable_types_.begin()); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + // Mess up with classes. + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + for (const auto& entry : deps->classes_) { + if (entry.IsResolved()) { + deps->classes_.insert(VerifierDeps::ClassResolution( + entry.GetDexTypeIndex(), VerifierDeps::kUnresolvedMarker)); + found = true; + break; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + for (const auto& entry : deps->classes_) { + if (!entry.IsResolved()) { + deps->classes_.insert(VerifierDeps::ClassResolution( + entry.GetDexTypeIndex(), VerifierDeps::kUnresolvedMarker - 1)); + found = true; + break; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + for (const auto& entry : deps->classes_) { + if (entry.IsResolved()) { + deps->classes_.insert(VerifierDeps::ClassResolution( + entry.GetDexTypeIndex(), entry.GetAccessFlags() - 1)); + found = true; + break; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + // Mess up with fields. + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + for (const auto& entry : deps->fields_) { + if (entry.IsResolved()) { + deps->fields_.insert(VerifierDeps::FieldResolution(entry.GetDexFieldIndex(), + VerifierDeps::kUnresolvedMarker, + entry.GetDeclaringClassIndex())); + found = true; + break; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + for (const auto& entry : deps->fields_) { + if (!entry.IsResolved()) { + deps->fields_.insert(VerifierDeps::FieldResolution(0 /* we know there is a field there */, + VerifierDeps::kUnresolvedMarker - 1, + 0 /* we know there is a class there */)); + found = true; + break; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + for (const auto& entry : deps->fields_) { + if (entry.IsResolved()) { + deps->fields_.insert(VerifierDeps::FieldResolution(entry.GetDexFieldIndex(), + entry.GetAccessFlags() - 1, + entry.GetDeclaringClassIndex())); + found = true; + break; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + for (const auto& entry : deps->fields_) { + static constexpr uint32_t kNewTypeIndex = 0; + if (entry.GetDeclaringClassIndex() != kNewTypeIndex) { + deps->fields_.insert(VerifierDeps::FieldResolution(entry.GetDexFieldIndex(), + entry.GetAccessFlags(), + kNewTypeIndex)); + found = true; + break; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + // Mess up with methods. + for (MethodResolutionKind resolution_kind : + { kDirectMethodResolution, kVirtualMethodResolution, kInterfaceMethodResolution }) { + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + std::set<VerifierDeps::MethodResolution>* methods = GetMethods(deps, resolution_kind); + for (const auto& entry : *methods) { + if (entry.IsResolved()) { + methods->insert(VerifierDeps::MethodResolution(entry.GetDexMethodIndex(), + VerifierDeps::kUnresolvedMarker, + entry.GetDeclaringClassIndex())); + found = true; + break; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + std::set<VerifierDeps::MethodResolution>* methods = GetMethods(deps, resolution_kind); + for (const auto& entry : *methods) { + if (!entry.IsResolved()) { + methods->insert(VerifierDeps::MethodResolution(0 /* we know there is a method there */, + VerifierDeps::kUnresolvedMarker - 1, + 0 /* we know there is a class there */)); + found = true; + break; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + std::set<VerifierDeps::MethodResolution>* methods = GetMethods(deps, resolution_kind); + for (const auto& entry : *methods) { + if (entry.IsResolved()) { + methods->insert(VerifierDeps::MethodResolution(entry.GetDexMethodIndex(), + entry.GetAccessFlags() - 1, + entry.GetDeclaringClassIndex())); + found = true; + break; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + std::set<VerifierDeps::MethodResolution>* methods = GetMethods(deps, resolution_kind); + for (const auto& entry : *methods) { + static constexpr uint32_t kNewTypeIndex = 0; + if (entry.IsResolved() && entry.GetDeclaringClassIndex() != kNewTypeIndex) { + methods->insert(VerifierDeps::MethodResolution(entry.GetDexMethodIndex(), + entry.GetAccessFlags(), + kNewTypeIndex)); + found = true; + break; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + std::set<VerifierDeps::MethodResolution>* methods = GetMethods(deps, resolution_kind); + for (const auto& entry : *methods) { + if (entry.IsResolved()) { + GetMethods(deps, GetNextResolutionKind(resolution_kind))->insert( + VerifierDeps::MethodResolution(entry.GetDexMethodIndex(), + entry.GetAccessFlags(), + entry.GetDeclaringClassIndex())); + found = true; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + + { + VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + std::set<VerifierDeps::MethodResolution>* methods = GetMethods(deps, resolution_kind); + for (const auto& entry : *methods) { + if (entry.IsResolved()) { + GetMethods(deps, GetNextResolutionKind(GetNextResolutionKind(resolution_kind)))->insert( + VerifierDeps::MethodResolution(entry.GetDexMethodIndex(), + entry.GetAccessFlags(), + entry.GetDeclaringClassIndex())); + found = true; + } + } + ASSERT_TRUE(found); + new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); + ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + } + } +} + } // namespace verifier } // namespace art |