Save the non-verified classes in the VerifierDeps.
We will need that information when taking an OTA to make sure
the same set of classes needs to be verified at runtime.
Currently, the vdex file will contain a list of unverified
classes. We could alternatively encode a bit vector of the size
of the type_id array, but the few experiments I did show that
the bit vector is actually larger. We can refine this later.
bug: 30937355
test: m test-art-host
test: verifier_deps_test.cc
Change-Id: I2670e4fd2e54ee7a148246baa705fda3a56617ff
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 6945eb0..b498573 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -565,7 +565,6 @@
"utils_test.cc",
"verifier/method_verifier_test.cc",
"verifier/reg_type_test.cc",
- "verifier/verifier_deps_test.cc",
"zip_archive_test.cc",
],
shared_libs: [
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index cea8377..96586c8 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3696,9 +3696,8 @@
return false;
}
-void ClassLinker::VerifyClass(Thread* self,
- Handle<mirror::Class> klass,
- verifier::HardFailLogMode log_level) {
+verifier::MethodVerifier::FailureKind ClassLinker::VerifyClass(
+ Thread* self, Handle<mirror::Class> klass, verifier::HardFailLogMode log_level) {
{
// TODO: assert that the monitor on the Class is held
ObjectLock<mirror::Class> lock(self, klass);
@@ -3719,16 +3718,16 @@
// this class as a parent to another.
if (klass->IsErroneous()) {
ThrowEarlierClassFailure(klass.Get());
- return;
+ return verifier::MethodVerifier::kHardFailure;
}
// Don't attempt to re-verify if already sufficiently verified.
if (klass->IsVerified()) {
EnsureSkipAccessChecksMethods(klass);
- return;
+ return verifier::MethodVerifier::kNoFailure;
}
if (klass->IsCompileTimeVerified() && Runtime::Current()->IsAotCompiler()) {
- return;
+ return verifier::MethodVerifier::kNoFailure;
}
if (klass->GetStatus() == mirror::Class::kStatusResolved) {
@@ -3744,7 +3743,7 @@
if (!Runtime::Current()->IsVerificationEnabled()) {
mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
EnsureSkipAccessChecksMethods(klass);
- return;
+ return verifier::MethodVerifier::kNoFailure;
}
}
@@ -3754,7 +3753,7 @@
// If we have a superclass and we get a hard verification failure we can return immediately.
if (supertype.Get() != nullptr && !AttemptSupertypeVerification(self, klass, supertype)) {
CHECK(self->IsExceptionPending()) << "Verification error should be pending.";
- return;
+ return verifier::MethodVerifier::kHardFailure;
}
// Verify all default super-interfaces.
@@ -3781,7 +3780,7 @@
} else if (UNLIKELY(!AttemptSupertypeVerification(self, klass, iface))) {
// We had a hard failure while verifying this interface. Just return immediately.
CHECK(self->IsExceptionPending()) << "Verification error should be pending.";
- return;
+ return verifier::MethodVerifier::kHardFailure;
} else if (UNLIKELY(!iface->IsVerified())) {
// We softly failed to verify the iface. Stop checking and clean up.
// Put the iface into the supertype handle so we know what caused us to fail.
@@ -3807,8 +3806,8 @@
// oat_file_class_status == mirror::Class::kStatusError => !preverified
DCHECK(!(oat_file_class_status == mirror::Class::kStatusError) || !preverified);
- verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
std::string error_msg;
+ verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
if (!preverified) {
Runtime* runtime = Runtime::Current();
verifier_failure = verifier::MethodVerifier::VerifyClass(self,
@@ -3881,6 +3880,7 @@
EnsureSkipAccessChecksMethods(klass);
}
}
+ return verifier_failure;
}
void ClassLinker::EnsureSkipAccessChecksMethods(Handle<mirror::Class> klass) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 239e973..fe1b4a8 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -36,6 +36,7 @@
#include "jni.h"
#include "mirror/class.h"
#include "object_callbacks.h"
+#include "verifier/method_verifier.h"
#include "verifier/verifier_log_mode.h"
namespace art {
@@ -483,9 +484,10 @@
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
- void VerifyClass(Thread* self,
- Handle<mirror::Class> klass,
- verifier::HardFailLogMode log_level = verifier::HardFailLogMode::kLogNone)
+ verifier::MethodVerifier::FailureKind VerifyClass(
+ Thread* self,
+ Handle<mirror::Class> klass,
+ verifier::HardFailLogMode log_level = verifier::HardFailLogMode::kLogNone)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!dex_lock_);
bool VerifyClassUsingOatFile(const DexFile& dex_file,
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index 3c7fb7a..4d1e337 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -280,6 +280,22 @@
return callbacks->GetVerifierDeps();
}
+void VerifierDeps::MaybeRecordVerificationStatus(const DexFile& dex_file,
+ uint16_t type_idx,
+ MethodVerifier::FailureKind failure_kind) {
+ if (failure_kind == MethodVerifier::kNoFailure) {
+ // We only record classes that did not fully verify at compile time.
+ return;
+ }
+
+ VerifierDeps* singleton = GetVerifierDepsSingleton();
+ if (singleton != nullptr) {
+ DexFileDeps* dex_deps = singleton->GetDexFileDeps(dex_file);
+ MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+ dex_deps->unverified_classes_.push_back(type_idx);
+ }
+}
+
void VerifierDeps::MaybeRecordClassResolution(const DexFile& dex_file,
uint16_t type_idx,
mirror::Class* klass) {
@@ -360,6 +376,14 @@
}
}
+static inline void EncodeUint16Vector(std::vector<uint8_t>* out,
+ const std::vector<uint16_t>& vector) {
+ EncodeUnsignedLeb128(out, vector.size());
+ for (uint16_t entry : vector) {
+ EncodeUnsignedLeb128(out, entry);
+ }
+}
+
template<typename T>
static inline void DecodeSet(const uint8_t** in, const uint8_t* end, std::set<T>* set) {
DCHECK(set->empty());
@@ -371,6 +395,17 @@
}
}
+static inline void DecodeUint16Vector(const uint8_t** in,
+ const uint8_t* end,
+ std::vector<uint16_t>* vector) {
+ DCHECK(vector->empty());
+ size_t num_entries = DecodeUint32WithOverflowCheck(in, end);
+ vector->reserve(num_entries);
+ for (size_t i = 0; i < num_entries; ++i) {
+ vector->push_back(dchecked_integral_cast<uint16_t>(DecodeUint32WithOverflowCheck(in, end)));
+ }
+}
+
static inline void EncodeStringVector(std::vector<uint8_t>* out,
const std::vector<std::string>& strings) {
EncodeUnsignedLeb128(out, strings.size());
@@ -407,6 +442,7 @@
EncodeSet(buffer, entry.second->direct_methods_);
EncodeSet(buffer, entry.second->virtual_methods_);
EncodeSet(buffer, entry.second->interface_methods_);
+ EncodeUint16Vector(buffer, entry.second->unverified_classes_);
}
}
@@ -423,6 +459,7 @@
DecodeSet(&data_start, data_end, &entry.second->direct_methods_);
DecodeSet(&data_start, data_end, &entry.second->virtual_methods_);
DecodeSet(&data_start, data_end, &entry.second->interface_methods_);
+ DecodeUint16Vector(&data_start, data_end, &entry.second->unverified_classes_);
}
CHECK_LE(data_start, data_end);
}
@@ -463,7 +500,8 @@
(fields_ == rhs.fields_) &&
(direct_methods_ == rhs.direct_methods_) &&
(virtual_methods_ == rhs.virtual_methods_) &&
- (interface_methods_ == rhs.interface_methods_);
+ (interface_methods_ == rhs.interface_methods_) &&
+ (unverified_classes_ == rhs.unverified_classes_);
}
} // namespace verifier
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index 3223f6f..9d2622d 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -26,6 +26,7 @@
#include "base/array_ref.h"
#include "base/mutex.h"
#include "method_resolution_kind.h"
+#include "method_verifier.h" // For MethodVerifier::FailureKind.
#include "obj_ptr.h"
#include "os.h"
@@ -49,6 +50,12 @@
explicit VerifierDeps(const std::vector<const DexFile*>& dex_files)
REQUIRES(!Locks::verifier_deps_lock_);
+ // Record the verification status of the class at `type_idx`.
+ static void MaybeRecordVerificationStatus(const DexFile& dex_file,
+ uint16_t type_idx,
+ MethodVerifier::FailureKind failure_kind)
+ REQUIRES(!Locks::verifier_deps_lock_);
+
// Record the outcome `klass` of resolving type `type_idx` from `dex_file`.
// If `klass` is null, the class is assumed unresolved.
static void MaybeRecordClassResolution(const DexFile& dex_file,
@@ -136,7 +143,7 @@
};
using TypeAssignabilityBase = std::tuple<uint32_t, uint32_t>;
- struct TypeAssignability : public std::tuple<uint32_t, uint32_t> {
+ struct TypeAssignability : public TypeAssignabilityBase {
TypeAssignability() = default;
TypeAssignability(const TypeAssignability&) = default;
TypeAssignability(uint32_t destination_idx, uint32_t source_idx)
@@ -165,6 +172,9 @@
std::set<MethodResolution> virtual_methods_;
std::set<MethodResolution> interface_methods_;
+ // List of classes that were not fully verified in that dex file.
+ std::vector<uint16_t> unverified_classes_;
+
bool Equals(const DexFileDeps& rhs) const;
};
diff --git a/runtime/verifier/verifier_deps_test.cc b/runtime/verifier/verifier_deps_test.cc
deleted file mode 100644
index 71203e6..0000000
--- a/runtime/verifier/verifier_deps_test.cc
+++ /dev/null
@@ -1,1060 +0,0 @@
-/*
- * Copyright (C) 2016 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 "verifier_deps.h"
-
-#include "class_linker.h"
-#include "common_runtime_test.h"
-#include "compiler_callbacks.h"
-#include "dex_file.h"
-#include "handle_scope-inl.h"
-#include "method_verifier-inl.h"
-#include "mirror/class_loader.h"
-#include "runtime.h"
-#include "thread.h"
-#include "scoped_thread_state_change-inl.h"
-
-namespace art {
-namespace verifier {
-
-class VerifierDepsCompilerCallbacks : public CompilerCallbacks {
- public:
- explicit VerifierDepsCompilerCallbacks()
- : CompilerCallbacks(CompilerCallbacks::CallbackMode::kCompileApp),
- deps_(nullptr) {}
-
- void MethodVerified(verifier::MethodVerifier* verifier ATTRIBUTE_UNUSED) OVERRIDE {}
- void ClassRejected(ClassReference ref ATTRIBUTE_UNUSED) OVERRIDE {}
- bool IsRelocationPossible() OVERRIDE { return false; }
-
- verifier::VerifierDeps* GetVerifierDeps() const OVERRIDE { return deps_; }
- void SetVerifierDeps(verifier::VerifierDeps* deps) { deps_ = deps; }
-
- private:
- verifier::VerifierDeps* deps_;
-};
-
-class VerifierDepsTest : public CommonRuntimeTest {
- public:
- void SetUpRuntimeOptions(RuntimeOptions* options) {
- CommonRuntimeTest::SetUpRuntimeOptions(options);
- callbacks_.reset(new VerifierDepsCompilerCallbacks());
- }
-
- mirror::Class* FindClassByName(const std::string& name, ScopedObjectAccess* soa)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::ClassLoader> class_loader_handle(
- hs.NewHandle(soa->Decode<mirror::ClassLoader>(class_loader_)));
- mirror::Class* klass = class_linker_->FindClass(Thread::Current(),
- name.c_str(),
- class_loader_handle);
- if (klass == nullptr) {
- DCHECK(Thread::Current()->IsExceptionPending());
- Thread::Current()->ClearException();
- }
- return klass;
- }
-
- void SetVerifierDeps(const std::vector<const DexFile*>& dex_files) {
- verifier_deps_.reset(new verifier::VerifierDeps(dex_files));
- VerifierDepsCompilerCallbacks* callbacks =
- reinterpret_cast<VerifierDepsCompilerCallbacks*>(callbacks_.get());
- callbacks->SetVerifierDeps(verifier_deps_.get());
- }
-
- void LoadDexFile(ScopedObjectAccess* soa) REQUIRES_SHARED(Locks::mutator_lock_) {
- class_loader_ = LoadDex("VerifierDeps");
- std::vector<const DexFile*> dex_files = GetDexFiles(class_loader_);
- CHECK_EQ(dex_files.size(), 1u);
- dex_file_ = dex_files.front();
-
- SetVerifierDeps(dex_files);
-
- ObjPtr<mirror::ClassLoader> loader = soa->Decode<mirror::ClassLoader>(class_loader_);
- class_linker_->RegisterDexFile(*dex_file_, loader.Ptr());
-
- klass_Main_ = FindClassByName("LMain;", soa);
- CHECK(klass_Main_ != nullptr);
- }
-
- bool VerifyMethod(const std::string& method_name) {
- ScopedObjectAccess soa(Thread::Current());
- LoadDexFile(&soa);
-
- StackHandleScope<2> hs(Thread::Current());
- Handle<mirror::ClassLoader> class_loader_handle(
- hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
- Handle<mirror::DexCache> dex_cache_handle(hs.NewHandle(klass_Main_->GetDexCache()));
-
- const DexFile::ClassDef* class_def = klass_Main_->GetClassDef();
- const uint8_t* class_data = dex_file_->GetClassData(*class_def);
- CHECK(class_data != nullptr);
-
- ClassDataItemIterator it(*dex_file_, class_data);
- while (it.HasNextStaticField() || it.HasNextInstanceField()) {
- it.Next();
- }
-
- ArtMethod* method = nullptr;
- while (it.HasNextDirectMethod()) {
- ArtMethod* resolved_method = class_linker_->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
- *dex_file_,
- it.GetMemberIndex(),
- dex_cache_handle,
- class_loader_handle,
- nullptr,
- it.GetMethodInvokeType(*class_def));
- CHECK(resolved_method != nullptr);
- if (method_name == resolved_method->GetName()) {
- method = resolved_method;
- break;
- }
- it.Next();
- }
- CHECK(method != nullptr);
-
- MethodVerifier verifier(Thread::Current(),
- dex_file_,
- dex_cache_handle,
- class_loader_handle,
- *class_def,
- it.GetMethodCodeItem(),
- it.GetMemberIndex(),
- method,
- it.GetMethodAccessFlags(),
- true /* can_load_classes */,
- true /* allow_soft_failures */,
- true /* need_precise_constants */,
- false /* verify to dump */,
- true /* allow_thread_suspension */);
- verifier.Verify();
- return !verifier.HasFailures();
- }
-
- void VerifyDexFile() {
- std::string error_msg;
- ScopedObjectAccess soa(Thread::Current());
-
- LoadDexFile(&soa);
- SetVerifierDeps({ dex_file_ });
-
- for (size_t i = 0; i < dex_file_->NumClassDefs(); i++) {
- const char* descriptor = dex_file_->GetClassDescriptor(dex_file_->GetClassDef(i));
- mirror::Class* klass = FindClassByName(descriptor, &soa);
- if (klass != nullptr) {
- MethodVerifier::VerifyClass(Thread::Current(),
- klass,
- nullptr,
- true,
- HardFailLogMode::kLogWarning,
- &error_msg);
- }
- }
- }
-
- bool TestAssignabilityRecording(const std::string& dst,
- const std::string& src,
- bool is_strict,
- bool is_assignable) {
- ScopedObjectAccess soa(Thread::Current());
- LoadDexFile(&soa);
- mirror::Class* klass_dst = FindClassByName(dst, &soa);
- DCHECK(klass_dst != nullptr);
- mirror::Class* klass_src = FindClassByName(src, &soa);
- DCHECK(klass_src != nullptr);
- verifier_deps_->AddAssignability(*dex_file_,
- klass_dst,
- klass_src,
- is_strict,
- is_assignable);
- return true;
- }
-
- // Iterates over all assignability records and tries to find an entry which
- // matches the expected destination/source pair.
- bool HasAssignable(const std::string& expected_destination,
- const std::string& expected_source,
- bool expected_is_assignable) {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
- for (auto& dex_dep : verifier_deps_->dex_deps_) {
- const DexFile& dex_file = *dex_dep.first;
- auto& storage = expected_is_assignable ? dex_dep.second->assignable_types_
- : dex_dep.second->unassignable_types_;
- for (auto& entry : storage) {
- std::string actual_destination =
- verifier_deps_->GetStringFromId(dex_file, entry.GetDestination());
- std::string actual_source = verifier_deps_->GetStringFromId(dex_file, entry.GetSource());
- if ((expected_destination == actual_destination) && (expected_source == actual_source)) {
- return true;
- }
- }
- }
- return false;
- }
-
- // Iterates over all class resolution records, finds an entry which matches
- // the given class descriptor and tests its properties.
- bool HasClass(const std::string& expected_klass,
- bool expected_resolved,
- const std::string& expected_access_flags = "") {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
- for (auto& dex_dep : verifier_deps_->dex_deps_) {
- for (auto& entry : dex_dep.second->classes_) {
- if (expected_resolved != entry.IsResolved()) {
- continue;
- }
-
- std::string actual_klass = dex_dep.first->StringByTypeIdx(entry.GetDexTypeIndex());
- if (expected_klass != actual_klass) {
- continue;
- }
-
- if (expected_resolved) {
- // Test access flags. Note that PrettyJavaAccessFlags always appends
- // a space after the modifiers. Add it to the expected access flags.
- std::string actual_access_flags = PrettyJavaAccessFlags(entry.GetAccessFlags());
- if (expected_access_flags + " " != actual_access_flags) {
- continue;
- }
- }
-
- return true;
- }
- }
- return false;
- }
-
- // Iterates over all field resolution records, finds an entry which matches
- // the given field class+name+type and tests its properties.
- bool HasField(const std::string& expected_klass,
- const std::string& expected_name,
- const std::string& expected_type,
- bool expected_resolved,
- const std::string& expected_access_flags = "",
- const std::string& expected_decl_klass = "") {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
- for (auto& dex_dep : verifier_deps_->dex_deps_) {
- for (auto& entry : dex_dep.second->fields_) {
- if (expected_resolved != entry.IsResolved()) {
- continue;
- }
-
- const DexFile::FieldId& field_id = dex_dep.first->GetFieldId(entry.GetDexFieldIndex());
-
- std::string actual_klass = dex_dep.first->StringByTypeIdx(field_id.class_idx_);
- if (expected_klass != actual_klass) {
- continue;
- }
-
- std::string actual_name = dex_dep.first->StringDataByIdx(field_id.name_idx_);
- if (expected_name != actual_name) {
- continue;
- }
-
- std::string actual_type = dex_dep.first->StringByTypeIdx(field_id.type_idx_);
- if (expected_type != actual_type) {
- continue;
- }
-
- if (expected_resolved) {
- // Test access flags. Note that PrettyJavaAccessFlags always appends
- // a space after the modifiers. Add it to the expected access flags.
- std::string actual_access_flags = PrettyJavaAccessFlags(entry.GetAccessFlags());
- if (expected_access_flags + " " != actual_access_flags) {
- continue;
- }
-
- std::string actual_decl_klass = verifier_deps_->GetStringFromId(
- *dex_dep.first, entry.GetDeclaringClassIndex());
- if (expected_decl_klass != actual_decl_klass) {
- continue;
- }
- }
-
- return true;
- }
- }
- return false;
- }
-
- // Iterates over all method resolution records, finds an entry which matches
- // the given field kind+class+name+signature and tests its properties.
- bool HasMethod(const std::string& expected_kind,
- const std::string& expected_klass,
- const std::string& expected_name,
- const std::string& expected_signature,
- bool expected_resolved,
- const std::string& expected_access_flags = "",
- const std::string& expected_decl_klass = "") {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
- for (auto& dex_dep : verifier_deps_->dex_deps_) {
- auto& storage = (expected_kind == "direct") ? dex_dep.second->direct_methods_
- : (expected_kind == "virtual") ? dex_dep.second->virtual_methods_
- : dex_dep.second->interface_methods_;
- for (auto& entry : storage) {
- if (expected_resolved != entry.IsResolved()) {
- continue;
- }
-
- const DexFile::MethodId& method_id = dex_dep.first->GetMethodId(entry.GetDexMethodIndex());
-
- std::string actual_klass = dex_dep.first->StringByTypeIdx(method_id.class_idx_);
- if (expected_klass != actual_klass) {
- continue;
- }
-
- std::string actual_name = dex_dep.first->StringDataByIdx(method_id.name_idx_);
- if (expected_name != actual_name) {
- continue;
- }
-
- std::string actual_signature = dex_dep.first->GetMethodSignature(method_id).ToString();
- if (expected_signature != actual_signature) {
- continue;
- }
-
- if (expected_resolved) {
- // Test access flags. Note that PrettyJavaAccessFlags always appends
- // a space after the modifiers. Add it to the expected access flags.
- std::string actual_access_flags = PrettyJavaAccessFlags(entry.GetAccessFlags());
- if (expected_access_flags + " " != actual_access_flags) {
- continue;
- }
-
- std::string actual_decl_klass = verifier_deps_->GetStringFromId(
- *dex_dep.first, entry.GetDeclaringClassIndex());
- if (expected_decl_klass != actual_decl_klass) {
- continue;
- }
- }
-
- return true;
- }
- }
- return false;
- }
-
- size_t NumberOfCompiledDexFiles() {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
- return verifier_deps_->dex_deps_.size();
- }
-
- size_t HasEachKindOfRecord() {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
- bool has_strings = false;
- bool has_assignability = false;
- bool has_classes = false;
- bool has_fields = false;
- bool has_methods = false;
-
- for (auto& entry : verifier_deps_->dex_deps_) {
- has_strings |= !entry.second->strings_.empty();
- has_assignability |= !entry.second->assignable_types_.empty();
- has_assignability |= !entry.second->unassignable_types_.empty();
- has_classes |= !entry.second->classes_.empty();
- has_fields |= !entry.second->fields_.empty();
- has_methods |= !entry.second->direct_methods_.empty();
- has_methods |= !entry.second->virtual_methods_.empty();
- has_methods |= !entry.second->interface_methods_.empty();
- }
-
- return has_strings && has_assignability && has_classes && has_fields && has_methods;
- }
-
- std::unique_ptr<verifier::VerifierDeps> verifier_deps_;
- const DexFile* dex_file_;
- jobject class_loader_;
- mirror::Class* klass_Main_;
-};
-
-TEST_F(VerifierDepsTest, StringToId) {
- ScopedObjectAccess soa(Thread::Current());
- LoadDexFile(&soa);
-
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
- uint32_t id_Main1 = verifier_deps_->GetIdFromString(*dex_file_, "LMain;");
- ASSERT_LT(id_Main1, dex_file_->NumStringIds());
- ASSERT_EQ("LMain;", verifier_deps_->GetStringFromId(*dex_file_, id_Main1));
-
- uint32_t id_Main2 = verifier_deps_->GetIdFromString(*dex_file_, "LMain;");
- ASSERT_LT(id_Main2, dex_file_->NumStringIds());
- ASSERT_EQ("LMain;", verifier_deps_->GetStringFromId(*dex_file_, id_Main2));
-
- uint32_t id_Lorem1 = verifier_deps_->GetIdFromString(*dex_file_, "Lorem ipsum");
- ASSERT_GE(id_Lorem1, dex_file_->NumStringIds());
- ASSERT_EQ("Lorem ipsum", verifier_deps_->GetStringFromId(*dex_file_, id_Lorem1));
-
- uint32_t id_Lorem2 = verifier_deps_->GetIdFromString(*dex_file_, "Lorem ipsum");
- ASSERT_GE(id_Lorem2, dex_file_->NumStringIds());
- ASSERT_EQ("Lorem ipsum", verifier_deps_->GetStringFromId(*dex_file_, id_Lorem2));
-
- ASSERT_EQ(id_Main1, id_Main2);
- ASSERT_EQ(id_Lorem1, id_Lorem2);
- ASSERT_NE(id_Main1, id_Lorem1);
-}
-
-TEST_F(VerifierDepsTest, Assignable_BothInBoot) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst */ "Ljava/util/TimeZone;",
- /* src */ "Ljava/util/SimpleTimeZone;",
- /* is_strict */ true,
- /* is_assignable */ true));
- ASSERT_TRUE(HasAssignable("Ljava/util/TimeZone;", "Ljava/util/SimpleTimeZone;", true));
-}
-
-TEST_F(VerifierDepsTest, Assignable_DestinationInBoot1) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst */ "Ljava/net/Socket;",
- /* src */ "LMySSLSocket;",
- /* is_strict */ true,
- /* is_assignable */ true));
- ASSERT_TRUE(HasAssignable("Ljava/net/Socket;", "LMySSLSocket;", true));
-}
-
-TEST_F(VerifierDepsTest, Assignable_DestinationInBoot2) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst */ "Ljava/util/TimeZone;",
- /* src */ "LMySimpleTimeZone;",
- /* is_strict */ true,
- /* is_assignable */ true));
- ASSERT_TRUE(HasAssignable("Ljava/util/TimeZone;", "LMySimpleTimeZone;", true));
-}
-
-TEST_F(VerifierDepsTest, Assignable_DestinationInBoot3) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst */ "Ljava/util/Collection;",
- /* src */ "LMyThreadSet;",
- /* is_strict */ true,
- /* is_assignable */ true));
- ASSERT_TRUE(HasAssignable("Ljava/util/Collection;", "LMyThreadSet;", true));
-}
-
-TEST_F(VerifierDepsTest, Assignable_BothArrays_Resolved) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst */ "[[Ljava/util/TimeZone;",
- /* src */ "[[Ljava/util/SimpleTimeZone;",
- /* is_strict */ true,
- /* is_assignable */ true));
- // If the component types of both arrays are resolved, we optimize the list of
- // dependencies by recording a dependency on the component types.
- ASSERT_FALSE(HasAssignable("[[Ljava/util/TimeZone;", "[[Ljava/util/SimpleTimeZone;", true));
- ASSERT_FALSE(HasAssignable("[Ljava/util/TimeZone;", "[Ljava/util/SimpleTimeZone;", true));
- ASSERT_TRUE(HasAssignable("Ljava/util/TimeZone;", "Ljava/util/SimpleTimeZone;", true));
-}
-
-TEST_F(VerifierDepsTest, Assignable_BothArrays_Erroneous) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst */ "[[Ljava/util/TimeZone;",
- /* src */ "[[LMyErroneousTimeZone;",
- /* is_strict */ true,
- /* is_assignable */ true));
- // If the component type of an array is erroneous, we record the dependency on
- // the array type.
- ASSERT_FALSE(HasAssignable("[[Ljava/util/TimeZone;", "[[LMyErroneousTimeZone;", true));
- ASSERT_TRUE(HasAssignable("[Ljava/util/TimeZone;", "[LMyErroneousTimeZone;", true));
- ASSERT_FALSE(HasAssignable("Ljava/util/TimeZone;", "LMyErroneousTimeZone;", true));
-}
-
- // We test that VerifierDeps does not try to optimize by storing assignability
- // of the component types. This is due to the fact that the component type may
- // be an erroneous class, even though the array type has resolved status.
-
-TEST_F(VerifierDepsTest, Assignable_ArrayToInterface1) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst */ "Ljava/io/Serializable;",
- /* src */ "[Ljava/util/TimeZone;",
- /* is_strict */ true,
- /* is_assignable */ true));
- ASSERT_TRUE(HasAssignable("Ljava/io/Serializable;", "[Ljava/util/TimeZone;", true));
-}
-
-TEST_F(VerifierDepsTest, Assignable_ArrayToInterface2) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst */ "Ljava/io/Serializable;",
- /* src */ "[LMyThreadSet;",
- /* is_strict */ true,
- /* is_assignable */ true));
- ASSERT_TRUE(HasAssignable("Ljava/io/Serializable;", "[LMyThreadSet;", true));
-}
-
-TEST_F(VerifierDepsTest, NotAssignable_BothInBoot) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst */ "Ljava/lang/Exception;",
- /* src */ "Ljava/util/SimpleTimeZone;",
- /* is_strict */ true,
- /* is_assignable */ false));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Exception;", "Ljava/util/SimpleTimeZone;", false));
-}
-
-TEST_F(VerifierDepsTest, NotAssignable_DestinationInBoot1) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst */ "Ljava/lang/Exception;",
- /* src */ "LMySSLSocket;",
- /* is_strict */ true,
- /* is_assignable */ false));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Exception;", "LMySSLSocket;", false));
-}
-
-TEST_F(VerifierDepsTest, NotAssignable_DestinationInBoot2) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst */ "Ljava/lang/Exception;",
- /* src */ "LMySimpleTimeZone;",
- /* is_strict */ true,
- /* is_assignable */ false));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Exception;", "LMySimpleTimeZone;", false));
-}
-
-TEST_F(VerifierDepsTest, NotAssignable_BothArrays) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst */ "[Ljava/lang/Exception;",
- /* src */ "[Ljava/util/SimpleTimeZone;",
- /* is_strict */ true,
- /* is_assignable */ false));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Exception;", "Ljava/util/SimpleTimeZone;", false));
-}
-
-TEST_F(VerifierDepsTest, ArgumentType_ResolvedClass) {
- ASSERT_TRUE(VerifyMethod("ArgumentType_ResolvedClass"));
- ASSERT_TRUE(HasClass("Ljava/lang/Thread;", true, "public"));
-}
-
-TEST_F(VerifierDepsTest, ArgumentType_ResolvedReferenceArray) {
- ASSERT_TRUE(VerifyMethod("ArgumentType_ResolvedReferenceArray"));
- ASSERT_TRUE(HasClass("[Ljava/lang/Thread;", true, "public final abstract"));
-}
-
-TEST_F(VerifierDepsTest, ArgumentType_ResolvedPrimitiveArray) {
- ASSERT_TRUE(VerifyMethod("ArgumentType_ResolvedPrimitiveArray"));
- ASSERT_TRUE(HasClass("[B", true, "public final abstract"));
-}
-
-TEST_F(VerifierDepsTest, ArgumentType_UnresolvedClass) {
- ASSERT_TRUE(VerifyMethod("ArgumentType_UnresolvedClass"));
- ASSERT_TRUE(HasClass("LUnresolvedClass;", false));
-}
-
-TEST_F(VerifierDepsTest, ArgumentType_UnresolvedSuper) {
- ASSERT_TRUE(VerifyMethod("ArgumentType_UnresolvedSuper"));
- ASSERT_TRUE(HasClass("LMySetWithUnresolvedSuper;", false));
-}
-
-TEST_F(VerifierDepsTest, ReturnType_Reference) {
- ASSERT_TRUE(VerifyMethod("ReturnType_Reference"));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;", "Ljava/lang/IllegalStateException;", true));
-}
-
-TEST_F(VerifierDepsTest, ReturnType_Array) {
- ASSERT_FALSE(VerifyMethod("ReturnType_Array"));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Integer;", "Ljava/lang/IllegalStateException;", false));
-}
-
-TEST_F(VerifierDepsTest, InvokeArgumentType) {
- ASSERT_TRUE(VerifyMethod("InvokeArgumentType"));
- ASSERT_TRUE(HasClass("Ljava/text/SimpleDateFormat;", true, "public"));
- ASSERT_TRUE(HasClass("Ljava/util/SimpleTimeZone;", true, "public"));
- ASSERT_TRUE(HasMethod("virtual",
- "Ljava/text/SimpleDateFormat;",
- "setTimeZone",
- "(Ljava/util/TimeZone;)V",
- true,
- "public",
- "Ljava/text/DateFormat;"));
- ASSERT_TRUE(HasAssignable("Ljava/util/TimeZone;", "Ljava/util/SimpleTimeZone;", true));
-}
-
-TEST_F(VerifierDepsTest, MergeTypes_RegisterLines) {
- ASSERT_TRUE(VerifyMethod("MergeTypes_RegisterLines"));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Exception;", "LMySocketTimeoutException;", true));
- ASSERT_TRUE(HasAssignable(
- "Ljava/lang/Exception;", "Ljava/util/concurrent/TimeoutException;", true));
-}
-
-TEST_F(VerifierDepsTest, MergeTypes_IfInstanceOf) {
- ASSERT_TRUE(VerifyMethod("MergeTypes_IfInstanceOf"));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Exception;", "Ljava/net/SocketTimeoutException;", true));
- ASSERT_TRUE(HasAssignable(
- "Ljava/lang/Exception;", "Ljava/util/concurrent/TimeoutException;", true));
- ASSERT_TRUE(HasAssignable("Ljava/net/SocketTimeoutException;", "Ljava/lang/Exception;", false));
-}
-
-TEST_F(VerifierDepsTest, MergeTypes_Unresolved) {
- ASSERT_TRUE(VerifyMethod("MergeTypes_Unresolved"));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Exception;", "Ljava/net/SocketTimeoutException;", true));
- ASSERT_TRUE(HasAssignable(
- "Ljava/lang/Exception;", "Ljava/util/concurrent/TimeoutException;", true));
-}
-
-TEST_F(VerifierDepsTest, ConstClass_Resolved) {
- ASSERT_TRUE(VerifyMethod("ConstClass_Resolved"));
- ASSERT_TRUE(HasClass("Ljava/lang/IllegalStateException;", true, "public"));
-}
-
-TEST_F(VerifierDepsTest, ConstClass_Unresolved) {
- ASSERT_TRUE(VerifyMethod("ConstClass_Unresolved"));
- ASSERT_TRUE(HasClass("LUnresolvedClass;", false));
-}
-
-TEST_F(VerifierDepsTest, CheckCast_Resolved) {
- ASSERT_TRUE(VerifyMethod("CheckCast_Resolved"));
- ASSERT_TRUE(HasClass("Ljava/lang/IllegalStateException;", true, "public"));
-}
-
-TEST_F(VerifierDepsTest, CheckCast_Unresolved) {
- ASSERT_TRUE(VerifyMethod("CheckCast_Unresolved"));
- ASSERT_TRUE(HasClass("LUnresolvedClass;", false));
-}
-
-TEST_F(VerifierDepsTest, InstanceOf_Resolved) {
- ASSERT_TRUE(VerifyMethod("InstanceOf_Resolved"));
- ASSERT_TRUE(HasClass("Ljava/lang/IllegalStateException;", true, "public"));
-}
-
-TEST_F(VerifierDepsTest, InstanceOf_Unresolved) {
- ASSERT_TRUE(VerifyMethod("InstanceOf_Unresolved"));
- ASSERT_TRUE(HasClass("LUnresolvedClass;", false));
-}
-
-TEST_F(VerifierDepsTest, NewInstance_Resolved) {
- ASSERT_TRUE(VerifyMethod("NewInstance_Resolved"));
- ASSERT_TRUE(HasClass("Ljava/lang/IllegalStateException;", true, "public"));
-}
-
-TEST_F(VerifierDepsTest, NewInstance_Unresolved) {
- ASSERT_TRUE(VerifyMethod("NewInstance_Unresolved"));
- ASSERT_TRUE(HasClass("LUnresolvedClass;", false));
-}
-
-TEST_F(VerifierDepsTest, NewArray_Resolved) {
- ASSERT_TRUE(VerifyMethod("NewArray_Resolved"));
- ASSERT_TRUE(HasClass("[Ljava/lang/IllegalStateException;", true, "public final abstract"));
-}
-
-TEST_F(VerifierDepsTest, NewArray_Unresolved) {
- ASSERT_TRUE(VerifyMethod("NewArray_Unresolved"));
- ASSERT_TRUE(HasClass("[LUnresolvedClass;", false));
-}
-
-TEST_F(VerifierDepsTest, Throw) {
- ASSERT_TRUE(VerifyMethod("Throw"));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;", "Ljava/lang/IllegalStateException;", true));
-}
-
-TEST_F(VerifierDepsTest, MoveException_Resolved) {
- ASSERT_TRUE(VerifyMethod("MoveException_Resolved"));
- ASSERT_TRUE(HasClass("Ljava/io/InterruptedIOException;", true, "public"));
- ASSERT_TRUE(HasClass("Ljava/net/SocketTimeoutException;", true, "public"));
- ASSERT_TRUE(HasClass("Ljava/util/zip/ZipException;", true, "public"));
-
- // Testing that all exception types are assignable to Throwable.
- ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;", "Ljava/io/InterruptedIOException;", true));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;", "Ljava/net/SocketTimeoutException;", true));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;", "Ljava/util/zip/ZipException;", true));
-
- // Testing that the merge type is assignable to Throwable.
- ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;", "Ljava/io/IOException;", true));
-
- // Merging of exception types.
- ASSERT_TRUE(HasAssignable("Ljava/io/IOException;", "Ljava/io/InterruptedIOException;", true));
- ASSERT_TRUE(HasAssignable("Ljava/io/IOException;", "Ljava/util/zip/ZipException;", true));
- ASSERT_TRUE(HasAssignable(
- "Ljava/io/InterruptedIOException;", "Ljava/net/SocketTimeoutException;", true));
-}
-
-TEST_F(VerifierDepsTest, MoveException_Unresolved) {
- ASSERT_FALSE(VerifyMethod("MoveException_Unresolved"));
- ASSERT_TRUE(HasClass("LUnresolvedException;", false));
-}
-
-TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInReferenced) {
- ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInReferenced"));
- ASSERT_TRUE(HasClass("Ljava/lang/System;", true, "public final"));
- ASSERT_TRUE(HasField("Ljava/lang/System;",
- "out",
- "Ljava/io/PrintStream;",
- true,
- "public final static",
- "Ljava/lang/System;"));
-}
-
-TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInSuperclass1) {
- ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInSuperclass1"));
- ASSERT_TRUE(HasClass("Ljava/util/SimpleTimeZone;", true, "public"));
- ASSERT_TRUE(HasField(
- "Ljava/util/SimpleTimeZone;", "LONG", "I", true, "public final static", "Ljava/util/TimeZone;"));
-}
-
-TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInSuperclass2) {
- ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInSuperclass2"));
- ASSERT_TRUE(HasField(
- "LMySimpleTimeZone;", "SHORT", "I", true, "public final static", "Ljava/util/TimeZone;"));
-}
-
-TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInInterface1) {
- ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInInterface1"));
- ASSERT_TRUE(HasClass("Ljavax/xml/transform/dom/DOMResult;", true, "public"));
- ASSERT_TRUE(HasField("Ljavax/xml/transform/dom/DOMResult;",
- "PI_ENABLE_OUTPUT_ESCAPING",
- "Ljava/lang/String;",
- true,
- "public final static",
- "Ljavax/xml/transform/Result;"));
-}
-
-TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInInterface2) {
- ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInInterface2"));
- ASSERT_TRUE(HasField("LMyDOMResult;",
- "PI_ENABLE_OUTPUT_ESCAPING",
- "Ljava/lang/String;",
- true,
- "public final static",
- "Ljavax/xml/transform/Result;"));
-}
-
-TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInInterface3) {
- ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInInterface3"));
- ASSERT_TRUE(HasField("LMyResult;",
- "PI_ENABLE_OUTPUT_ESCAPING",
- "Ljava/lang/String;",
- true,
- "public final static",
- "Ljavax/xml/transform/Result;"));
-}
-
-TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInInterface4) {
- ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInInterface4"));
- ASSERT_TRUE(HasField("LMyDocument;",
- "ELEMENT_NODE",
- "S",
- true,
- "public final static",
- "Lorg/w3c/dom/Node;"));
-}
-
-TEST_F(VerifierDepsTest, StaticField_Unresolved_ReferrerInBoot) {
- ASSERT_TRUE(VerifyMethod("StaticField_Unresolved_ReferrerInBoot"));
- ASSERT_TRUE(HasClass("Ljava/util/TimeZone;", true, "public abstract"));
- ASSERT_TRUE(HasField("Ljava/util/TimeZone;", "x", "I", false));
-}
-
-TEST_F(VerifierDepsTest, StaticField_Unresolved_ReferrerInDex) {
- ASSERT_TRUE(VerifyMethod("StaticField_Unresolved_ReferrerInDex"));
- ASSERT_TRUE(HasField("LMyThreadSet;", "x", "I", false));
-}
-
-TEST_F(VerifierDepsTest, InstanceField_Resolved_DeclaredInReferenced) {
- ASSERT_TRUE(VerifyMethod("InstanceField_Resolved_DeclaredInReferenced"));
- ASSERT_TRUE(HasClass("Ljava/io/InterruptedIOException;", true, "public"));
- ASSERT_TRUE(HasField("Ljava/io/InterruptedIOException;",
- "bytesTransferred",
- "I",
- true,
- "public",
- "Ljava/io/InterruptedIOException;"));
- ASSERT_TRUE(HasAssignable(
- "Ljava/io/InterruptedIOException;", "LMySocketTimeoutException;", true));
-}
-
-TEST_F(VerifierDepsTest, InstanceField_Resolved_DeclaredInSuperclass1) {
- ASSERT_TRUE(VerifyMethod("InstanceField_Resolved_DeclaredInSuperclass1"));
- ASSERT_TRUE(HasClass("Ljava/net/SocketTimeoutException;", true, "public"));
- ASSERT_TRUE(HasField("Ljava/net/SocketTimeoutException;",
- "bytesTransferred",
- "I",
- true,
- "public",
- "Ljava/io/InterruptedIOException;"));
- ASSERT_TRUE(HasAssignable(
- "Ljava/io/InterruptedIOException;", "LMySocketTimeoutException;", true));
-}
-
-TEST_F(VerifierDepsTest, InstanceField_Resolved_DeclaredInSuperclass2) {
- ASSERT_TRUE(VerifyMethod("InstanceField_Resolved_DeclaredInSuperclass2"));
- ASSERT_TRUE(HasField("LMySocketTimeoutException;",
- "bytesTransferred",
- "I",
- true,
- "public",
- "Ljava/io/InterruptedIOException;"));
- ASSERT_TRUE(HasAssignable(
- "Ljava/io/InterruptedIOException;", "LMySocketTimeoutException;", true));
-}
-
-TEST_F(VerifierDepsTest, InstanceField_Unresolved_ReferrerInBoot) {
- ASSERT_TRUE(VerifyMethod("InstanceField_Unresolved_ReferrerInBoot"));
- ASSERT_TRUE(HasClass("Ljava/io/InterruptedIOException;", true, "public"));
- ASSERT_TRUE(HasField("Ljava/io/InterruptedIOException;", "x", "I", false));
-}
-
-TEST_F(VerifierDepsTest, InstanceField_Unresolved_ReferrerInDex) {
- ASSERT_TRUE(VerifyMethod("InstanceField_Unresolved_ReferrerInDex"));
- ASSERT_TRUE(HasField("LMyThreadSet;", "x", "I", false));
-}
-
-TEST_F(VerifierDepsTest, InvokeStatic_Resolved_DeclaredInReferenced) {
- ASSERT_TRUE(VerifyMethod("InvokeStatic_Resolved_DeclaredInReferenced"));
- ASSERT_TRUE(HasClass("Ljava/net/Socket;", true, "public"));
- ASSERT_TRUE(HasMethod("direct",
- "Ljava/net/Socket;",
- "setSocketImplFactory",
- "(Ljava/net/SocketImplFactory;)V",
- true,
- "public static",
- "Ljava/net/Socket;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeStatic_Resolved_DeclaredInSuperclass1) {
- ASSERT_TRUE(VerifyMethod("InvokeStatic_Resolved_DeclaredInSuperclass1"));
- ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract"));
- ASSERT_TRUE(HasMethod("direct",
- "Ljavax/net/ssl/SSLSocket;",
- "setSocketImplFactory",
- "(Ljava/net/SocketImplFactory;)V",
- true,
- "public static",
- "Ljava/net/Socket;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeStatic_Resolved_DeclaredInSuperclass2) {
- ASSERT_TRUE(VerifyMethod("InvokeStatic_Resolved_DeclaredInSuperclass2"));
- ASSERT_TRUE(HasMethod("direct",
- "LMySSLSocket;",
- "setSocketImplFactory",
- "(Ljava/net/SocketImplFactory;)V",
- true,
- "public static",
- "Ljava/net/Socket;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeStatic_DeclaredInInterface1) {
- ASSERT_TRUE(VerifyMethod("InvokeStatic_DeclaredInInterface1"));
- ASSERT_TRUE(HasClass("Ljava/util/Map$Entry;", true, "public abstract interface"));
- ASSERT_TRUE(HasMethod("direct",
- "Ljava/util/Map$Entry;",
- "comparingByKey",
- "()Ljava/util/Comparator;",
- true,
- "public static",
- "Ljava/util/Map$Entry;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeStatic_DeclaredInInterface2) {
- ASSERT_FALSE(VerifyMethod("InvokeStatic_DeclaredInInterface2"));
- ASSERT_TRUE(HasClass("Ljava/util/AbstractMap$SimpleEntry;", true, "public"));
- ASSERT_TRUE(HasMethod("direct",
- "Ljava/util/AbstractMap$SimpleEntry;",
- "comparingByKey",
- "()Ljava/util/Comparator;",
- false));
-}
-
-TEST_F(VerifierDepsTest, InvokeStatic_Unresolved1) {
- ASSERT_FALSE(VerifyMethod("InvokeStatic_Unresolved1"));
- ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract"));
- ASSERT_TRUE(HasMethod("direct", "Ljavax/net/ssl/SSLSocket;", "x", "()V", false));
-}
-
-TEST_F(VerifierDepsTest, InvokeStatic_Unresolved2) {
- ASSERT_FALSE(VerifyMethod("InvokeStatic_Unresolved2"));
- ASSERT_TRUE(HasMethod("direct", "LMySSLSocket;", "x", "()V", false));
-}
-
-TEST_F(VerifierDepsTest, InvokeDirect_Resolved_DeclaredInReferenced) {
- ASSERT_TRUE(VerifyMethod("InvokeDirect_Resolved_DeclaredInReferenced"));
- ASSERT_TRUE(HasClass("Ljava/net/Socket;", true, "public"));
- ASSERT_TRUE(HasMethod(
- "direct", "Ljava/net/Socket;", "<init>", "()V", true, "public", "Ljava/net/Socket;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeDirect_Resolved_DeclaredInSuperclass1) {
- ASSERT_FALSE(VerifyMethod("InvokeDirect_Resolved_DeclaredInSuperclass1"));
- ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract"));
- ASSERT_TRUE(HasMethod("direct",
- "Ljavax/net/ssl/SSLSocket;",
- "checkOldImpl",
- "()V",
- true,
- "private",
- "Ljava/net/Socket;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeDirect_Resolved_DeclaredInSuperclass2) {
- ASSERT_FALSE(VerifyMethod("InvokeDirect_Resolved_DeclaredInSuperclass2"));
- ASSERT_TRUE(HasMethod(
- "direct", "LMySSLSocket;", "checkOldImpl", "()V", true, "private", "Ljava/net/Socket;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeDirect_Unresolved1) {
- ASSERT_FALSE(VerifyMethod("InvokeDirect_Unresolved1"));
- ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract"));
- ASSERT_TRUE(HasMethod("direct", "Ljavax/net/ssl/SSLSocket;", "x", "()V", false));
-}
-
-TEST_F(VerifierDepsTest, InvokeDirect_Unresolved2) {
- ASSERT_FALSE(VerifyMethod("InvokeDirect_Unresolved2"));
- ASSERT_TRUE(HasMethod("direct", "LMySSLSocket;", "x", "()V", false));
-}
-
-TEST_F(VerifierDepsTest, InvokeVirtual_Resolved_DeclaredInReferenced) {
- ASSERT_TRUE(VerifyMethod("InvokeVirtual_Resolved_DeclaredInReferenced"));
- ASSERT_TRUE(HasClass("Ljava/lang/Throwable;", true, "public"));
- ASSERT_TRUE(HasMethod("virtual",
- "Ljava/lang/Throwable;",
- "getMessage",
- "()Ljava/lang/String;",
- true,
- "public",
- "Ljava/lang/Throwable;"));
- // Type dependency on `this` argument.
- ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;", "LMySocketTimeoutException;", true));
-}
-
-TEST_F(VerifierDepsTest, InvokeVirtual_Resolved_DeclaredInSuperclass1) {
- ASSERT_TRUE(VerifyMethod("InvokeVirtual_Resolved_DeclaredInSuperclass1"));
- ASSERT_TRUE(HasClass("Ljava/io/InterruptedIOException;", true, "public"));
- ASSERT_TRUE(HasMethod("virtual",
- "Ljava/io/InterruptedIOException;",
- "getMessage",
- "()Ljava/lang/String;",
- true,
- "public",
- "Ljava/lang/Throwable;"));
- // Type dependency on `this` argument.
- ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;", "LMySocketTimeoutException;", true));
-}
-
-TEST_F(VerifierDepsTest, InvokeVirtual_Resolved_DeclaredInSuperclass2) {
- ASSERT_TRUE(VerifyMethod("InvokeVirtual_Resolved_DeclaredInSuperclass2"));
- ASSERT_TRUE(HasMethod("virtual",
- "LMySocketTimeoutException;",
- "getMessage",
- "()Ljava/lang/String;",
- true,
- "public",
- "Ljava/lang/Throwable;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeVirtual_Resolved_DeclaredInSuperinterface) {
- ASSERT_TRUE(VerifyMethod("InvokeVirtual_Resolved_DeclaredInSuperinterface"));
- ASSERT_TRUE(HasMethod("virtual",
- "LMyThreadSet;",
- "size",
- "()I",
- true,
- "public abstract",
- "Ljava/util/Set;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeVirtual_Unresolved1) {
- ASSERT_FALSE(VerifyMethod("InvokeVirtual_Unresolved1"));
- ASSERT_TRUE(HasClass("Ljava/io/InterruptedIOException;", true, "public"));
- ASSERT_TRUE(HasMethod("virtual", "Ljava/io/InterruptedIOException;", "x", "()V", false));
-}
-
-TEST_F(VerifierDepsTest, InvokeVirtual_Unresolved2) {
- ASSERT_FALSE(VerifyMethod("InvokeVirtual_Unresolved2"));
- ASSERT_TRUE(HasMethod("virtual", "LMySocketTimeoutException;", "x", "()V", false));
-}
-
-TEST_F(VerifierDepsTest, InvokeVirtual_ActuallyDirect) {
- ASSERT_FALSE(VerifyMethod("InvokeVirtual_ActuallyDirect"));
- ASSERT_TRUE(HasMethod("virtual", "LMyThread;", "activeCount", "()I", false));
- ASSERT_TRUE(HasMethod("direct",
- "LMyThread;",
- "activeCount",
- "()I",
- true,
- "public static",
- "Ljava/lang/Thread;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInReferenced) {
- ASSERT_TRUE(VerifyMethod("InvokeInterface_Resolved_DeclaredInReferenced"));
- ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public abstract interface"));
- ASSERT_TRUE(HasMethod("interface",
- "Ljava/lang/Runnable;",
- "run",
- "()V",
- true,
- "public abstract",
- "Ljava/lang/Runnable;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInSuperclass) {
- ASSERT_FALSE(VerifyMethod("InvokeInterface_Resolved_DeclaredInSuperclass"));
- ASSERT_TRUE(HasMethod("interface", "LMyThread;", "join", "()V", false));
-}
-
-TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInSuperinterface1) {
- ASSERT_FALSE(VerifyMethod("InvokeInterface_Resolved_DeclaredInSuperinterface1"));
- ASSERT_TRUE(HasMethod("interface",
- "LMyThreadSet;",
- "run",
- "()V",
- true,
- "public abstract",
- "Ljava/lang/Runnable;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInSuperinterface2) {
- ASSERT_FALSE(VerifyMethod("InvokeInterface_Resolved_DeclaredInSuperinterface2"));
- ASSERT_TRUE(HasMethod("interface",
- "LMyThreadSet;",
- "isEmpty",
- "()Z",
- true,
- "public abstract",
- "Ljava/util/Set;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeInterface_Unresolved1) {
- ASSERT_FALSE(VerifyMethod("InvokeInterface_Unresolved1"));
- ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public abstract interface"));
- ASSERT_TRUE(HasMethod("interface", "Ljava/lang/Runnable;", "x", "()V", false));
-}
-
-TEST_F(VerifierDepsTest, InvokeInterface_Unresolved2) {
- ASSERT_FALSE(VerifyMethod("InvokeInterface_Unresolved2"));
- ASSERT_TRUE(HasMethod("interface", "LMyThreadSet;", "x", "()V", false));
-}
-
-TEST_F(VerifierDepsTest, InvokeSuper_ThisAssignable) {
- ASSERT_TRUE(VerifyMethod("InvokeSuper_ThisAssignable"));
- ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public abstract interface"));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Runnable;", "LMain;", true));
- ASSERT_TRUE(HasMethod("interface",
- "Ljava/lang/Runnable;",
- "run",
- "()V",
- true,
- "public abstract",
- "Ljava/lang/Runnable;"));
-}
-
-TEST_F(VerifierDepsTest, InvokeSuper_ThisNotAssignable) {
- ASSERT_FALSE(VerifyMethod("InvokeSuper_ThisNotAssignable"));
- ASSERT_TRUE(HasClass("Ljava/lang/Integer;", true, "public final"));
- ASSERT_TRUE(HasAssignable("Ljava/lang/Integer;", "LMain;", false));
- ASSERT_TRUE(HasMethod(
- "virtual", "Ljava/lang/Integer;", "intValue", "()I", true, "public", "Ljava/lang/Integer;"));
-}
-
-TEST_F(VerifierDepsTest, EncodeDecode) {
- VerifyDexFile();
-
- ASSERT_EQ(1u, NumberOfCompiledDexFiles());
- ASSERT_TRUE(HasEachKindOfRecord());
-
- std::vector<uint8_t> buffer;
- verifier_deps_->Encode(&buffer);
- ASSERT_FALSE(buffer.empty());
-
- VerifierDeps decoded_deps({ dex_file_ }, ArrayRef<uint8_t>(buffer));
- ASSERT_TRUE(verifier_deps_->Equals(decoded_deps));
-}
-
-} // namespace verifier
-} // namespace art