summaryrefslogtreecommitdiff
path: root/runtime/verifier
diff options
context:
space:
mode:
author Andreas Gampe <agampe@google.com> 2019-03-13 15:49:20 -0700
committer Treehugger Robot <treehugger-gerrit@google.com> 2019-03-15 16:11:36 +0000
commita43ba3da86c046c545a988f3d40f53c24a525f83 (patch)
treea66479561d9f14a9b19e31a9a6851f81ae50673c /runtime/verifier
parente37b7915908dba10e90c39a3a82cb0cd1dc05f5c (diff)
ART: Add ClassVerifier
Remove class handling from MethodVerifier. Test: m test-art-host Change-Id: I0e125e0c8a852936ed7cff0f349a7fde97f62826
Diffstat (limited to 'runtime/verifier')
-rw-r--r--runtime/verifier/class_verifier.cc206
-rw-r--r--runtime/verifier/class_verifier.h86
-rw-r--r--runtime/verifier/method_verifier.cc150
-rw-r--r--runtime/verifier/method_verifier.h22
-rw-r--r--runtime/verifier/method_verifier_test.cc3
5 files changed, 295 insertions, 172 deletions
diff --git a/runtime/verifier/class_verifier.cc b/runtime/verifier/class_verifier.cc
new file mode 100644
index 0000000000..649fb112d3
--- /dev/null
+++ b/runtime/verifier/class_verifier.cc
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "class_verifier.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "art_method-inl.h"
+#include "base/systrace.h"
+#include "base/utils.h"
+#include "class_linker.h"
+#include "compiler_callbacks.h"
+#include "dex/class_accessor-inl.h"
+#include "dex/class_reference.h"
+#include "dex/descriptors_names.h"
+#include "dex/dex_file-inl.h"
+#include "handle_scope-inl.h"
+#include "method_verifier-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/dex_cache.h"
+#include "runtime.h"
+
+namespace art {
+namespace verifier {
+
+using android::base::StringPrintf;
+
+// We print a warning blurb about "dx --no-optimize" when we find monitor-locking issues. Make
+// sure we only print this once.
+static bool gPrintedDxMonitorText = false;
+
+FailureKind ClassVerifier::VerifyClass(Thread* self,
+ 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;
+ }
+ 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();
+ }
+ 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;
+ }
+ 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,
+ &dex_file,
+ dex_cache,
+ class_loader,
+ *class_def,
+ callbacks,
+ allow_soft_failures,
+ log_level,
+ api_level,
+ error);
+}
+
+FailureKind ClassVerifier::VerifyClass(Thread* self,
+ 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) {
+ // A class must not be abstract and final.
+ if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) {
+ *error = "Verifier rejected class ";
+ *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
+ *error += ": class is abstract and final.";
+ return FailureKind::kHardFailure;
+ }
+
+ ClassAccessor accessor(*dex_file, class_def);
+ SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(accessor.GetDescriptor());
+
+ int64_t previous_method_idx[2] = { -1, -1 };
+ MethodVerifier::FailureData failure_data;
+ ClassLinker* const linker = Runtime::Current()->GetClassLinker();
+
+ for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+ int64_t* previous_idx = &previous_method_idx[method.IsStaticOrDirect() ? 0u : 1u];
+ self->AllowThreadSuspension();
+ const uint32_t method_idx = method.GetIndex();
+ if (method_idx == *previous_idx) {
+ // smali can create dex files with two encoded_methods sharing the same method_idx
+ // http://code.google.com/p/smali/issues/detail?id=119
+ continue;
+ }
+ *previous_idx = method_idx;
+ 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;
+ }
+ std::string hard_failure_msg;
+ MethodVerifier::FailureData result =
+ MethodVerifier::VerifyMethod(self,
+ method_idx,
+ dex_file,
+ dex_cache,
+ class_loader,
+ class_def,
+ method.GetCodeItem(),
+ resolved_method,
+ method.GetAccessFlags(),
+ callbacks,
+ allow_soft_failures,
+ log_level,
+ /*need_precise_constants=*/ false,
+ api_level,
+ &hard_failure_msg);
+ if (result.kind == FailureKind::kHardFailure) {
+ if (failure_data.kind == FailureKind::kHardFailure) {
+ // If we logged an error before, we need a newline.
+ *error += "\n";
+ } else {
+ // If we didn't log a hard failure before, print the header of the message.
+ *error += "Verifier rejected class ";
+ *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
+ *error += ":";
+ }
+ *error += " ";
+ *error += hard_failure_msg;
+ }
+ failure_data.Merge(result);
+ }
+
+ if (failure_data.kind == FailureKind::kNoFailure) {
+ return FailureKind::kNoFailure;
+ } else {
+ if ((failure_data.types & VERIFY_ERROR_LOCKING) != 0) {
+ // Print a warning about expected slow-down. Use a string temporary to print one contiguous
+ // warning.
+ std::string tmp =
+ StringPrintf("Class %s failed lock verification and will run slower.",
+ PrettyDescriptor(accessor.GetDescriptor()).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;
+ }
+ return failure_data.kind;
+ }
+}
+
+void ClassVerifier::Init() {
+ MethodVerifier::Init();
+}
+
+void ClassVerifier::Shutdown() {
+ MethodVerifier::Shutdown();
+}
+
+void ClassVerifier::VisitStaticRoots(RootVisitor* visitor) {
+ MethodVerifier::VisitStaticRoots(visitor);
+}
+
+} // namespace verifier
+} // namespace art
diff --git a/runtime/verifier/class_verifier.h b/runtime/verifier/class_verifier.h
new file mode 100644
index 0000000000..b7d38500cc
--- /dev/null
+++ b/runtime/verifier/class_verifier.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_VERIFIER_CLASS_VERIFIER_H_
+#define ART_RUNTIME_VERIFIER_CLASS_VERIFIER_H_
+
+#include <string>
+
+#include <android-base/macros.h>
+#include <android-base/thread_annotations.h>
+
+#include "base/locks.h"
+#include "handle.h"
+#include "obj_ptr.h"
+#include "verifier_enums.h"
+
+namespace art {
+
+class CompilerCallbacks;
+class DexFile;
+class RootVisitor;
+class Thread;
+
+namespace dex {
+struct ClassDef;
+} // namespace dex
+
+namespace mirror {
+class Class;
+class DexCache;
+class ClassLoader;
+} // namespace mirror
+
+namespace verifier {
+
+// Verifier that ensures the complete class is OK.
+class ClassVerifier {
+ public:
+ // Verify a class. Returns "kNoFailure" on success.
+ static FailureKind VerifyClass(Thread* self,
+ 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_);
+ static FailureKind VerifyClass(Thread* self,
+ 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)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static void Init() REQUIRES_SHARED(Locks::mutator_lock_);
+ static void Shutdown();
+
+ static void VisitStaticRoots(RootVisitor* visitor)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ClassVerifier);
+};
+
+} // namespace verifier
+} // namespace art
+
+#endif // ART_RUNTIME_VERIFIER_CLASS_VERIFIER_H_
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 91eba2149b..f32dd739ad 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -73,10 +73,6 @@ static constexpr bool kTimeVerifyMethod = !kIsDebugBuild;
// On VLOG(verifier), should we dump the whole state when we run into a hard failure?
static constexpr bool kDumpRegLinesOnHardFailureIfVLOG = true;
-// We print a warning blurb about "dx --no-optimize" when we find monitor-locking issues. Make
-// sure we only print this once.
-static bool gPrintedDxMonitorText = false;
-
PcToRegisterLineTable::PcToRegisterLineTable(ScopedArenaAllocator& allocator)
: register_lines_(allocator.Adapter(kArenaAllocVerifier)) {}
@@ -145,55 +141,6 @@ static void SafelyMarkAllRegistersAsConflicts(MethodVerifier* verifier, Register
reg_line->MarkAllRegistersAsConflicts(verifier);
}
-FailureKind MethodVerifier::VerifyClass(Thread* self,
- 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;
- }
- 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();
- }
- 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;
- }
- 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,
- &dex_file,
- dex_cache,
- class_loader,
- *class_def,
- callbacks,
- allow_soft_failures,
- log_level,
- api_level,
- error);
-}
-
static FailureKind FailureKindMax(FailureKind fk1, FailureKind fk2) {
static_assert(FailureKind::kNoFailure < FailureKind::kSoftFailure
&& FailureKind::kSoftFailure < FailureKind::kHardFailure,
@@ -206,103 +153,6 @@ void MethodVerifier::FailureData::Merge(const MethodVerifier::FailureData& fd) {
types |= fd.types;
}
-FailureKind MethodVerifier::VerifyClass(Thread* self,
- 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) {
- // A class must not be abstract and final.
- if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) {
- *error = "Verifier rejected class ";
- *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
- *error += ": class is abstract and final.";
- return FailureKind::kHardFailure;
- }
-
- ClassAccessor accessor(*dex_file, class_def);
- SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(accessor.GetDescriptor());
-
- int64_t previous_method_idx[2] = { -1, -1 };
- MethodVerifier::FailureData failure_data;
- ClassLinker* const linker = Runtime::Current()->GetClassLinker();
-
- for (const ClassAccessor::Method& method : accessor.GetMethods()) {
- int64_t* previous_idx = &previous_method_idx[method.IsStaticOrDirect() ? 0u : 1u];
- self->AllowThreadSuspension();
- const uint32_t method_idx = method.GetIndex();
- if (method_idx == *previous_idx) {
- // smali can create dex files with two encoded_methods sharing the same method_idx
- // http://code.google.com/p/smali/issues/detail?id=119
- continue;
- }
- *previous_idx = method_idx;
- 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;
- }
- std::string hard_failure_msg;
- MethodVerifier::FailureData result = VerifyMethod(self,
- method_idx,
- dex_file,
- dex_cache,
- class_loader,
- class_def,
- method.GetCodeItem(),
- resolved_method,
- method.GetAccessFlags(),
- callbacks,
- allow_soft_failures,
- log_level,
- /*need_precise_constants=*/ false,
- api_level,
- &hard_failure_msg);
- if (result.kind == FailureKind::kHardFailure) {
- if (failure_data.kind == FailureKind::kHardFailure) {
- // If we logged an error before, we need a newline.
- *error += "\n";
- } else {
- // If we didn't log a hard failure before, print the header of the message.
- *error += "Verifier rejected class ";
- *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
- *error += ":";
- }
- *error += " ";
- *error += hard_failure_msg;
- }
- failure_data.Merge(result);
- }
-
- if (failure_data.kind == FailureKind::kNoFailure) {
- return FailureKind::kNoFailure;
- } else {
- if ((failure_data.types & VERIFY_ERROR_LOCKING) != 0) {
- // Print a warning about expected slow-down. Use a string temporary to print one contiguous
- // warning.
- std::string tmp =
- StringPrintf("Class %s failed lock verification and will run slower.",
- PrettyDescriptor(accessor.GetDescriptor()).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;
- }
- return failure_data.kind;
- }
-}
-
static bool IsLargeMethod(const CodeItemDataAccessor& accessor) {
if (!accessor.HasCodeItem()) {
return false;
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index c178df05a4..92abe9bd5d 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -99,27 +99,6 @@ class PcToRegisterLineTable {
// The verifier
class MethodVerifier {
public:
- // Verify a class. Returns "kNoFailure" on success.
- static FailureKind VerifyClass(Thread* self,
- 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_);
- static FailureKind VerifyClass(Thread* self,
- 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)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
static MethodVerifier* VerifyMethodAndDump(Thread* self,
VariableIndentationOutputStream* vios,
uint32_t method_idx,
@@ -807,6 +786,7 @@ class MethodVerifier {
const uint32_t api_level_;
friend class art::Thread;
+ friend class ClassVerifier;
friend class VerifierDepsTest;
DISALLOW_COPY_AND_ASSIGN(MethodVerifier);
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index 09171a4342..e56cde9d41 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -23,6 +23,7 @@
#include "base/utils.h"
#include "class_linker-inl.h"
+#include "class_verifier.h"
#include "common_runtime_test.h"
#include "dex/dex_file-inl.h"
#include "scoped_thread_state_change-inl.h"
@@ -41,7 +42,7 @@ class MethodVerifierTest : public CommonRuntimeTest {
// Verify the class
std::string error_msg;
- FailureKind failure = MethodVerifier::VerifyClass(
+ FailureKind failure = ClassVerifier::VerifyClass(
self, klass, nullptr, true, HardFailLogMode::kLogWarning, /* api_level= */ 0u, &error_msg);
if (android::base::StartsWith(descriptor, "Ljava/lang/invoke")) {