diff options
-rw-r--r-- | dex2oat/driver/compiler_driver.cc | 1 | ||||
-rw-r--r-- | openjdkjvmti/ti_redefine.cc | 72 | ||||
-rw-r--r-- | openjdkjvmti/ti_redefine.h | 10 | ||||
-rw-r--r-- | runtime/class_linker.cc | 9 | ||||
-rw-r--r-- | runtime/verifier/class_verifier.cc | 244 | ||||
-rw-r--r-- | runtime/verifier/class_verifier.h | 48 | ||||
-rw-r--r-- | runtime/verifier/method_verifier_test.cc | 10 | ||||
-rw-r--r-- | tools/art_verifier/art_verifier.cc | 10 |
8 files changed, 72 insertions, 332 deletions
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc index cc9f9ec450..e1f51437ce 100644 --- a/dex2oat/driver/compiler_driver.cc +++ b/dex2oat/driver/compiler_driver.cc @@ -1846,6 +1846,7 @@ class VerifyClassVisitor : public CompilationVisitor { verifier::ClassVerifier::VerifyClass(soa.Self(), soa.Self()->GetVerifierDeps(), &dex_file, + klass, dex_cache, class_loader, class_def, diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index 65bfc15b04..0289a7b934 100644 --- a/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc @@ -1608,13 +1608,16 @@ RedefinitionDataIter RedefinitionDataHolder::end() { bool Redefiner::ClassRedefinition::CheckVerification(const RedefinitionDataIter& iter) { DCHECK_EQ(dex_file_->NumClassDefs(), 1u); - art::StackHandleScope<2> hs(driver_->self_); + art::StackHandleScope<3> hs(driver_->self_); std::string error; // TODO Make verification log level lower art::verifier::FailureKind failure = art::verifier::ClassVerifier::VerifyClass(driver_->self_, /*verifier_deps=*/nullptr, dex_file_.get(), + hs.NewHandle(iter.GetNewClassObject() != nullptr + ? iter.GetNewClassObject() + : iter.GetMirrorClass()), hs.NewHandle(iter.GetNewDexCache()), hs.NewHandle(GetClassLoader()), /*class_def=*/ dex_file_->GetClassDef(0), @@ -1624,24 +1627,11 @@ bool Redefiner::ClassRedefinition::CheckVerification(const RedefinitionDataIter& art::verifier::HardFailLogMode::kLogWarning, art::Runtime::Current()->GetTargetSdkVersion(), &error); - switch (failure) { - case art::verifier::FailureKind::kNoFailure: - // TODO It is possible that by doing redefinition previous NO_COMPILE verification failures - // were fixed. It would be nice to reflect this in the new implementations. - return true; - case art::verifier::FailureKind::kSoftFailure: - case art::verifier::FailureKind::kAccessChecksFailure: - case art::verifier::FailureKind::kTypeChecksFailure: - // Soft failures might require interpreter on some methods. It won't prevent redefinition but - // it does mean we need to run the verifier again and potentially update method flags after - // performing the swap. - needs_reverify_ = true; - return true; - case art::verifier::FailureKind::kHardFailure: { - RecordFailure(ERR(FAILS_VERIFICATION), "Failed to verify class. Error was: " + error); - return false; - } + if (failure == art::verifier::FailureKind::kHardFailure) { + RecordFailure(ERR(FAILS_VERIFICATION), "Failed to verify class. Error was: " + error); + return false; } + return true; } // Looks through the previously allocated cookies to see if we need to update them with another new @@ -2519,36 +2509,9 @@ jvmtiError Redefiner::Run() { // owns the DexFile and when ownership is transferred. ReleaseAllDexFiles(); } - // By now the class-linker knows about all the classes so we can safetly retry verification and - // update method flags. - ReverifyClasses(holder); return OK; } -void Redefiner::ReverifyClasses(RedefinitionDataHolder& holder) { - for (RedefinitionDataIter data = holder.begin(); data != holder.end(); ++data) { - data.GetRedefinition().ReverifyClass(data); - } -} - -void Redefiner::ClassRedefinition::ReverifyClass(const RedefinitionDataIter &cur_data) { - if (!needs_reverify_) { - return; - } - VLOG(plugin) << "Reverifying " << class_sig_ << " due to soft failures"; - std::string error; - // TODO Make verification log level lower - art::verifier::FailureKind failure = - art::verifier::ClassVerifier::ReverifyClass(driver_->self_, - cur_data.GetMirrorClass(), - /*log_level=*/ - art::verifier::HardFailLogMode::kLogWarning, - /*api_level=*/ - art::Runtime::Current()->GetTargetSdkVersion(), - &error); - CHECK_NE(failure, art::verifier::FailureKind::kHardFailure); -} - void Redefiner::ClassRedefinition::UpdateMethods(art::ObjPtr<art::mirror::Class> mclass, const art::dex::ClassDef& class_def) { art::ClassLinker* linker = driver_->runtime_->GetClassLinker(); @@ -3050,25 +3013,6 @@ void Redefiner::ClassRedefinition::UpdateClass(const RedefinitionDataIter& holde } else if (!holder.IsActuallyStructural()) { UpdateClassInPlace(holder); } - UpdateClassCommon(holder); -} - -void Redefiner::ClassRedefinition::UpdateClassCommon(const RedefinitionDataIter &cur_data) { - // NB This is after we've already replaced all old-refs with new-refs in the structural case. - art::ObjPtr<art::mirror::Class> klass(cur_data.GetMirrorClass()); - DCHECK(!IsStructuralRedefinition() || klass == cur_data.GetNewClassObject()); - if (!needs_reverify_) { - return; - } - // Force the most restrictive interpreter environment. We don't know what the final verification - // will allow. We will clear these after retrying verification once we drop the mutator-lock. - klass->VisitMethods([](art::ArtMethod* m) REQUIRES_SHARED(art::Locks::mutator_lock_) { - if (!m->IsNative() && m->IsInvokable() && !m->IsObsolete()) { - m->ClearSkipAccessChecks(); - m->SetDontCompile(); - m->SetMustCountLocks(); - } - }, art::kRuntimePointerSize); } // Restores the old obsolete methods maps if it turns out they weren't needed (ie there were no new diff --git a/openjdkjvmti/ti_redefine.h b/openjdkjvmti/ti_redefine.h index d7c7b89899..76de9a7bed 100644 --- a/openjdkjvmti/ti_redefine.h +++ b/openjdkjvmti/ti_redefine.h @@ -240,12 +240,6 @@ class Redefiner { void UpdateClass(const RedefinitionDataIter& cur_data) REQUIRES(art::Locks::mutator_lock_); - void UpdateClassCommon(const RedefinitionDataIter& cur_data) - REQUIRES(art::Locks::mutator_lock_); - - void ReverifyClass(const RedefinitionDataIter& cur_data) - REQUIRES_SHARED(art::Locks::mutator_lock_); - void CollectNewFieldAndMethodMappings(const RedefinitionDataIter& data, std::map<art::ArtMethod*, art::ArtMethod*>* method_map, std::map<art::ArtField*, art::ArtField*>* field_map) @@ -292,10 +286,6 @@ class Redefiner { bool added_fields_ = false; bool added_methods_ = false; bool has_virtuals_ = false; - - // Does the class need to be reverified due to verification soft-fails possibly forcing - // interpreter or lock-counting? - bool needs_reverify_ = false; }; ArtJvmTiEnv* env_; diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index f842265d29..719f0caad8 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -4744,9 +4744,16 @@ verifier::FailureKind ClassLinker::PerformClassVerification(Thread* self, verifier::HardFailLogMode log_level, std::string* error_msg) { Runtime* const runtime = Runtime::Current(); + StackHandleScope<2> hs(self); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache())); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader())); return verifier::ClassVerifier::VerifyClass(self, verifier_deps, - klass.Get(), + dex_cache->GetDexFile(), + klass, + dex_cache, + class_loader, + *klass->GetClassDef(), runtime->GetCompilerCallbacks(), runtime->IsAotCompiler(), log_level, diff --git a/runtime/verifier/class_verifier.cc b/runtime/verifier/class_verifier.cc index 7e0ed1edea..1c8142b642 100644 --- a/runtime/verifier/class_verifier.cc +++ b/runtime/verifier/class_verifier.cc @@ -51,202 +51,39 @@ using android::base::StringPrintf; // sure we only print this once. static bool gPrintedDxMonitorText = false; -// A class used by the verifier to tell users about what options need to be set for given methods. -class VerifierCallback { - public: - virtual ~VerifierCallback() {} - virtual void SetDontCompile(ArtMethod* method, bool value) - REQUIRES_SHARED(Locks::mutator_lock_) = 0; - virtual void SetMustCountLocks(ArtMethod* method, bool value) - REQUIRES_SHARED(Locks::mutator_lock_) = 0; -}; - -class StandardVerifyCallback : public VerifierCallback { - public: - void SetDontCompile(ArtMethod* m, bool value) override REQUIRES_SHARED(Locks::mutator_lock_) { - if (value) { - m->SetDontCompile(); - } - } - void SetMustCountLocks(ArtMethod* m, bool value) override REQUIRES_SHARED(Locks::mutator_lock_) { - if (value) { - m->SetMustCountLocks(); - } - } -}; - -FailureKind ClassVerifier::ReverifyClass(Thread* self, - ObjPtr<mirror::Class> klass, - HardFailLogMode log_level, - uint32_t api_level, - std::string* error) { - DCHECK(!Runtime::Current()->IsAotCompiler()); - StackHandleScope<1> hs(self); - Handle<mirror::Class> h_klass(hs.NewHandle(klass)); - // We don't want to mess with these while other mutators are possibly looking at them. Instead we - // will wait until we can update them while everything is suspended. - class DelayedVerifyCallback : public VerifierCallback { - public: - void SetDontCompile(ArtMethod* m, bool value) override REQUIRES_SHARED(Locks::mutator_lock_) { - dont_compiles_.push_back({ m, value }); - } - void SetMustCountLocks(ArtMethod* m, bool value) override - REQUIRES_SHARED(Locks::mutator_lock_) { - count_locks_.push_back({ m, value }); - } - void UpdateFlags(bool skip_access_checks) REQUIRES(Locks::mutator_lock_) { - for (auto it : count_locks_) { - VLOG(verifier_debug) << "Setting " << it.first->PrettyMethod() << " count locks to " - << it.second; - if (it.second) { - it.first->SetMustCountLocks(); - } else { - it.first->ClearMustCountLocks(); - } - if (skip_access_checks && it.first->IsInvokable() && !it.first->IsNative()) { - it.first->SetSkipAccessChecks(); - } - } - for (auto it : dont_compiles_) { - VLOG(verifier_debug) << "Setting " << it.first->PrettyMethod() << " dont-compile to " - << it.second; - if (it.second) { - it.first->SetDontCompile(); - } else { - it.first->ClearDontCompile(); - } - } - } - - private: - std::vector<std::pair<ArtMethod*, bool>> dont_compiles_; - std::vector<std::pair<ArtMethod*, bool>> count_locks_; - }; - DelayedVerifyCallback dvc; - FailureKind res = CommonVerifyClass(self, - /*verifier_deps=*/nullptr, - h_klass.Get(), - /*callbacks=*/nullptr, - &dvc, - /*allow_soft_failures=*/false, - log_level, - api_level, - error); - DCHECK_NE(res, FailureKind::kHardFailure); - ScopedThreadSuspension sts(Thread::Current(), ThreadState::kSuspended); - ScopedSuspendAll ssa("Update method flags for reverify"); - dvc.UpdateFlags(res == FailureKind::kNoFailure); - return res; -} - -FailureKind ClassVerifier::VerifyClass(Thread* self, - VerifierDeps* verifier_deps, - ObjPtr<mirror::Class> klass, - CompilerCallbacks* callbacks, - bool allow_soft_failures, - HardFailLogMode log_level, - uint32_t api_level, - std::string* error) { - if (klass->IsVerified()) { - return FailureKind::kNoFailure; +static void UpdateMethodFlags(uint32_t method_index, + Handle<mirror::Class> klass, + Handle<mirror::DexCache> dex_cache, + int error_types) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (klass == nullptr) { + DCHECK(Runtime::Current()->IsAotCompiler()); + // Flags will be set at runtime. + return; } - StandardVerifyCallback svc; - return CommonVerifyClass(self, - verifier_deps, - klass, - callbacks, - &svc, - allow_soft_failures, - log_level, - api_level, - error); -} -FailureKind ClassVerifier::CommonVerifyClass(Thread* self, - VerifierDeps* verifier_deps, - ObjPtr<mirror::Class> klass, - CompilerCallbacks* callbacks, - VerifierCallback* verifier_callback, - bool allow_soft_failures, - HardFailLogMode log_level, - uint32_t api_level, - std::string* error) { - bool early_failure = false; - std::string failure_message; - const DexFile& dex_file = klass->GetDexFile(); - const dex::ClassDef* class_def = klass->GetClassDef(); - ObjPtr<mirror::Class> super = klass->GetSuperClass(); - std::string temp; - if (super == nullptr && strcmp("Ljava/lang/Object;", klass->GetDescriptor(&temp)) != 0) { - early_failure = true; - failure_message = " that has no super class"; - } else if (super != nullptr && super->IsFinal()) { - early_failure = true; - failure_message = " that attempts to sub-class final class " + super->PrettyDescriptor(); - } else if (class_def == nullptr) { - early_failure = true; - failure_message = " that isn't present in dex file " + dex_file.GetLocation(); + // Mark methods with DontCompile/MustCountLocks flags. + ClassLinker* const linker = Runtime::Current()->GetClassLinker(); + ArtMethod* method = + klass->FindClassMethod(dex_cache.Get(), method_index, linker->GetImagePointerSize()); + DCHECK(method != nullptr); + DCHECK(method->GetDeclaringClass() == klass.Get()); + if (!CanCompilerHandleVerificationFailure(error_types)) { + method->SetDontCompile(); } - if (early_failure) { - *error = "Verifier rejected class " + klass->PrettyDescriptor() + failure_message; - if (callbacks != nullptr) { - ClassReference ref(&dex_file, klass->GetDexClassDefIndex()); - callbacks->ClassRejected(ref); - } - return FailureKind::kHardFailure; + if ((error_types & VerifyError::VERIFY_ERROR_LOCKING) != 0) { + method->SetMustCountLocks(); } - StackHandleScope<2> hs(self); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache())); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader())); - return VerifyClass(self, - verifier_deps, - &dex_file, - dex_cache, - class_loader, - *class_def, - callbacks, - verifier_callback, - allow_soft_failures, - log_level, - api_level, - error); -} - - -FailureKind ClassVerifier::VerifyClass(Thread* self, - VerifierDeps* verifier_deps, - const DexFile* dex_file, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - const dex::ClassDef& class_def, - CompilerCallbacks* callbacks, - bool allow_soft_failures, - HardFailLogMode log_level, - uint32_t api_level, - std::string* error) { - StandardVerifyCallback svc; - return VerifyClass(self, - verifier_deps, - dex_file, - dex_cache, - class_loader, - class_def, - callbacks, - &svc, - allow_soft_failures, - log_level, - api_level, - error); } FailureKind ClassVerifier::VerifyClass(Thread* self, VerifierDeps* verifier_deps, const DexFile* dex_file, + Handle<mirror::Class> klass, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const dex::ClassDef& class_def, CompilerCallbacks* callbacks, - VerifierCallback* verifier_callback, bool allow_soft_failures, HardFailLogMode log_level, uint32_t api_level, @@ -259,6 +96,9 @@ FailureKind ClassVerifier::VerifyClass(Thread* self, return FailureKind::kHardFailure; } + // Note that `klass` can be a redefined class, not in the loader's table yet. + // Therefore, we do not use it for class resolution, but only when needing to + // update its methods' flags. ClassAccessor accessor(*dex_file, class_def); SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(accessor.GetDescriptor()); metrics::AutoTimer timer{GetMetrics()->ClassVerificationTotalTime()}; @@ -310,33 +150,19 @@ FailureKind ClassVerifier::VerifyClass(Thread* self, *error += " "; *error += hard_failure_msg; } else if (result.kind != FailureKind::kNoFailure) { - // Mark methods with DontCompile/MustCountLocks flags. - const InvokeType type = method.GetInvokeType(class_def.access_flags_); - ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( - method_idx, dex_cache, class_loader, /* referrer= */ nullptr, type); - if (resolved_method == nullptr) { - DCHECK(self->IsExceptionPending()); - // We couldn't resolve the method, but continue regardless. - self->ClearException(); - } else { - DCHECK(resolved_method->GetDeclaringClassUnchecked() != nullptr) << type; - if (!CanCompilerHandleVerificationFailure(result.types)) { - verifier_callback->SetDontCompile(resolved_method, true); - } - if ((result.types & VerifyError::VERIFY_ERROR_LOCKING) != 0) { - verifier_callback->SetMustCountLocks(resolved_method, true); - // Print a warning about expected slow-down. - // Use a string temporary to print one contiguous warning. - std::string tmp = - StringPrintf("Method %s failed lock verification and will run slower.", - resolved_method->PrettyMethod().c_str()); - if (!gPrintedDxMonitorText) { - tmp = tmp + "\nCommon causes for lock verification issues are non-optimized dex code\n" - "and incorrect proguard optimizations."; - gPrintedDxMonitorText = true; - } - LOG(WARNING) << tmp; + UpdateMethodFlags(method.GetIndex(), klass, dex_cache, result.types); + if ((result.types & VerifyError::VERIFY_ERROR_LOCKING) != 0) { + // Print a warning about expected slow-down. + // Use a string temporary to print one contiguous warning. + std::string tmp = + StringPrintf("Method %s failed lock verification and will run slower.", + dex_file->PrettyMethod(method.GetIndex()).c_str()); + if (!gPrintedDxMonitorText) { + tmp = tmp + "\nCommon causes for lock verification issues are non-optimized dex code\n" + "and incorrect proguard optimizations."; + gPrintedDxMonitorText = true; } + LOG(WARNING) << tmp; } } diff --git a/runtime/verifier/class_verifier.h b/runtime/verifier/class_verifier.h index a81b0b86a8..26cdf2b8de 100644 --- a/runtime/verifier/class_verifier.h +++ b/runtime/verifier/class_verifier.h @@ -49,35 +49,17 @@ class ClassLoader; namespace verifier { -class VerifierCallback; class VerifierDeps; // Verifier that ensures the complete class is OK. class ClassVerifier { public: - // Redo verification on a loaded class. This is for use by class redefinition. This must be called - // with all methods already having all of kAccDontCompile and kAccCountLocks and not having - // kAccSkipAccessChecks. This will remove some of these flags from the method. The caller must - // ensure this cannot race with other changes to the verification class flags. - static FailureKind ReverifyClass(Thread* self, - ObjPtr<mirror::Class> klass, - HardFailLogMode log_level, - uint32_t api_level, - std::string* error) - REQUIRES_SHARED(Locks::mutator_lock_); - // Verify a class. Returns "kNoFailure" on success. - static FailureKind VerifyClass(Thread* self, - VerifierDeps* verifier_deps, - ObjPtr<mirror::Class> klass, - CompilerCallbacks* callbacks, - bool allow_soft_failures, - HardFailLogMode log_level, - uint32_t api_level, - std::string* error) - REQUIRES_SHARED(Locks::mutator_lock_); + // The main entrypoint for class verification. During AOT, `klass` can be + // null. static FailureKind VerifyClass(Thread* self, VerifierDeps* verifier_deps, const DexFile* dex_file, + Handle<mirror::Class> klass, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const dex::ClassDef& class_def, @@ -95,30 +77,6 @@ class ClassVerifier { REQUIRES_SHARED(Locks::mutator_lock_); private: - static FailureKind CommonVerifyClass(Thread* self, - VerifierDeps* verifier_deps, - ObjPtr<mirror::Class> klass, - CompilerCallbacks* callbacks, - VerifierCallback* verifier_callback, - bool allow_soft_failures, - HardFailLogMode log_level, - uint32_t api_level, - std::string* error) - REQUIRES_SHARED(Locks::mutator_lock_); - - static FailureKind VerifyClass(Thread* self, - VerifierDeps* verifier_deps, - const DexFile* dex_file, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - const dex::ClassDef& class_def, - CompilerCallbacks* callbacks, - VerifierCallback* verifier_callback, - bool allow_soft_failures, - HardFailLogMode log_level, - uint32_t api_level, - std::string* error) - REQUIRES_SHARED(Locks::mutator_lock_); DISALLOW_COPY_AND_ASSIGN(ClassVerifier); }; diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc index 976198240b..aa794704c5 100644 --- a/runtime/verifier/method_verifier_test.cc +++ b/runtime/verifier/method_verifier_test.cc @@ -41,13 +41,21 @@ class MethodVerifierTest : public CommonRuntimeTest { REQUIRES_SHARED(Locks::mutator_lock_) { ASSERT_FALSE(descriptor.empty()); Thread* self = Thread::Current(); - ObjPtr<mirror::Class> klass = class_linker_->FindSystemClass(self, descriptor.c_str()); + StackHandleScope<3> hs(self); + Handle<mirror::Class> klass( + hs.NewHandle(class_linker_->FindSystemClass(self, descriptor.c_str()))); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache())); + Handle<mirror::ClassLoader> loader(hs.NewHandle(klass->GetClassLoader())); // Verify the class std::string error_msg; FailureKind failure = ClassVerifier::VerifyClass(self, /* verifier_deps= */ nullptr, + dex_cache->GetDexFile(), klass, + dex_cache, + loader, + *klass->GetClassDef(), nullptr, true, HardFailLogMode::kLogWarning, diff --git a/tools/art_verifier/art_verifier.cc b/tools/art_verifier/art_verifier.cc index 313c4705d4..98935a2b4c 100644 --- a/tools/art_verifier/art_verifier.cc +++ b/tools/art_verifier/art_verifier.cc @@ -214,10 +214,11 @@ struct MethodVerifierMain : public CmdlineMain<MethodVerifierArgs> { jobject class_loader = Install(runtime, unique_dex_files, &dex_files); CHECK(class_loader != nullptr); - StackHandleScope<2> scope(soa.Self()); + StackHandleScope<3> scope(soa.Self()); Handle<mirror::ClassLoader> h_loader = scope.NewHandle( soa.Decode<mirror::ClassLoader>(class_loader)); MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr)); + MutableHandle<mirror::DexCache> h_dex_cache(scope.NewHandle<mirror::DexCache>(nullptr)); if (args_->method_verifier_verbose_) { gLogVerbosity.verifier = true; @@ -244,11 +245,16 @@ struct MethodVerifierMain : public CmdlineMain<MethodVerifierArgs> { soa.Self()->ClearException(); continue; } + h_dex_cache.Assign(h_klass->GetDexCache()); std::string error_msg; verifier::FailureKind res = verifier::ClassVerifier::VerifyClass(soa.Self(), /* verifier_deps= */ nullptr, - h_klass.Get(), + h_dex_cache->GetDexFile(), + h_klass, + h_dex_cache, + h_loader, + *h_klass->GetClassDef(), runtime->GetCompilerCallbacks(), true, verifier::HardFailLogMode::kLogWarning, |