diff options
| -rw-r--r-- | dex2oat/driver/compiler_driver.cc | 5 | ||||
| -rw-r--r-- | dex2oat/verifier_deps_test.cc | 742 | ||||
| -rw-r--r-- | runtime/vdex_file.h | 4 | ||||
| -rw-r--r-- | runtime/verifier/method_verifier.cc | 14 | ||||
| -rw-r--r-- | runtime/verifier/verifier_deps.cc | 404 | ||||
| -rw-r--r-- | runtime/verifier/verifier_deps.h | 136 |
6 files changed, 7 insertions, 1298 deletions
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc index c08227a1b8..f03113fefd 100644 --- a/dex2oat/driver/compiler_driver.cc +++ b/dex2oat/driver/compiler_driver.cc @@ -1933,12 +1933,13 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, ClassReference ref(dex_file, accessor.GetClassDefIndex()); const ClassStatus existing = ClassStatus::kNotReady; ClassStateTable::InsertResult result = - compiled_classes_.Insert(ref, existing, ClassStatus::kVerified); + compiled_classes_.Insert(ref, existing, ClassStatus::kVerifiedNeedsAccessChecks); CHECK_EQ(result, ClassStateTable::kInsertResultSuccess) << ref.dex_file->GetLocation(); } else { // Update the class status, so later compilation stages know they don't need to verify // the class. - LoadAndUpdateStatus(accessor, ClassStatus::kVerified, class_loader, soa.Self()); + LoadAndUpdateStatus( + accessor, ClassStatus::kVerifiedNeedsAccessChecks, class_loader, soa.Self()); // Create `VerifiedMethod`s for each methods, the compiler expects one for // quickening or compiling. // Note that this means: diff --git a/dex2oat/verifier_deps_test.cc b/dex2oat/verifier_deps_test.cc index 79cd69a732..0e0ce91025 100644 --- a/dex2oat/verifier_deps_test.cc +++ b/dex2oat/verifier_deps_test.cc @@ -239,7 +239,7 @@ class VerifierDepsTest : public CommonCompilerDriverTest { } else if (&cls->GetDexFile() != dex_file) { // Ignore classes from different dex files. } else if (verified_classes[i]) { - ASSERT_EQ(cls->GetStatus(), ClassStatus::kVerified); + ASSERT_EQ(cls->GetStatus(), ClassStatus::kVerifiedNeedsAccessChecks); } else { ASSERT_LT(cls->GetStatus(), ClassStatus::kVerified); } @@ -291,141 +291,6 @@ class VerifierDepsTest : public CommonCompilerDriverTest { 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 = "") { - 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 = "") { - for (auto& dex_dep : verifier_deps_->dex_deps_) { - for (auto& entry : dex_dep.second->fields_) { - if (expected_resolved != entry.IsResolved()) { - continue; - } - - const dex::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_klass, - const std::string& expected_name, - const std::string& expected_signature, - bool expect_resolved, - const std::string& expected_access_flags = "", - const std::string& expected_decl_klass = "") { - for (auto& dex_dep : verifier_deps_->dex_deps_) { - for (const VerifierDeps::MethodResolution& entry : dex_dep.second->methods_) { - if (expect_resolved != entry.IsResolved()) { - continue; - } - - const dex::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 (expect_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() { return verifier_deps_->dex_deps_.size(); } @@ -437,9 +302,6 @@ class VerifierDepsTest : public CommonCompilerDriverTest { bool HasEachKindOfRecord() { bool has_strings = false; bool has_assignability = false; - bool has_classes = false; - bool has_fields = false; - bool has_methods = false; bool has_verified_classes = false; bool has_unverified_classes = false; bool has_redefined_classes = false; @@ -449,9 +311,6 @@ class VerifierDepsTest : public CommonCompilerDriverTest { 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->methods_.empty(); has_verified_classes |= HasBoolValue(entry.second->verified_classes_, true); has_unverified_classes |= HasBoolValue(entry.second->verified_classes_, false); has_redefined_classes |= HasBoolValue(entry.second->redefined_classes_, true); @@ -460,9 +319,6 @@ class VerifierDepsTest : public CommonCompilerDriverTest { return has_strings && has_assignability && - has_classes && - has_fields && - has_methods && has_verified_classes && has_unverified_classes && has_redefined_classes && @@ -605,21 +461,6 @@ TEST_F(VerifierDepsTest, NotAssignable_BothArrays) { 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_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)); @@ -632,14 +473,6 @@ TEST_F(VerifierDepsTest, ReturnType_Array) { 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("Ljava/text/SimpleDateFormat;", - "setTimeZone", - "(Ljava/util/TimeZone;)V", - /* expect_resolved= */ true, - "public", - "Ljava/text/DateFormat;")); ASSERT_TRUE(HasAssignable("Ljava/util/TimeZone;", "Ljava/util/SimpleTimeZone;", true)); } @@ -665,51 +498,6 @@ TEST_F(VerifierDepsTest, MergeTypes_Unresolved) { "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_FALSE(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_FALSE(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_FALSE(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_FALSE(VerifyMethod("NewInstance_Unresolved")); - ASSERT_TRUE(HasClass("LUnresolvedClass;", false)); -} - -TEST_F(VerifierDepsTest, NewArray_Unresolved) { - ASSERT_FALSE(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)); @@ -717,9 +505,6 @@ TEST_F(VerifierDepsTest, Throw) { 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)); @@ -736,404 +521,44 @@ TEST_F(VerifierDepsTest, MoveException_Resolved) { "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")); - ASSERT_TRUE(HasField("Ljava/lang/System;", - "out", - "Ljava/io/PrintStream;", - true, - "public 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 static", "Ljava/util/TimeZone;")); -} - -TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInSuperclass2) { - ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInSuperclass2")); - ASSERT_TRUE(HasField( - "LMySimpleTimeZone;", "SHORT", "I", true, "public 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 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 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 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 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")); - 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;", "Ljava/net/SocketTimeoutException;", 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;", "Ljava/net/SocketTimeoutException;", 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;", "Ljava/net/SocketTimeoutException;", 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("Ljava/net/Socket;", - "setSocketImplFactory", - "(Ljava/net/SocketImplFactory;)V", - /* expect_resolved= */ 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")); - ASSERT_TRUE(HasMethod("Ljavax/net/ssl/SSLSocket;", - "setSocketImplFactory", - "(Ljava/net/SocketImplFactory;)V", - /* expect_resolved= */ true, - "public static", - "Ljava/net/Socket;")); -} - -TEST_F(VerifierDepsTest, InvokeStatic_Resolved_DeclaredInSuperclass2) { - ASSERT_TRUE(VerifyMethod("InvokeStatic_Resolved_DeclaredInSuperclass2")); - ASSERT_TRUE(HasMethod("LMySSLSocket;", - "setSocketImplFactory", - "(Ljava/net/SocketImplFactory;)V", - /* expect_resolved= */ 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 interface")); - ASSERT_TRUE(HasMethod("Ljava/util/Map$Entry;", - "comparingByKey", - "()Ljava/util/Comparator;", - /* expect_resolved= */ 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("Ljava/util/AbstractMap$SimpleEntry;", - "comparingByKey", - "()Ljava/util/Comparator;", - /* expect_resolved= */ false)); -} - -TEST_F(VerifierDepsTest, InvokeStatic_Unresolved1) { - ASSERT_FALSE(VerifyMethod("InvokeStatic_Unresolved1")); - ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public")); - ASSERT_TRUE(HasMethod("Ljavax/net/ssl/SSLSocket;", - "x", - "()V", - /* expect_resolved= */ false)); -} - -TEST_F(VerifierDepsTest, InvokeStatic_Unresolved2) { - ASSERT_FALSE(VerifyMethod("InvokeStatic_Unresolved2")); - ASSERT_TRUE(HasMethod("LMySSLSocket;", - "x", - "()V", - /* expect_resolved= */ false)); -} - -TEST_F(VerifierDepsTest, InvokeDirect_Resolved_DeclaredInReferenced) { - ASSERT_TRUE(VerifyMethod("InvokeDirect_Resolved_DeclaredInReferenced")); - ASSERT_TRUE(HasClass("Ljava/net/Socket;", true, "public")); - ASSERT_TRUE(HasMethod("Ljava/net/Socket;", - "<init>", - "()V", - /* expect_resolved= */ 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")); - ASSERT_TRUE(HasMethod("Ljavax/net/ssl/SSLSocket;", - "checkOldImpl", - "()V", - /* expect_resolved= */ true, - "private", - "Ljava/net/Socket;")); -} - -TEST_F(VerifierDepsTest, InvokeDirect_Resolved_DeclaredInSuperclass2) { - ASSERT_FALSE(VerifyMethod("InvokeDirect_Resolved_DeclaredInSuperclass2")); - ASSERT_TRUE(HasMethod("LMySSLSocket;", - "checkOldImpl", - "()V", - /* expect_resolved= */ true, - "private", - "Ljava/net/Socket;")); -} - -TEST_F(VerifierDepsTest, InvokeDirect_Unresolved1) { - ASSERT_FALSE(VerifyMethod("InvokeDirect_Unresolved1")); - ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public")); - ASSERT_TRUE(HasMethod("Ljavax/net/ssl/SSLSocket;", - "x", - "()V", - /* expect_resolved= */ false)); -} - -TEST_F(VerifierDepsTest, InvokeDirect_Unresolved2) { - ASSERT_FALSE(VerifyMethod("InvokeDirect_Unresolved2")); - ASSERT_TRUE(HasMethod("LMySSLSocket;", - "x", - "()V", - /* expect_resolved= */ false)); -} - TEST_F(VerifierDepsTest, InvokeVirtual_Resolved_DeclaredInReferenced) { ASSERT_TRUE(VerifyMethod("InvokeVirtual_Resolved_DeclaredInReferenced")); - ASSERT_TRUE(HasClass("Ljava/lang/Throwable;", true, "public")); - ASSERT_TRUE(HasMethod("Ljava/lang/Throwable;", - "getMessage", - "()Ljava/lang/String;", - /* expect_resolved= */ true, - "public", - "Ljava/lang/Throwable;")); // Type dependency on `this` argument. ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;", "Ljava/net/SocketTimeoutException;", true)); } TEST_F(VerifierDepsTest, InvokeVirtual_Resolved_DeclaredInSuperclass1) { ASSERT_TRUE(VerifyMethod("InvokeVirtual_Resolved_DeclaredInSuperclass1")); - ASSERT_TRUE(HasClass("Ljava/io/InterruptedIOException;", true, "public")); - ASSERT_TRUE(HasMethod("Ljava/io/InterruptedIOException;", - "getMessage", - "()Ljava/lang/String;", - /* expect_resolved= */ true, - "public", - "Ljava/lang/Throwable;")); // Type dependency on `this` argument. ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;", "Ljava/net/SocketTimeoutException;", true)); } -TEST_F(VerifierDepsTest, InvokeVirtual_Resolved_DeclaredInSuperclass2) { - ASSERT_TRUE(VerifyMethod("InvokeVirtual_Resolved_DeclaredInSuperclass2")); - ASSERT_TRUE(HasMethod("LMySocketTimeoutException;", - "getMessage", - "()Ljava/lang/String;", - /* expect_resolved= */ true, - "public", - "Ljava/lang/Throwable;")); -} - -TEST_F(VerifierDepsTest, InvokeVirtual_Resolved_DeclaredInSuperinterface) { - ASSERT_TRUE(VerifyMethod("InvokeVirtual_Resolved_DeclaredInSuperinterface")); - ASSERT_TRUE(HasMethod("LMyThreadSet;", - "size", - "()I", - /* expect_resolved= */ true, - "public", - "Ljava/util/Set;")); -} - -TEST_F(VerifierDepsTest, InvokeVirtual_Unresolved1) { - ASSERT_FALSE(VerifyMethod("InvokeVirtual_Unresolved1")); - ASSERT_TRUE(HasClass("Ljava/io/InterruptedIOException;", true, "public")); - ASSERT_TRUE(HasMethod("Ljava/io/InterruptedIOException;", - "x", - "()V", - /* expect_resolved= */ false)); -} - -TEST_F(VerifierDepsTest, InvokeVirtual_Unresolved2) { - ASSERT_FALSE(VerifyMethod("InvokeVirtual_Unresolved2")); - ASSERT_TRUE(HasMethod("LMySocketTimeoutException;", - "x", - "()V", - /* expect_resolved= */ false)); -} - -TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInReferenced) { - ASSERT_TRUE(VerifyMethod("InvokeInterface_Resolved_DeclaredInReferenced")); - ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public interface")); - ASSERT_TRUE(HasMethod("Ljava/lang/Runnable;", - "run", - "()V", - /* expect_resolved= */ true, - "public", - "Ljava/lang/Runnable;")); -} - -TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInSuperclass) { - ASSERT_FALSE(VerifyMethod("InvokeInterface_Resolved_DeclaredInSuperclass")); - // TODO: Maybe we should not record dependency if the invoke type does not match the lookup type. - ASSERT_TRUE(HasMethod("LMyThread;", - "join", - "()V", - /* expect_resolved= */ true, - "public", - "Ljava/lang/Thread;")); -} - -TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInSuperinterface1) { - ASSERT_FALSE(VerifyMethod("InvokeInterface_Resolved_DeclaredInSuperinterface1")); - // TODO: Maybe we should not record dependency if the invoke type does not match the lookup type. - ASSERT_TRUE(HasMethod("LMyThreadSet;", - "run", - "()V", - /* expect_resolved= */ true, - "public", - "Ljava/lang/Thread;")); -} - -TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInSuperinterface2) { - ASSERT_FALSE(VerifyMethod("InvokeInterface_Resolved_DeclaredInSuperinterface2")); - ASSERT_TRUE(HasMethod("LMyThreadSet;", - "isEmpty", - "()Z", - /* expect_resolved= */ true, - "public", - "Ljava/util/Set;")); -} - -TEST_F(VerifierDepsTest, InvokeInterface_Unresolved1) { - ASSERT_FALSE(VerifyMethod("InvokeInterface_Unresolved1")); - ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public interface")); - ASSERT_TRUE(HasMethod("Ljava/lang/Runnable;", - "x", - "()V", - /* expect_resolved= */ false)); -} - -TEST_F(VerifierDepsTest, InvokeInterface_Unresolved2) { - ASSERT_FALSE(VerifyMethod("InvokeInterface_Unresolved2")); - ASSERT_TRUE(HasMethod("LMyThreadSet;", "x", "()V", /* expect_resolved= */ false)); -} - TEST_F(VerifierDepsTest, InvokeSuper_ThisAssignable) { ASSERT_TRUE(VerifyMethod("InvokeSuper_ThisAssignable")); - ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public interface")); ASSERT_TRUE(HasAssignable("Ljava/lang/Runnable;", "Ljava/lang/Thread;", true)); - ASSERT_TRUE(HasMethod("Ljava/lang/Runnable;", - "run", - "()V", - /* expect_resolved= */ true, - "public", - "Ljava/lang/Runnable;")); } TEST_F(VerifierDepsTest, InvokeSuper_ThisNotAssignable) { ASSERT_FALSE(VerifyMethod("InvokeSuper_ThisNotAssignable")); - ASSERT_TRUE(HasClass("Ljava/lang/Integer;", true, "public")); ASSERT_TRUE(HasAssignable("Ljava/lang/Integer;", "Ljava/lang/Thread;", false)); - ASSERT_TRUE(HasMethod("Ljava/lang/Integer;", - "intValue", "()I", - /* expect_resolved= */ true, - "public", "Ljava/lang/Integer;")); -} - -TEST_F(VerifierDepsTest, ArgumentType_ResolvedReferenceArray) { - ASSERT_TRUE(VerifyMethod("ArgumentType_ResolvedReferenceArray")); - ASSERT_TRUE(HasClass("[Ljava/lang/Thread;", true, "public")); -} - -TEST_F(VerifierDepsTest, NewArray_Resolved) { - ASSERT_TRUE(VerifyMethod("NewArray_Resolved")); - ASSERT_TRUE(HasClass("[Ljava/lang/IllegalStateException;", true, "public")); } TEST_F(VerifierDepsTest, EncodeDecode) { @@ -1199,14 +624,6 @@ TEST_F(VerifierDepsTest, RedefinedClass) { VerifyDexFile(); // Test that a class which redefines a boot classpath class has dependencies recorded. ASSERT_TRUE(HasRedefinedClass("Ljava/net/SocketTimeoutException;")); - // These come from test case InstanceField_Resolved_DeclaredInSuperclass1. - ASSERT_TRUE(HasClass("Ljava/net/SocketTimeoutException;", true, "public")); - ASSERT_TRUE(HasField("Ljava/net/SocketTimeoutException;", - "bytesTransferred", - "I", - true, - "public", - "Ljava/io/InterruptedIOException;")); } TEST_F(VerifierDepsTest, UnverifiedOrder) { @@ -1270,149 +687,6 @@ TEST_F(VerifierDepsTest, VerifyDeps) { ASSERT_FALSE(RunValidation([](VerifierDeps::DexFileDeps& deps) { deps.unassignable_types_.insert(*deps.assignable_types_.begin()); }, buffer, &error_msg)); - - // Mess with classes. - ASSERT_FALSE(RunValidation([](VerifierDeps::DexFileDeps& deps) { - for (const auto& entry : deps.classes_) { - if (entry.IsResolved()) { - deps.classes_.insert(VerifierDeps::ClassResolution( - entry.GetDexTypeIndex(), VerifierDeps::kUnresolvedMarker)); - return; - } - } - LOG(FATAL) << "Could not find any resolved classes"; - UNREACHABLE(); - }, buffer, &error_msg)); - ASSERT_FALSE(RunValidation([](VerifierDeps::DexFileDeps& deps) { - for (const auto& entry : deps.classes_) { - if (!entry.IsResolved()) { - deps.classes_.insert(VerifierDeps::ClassResolution( - entry.GetDexTypeIndex(), VerifierDeps::kUnresolvedMarker - 1)); - return; - } - } - LOG(FATAL) << "Could not find any unresolved classes"; - UNREACHABLE(); - }, buffer, &error_msg)); - ASSERT_FALSE(RunValidation([](VerifierDeps::DexFileDeps& deps) { - for (const auto& entry : deps.classes_) { - if (entry.IsResolved()) { - deps.classes_.insert(VerifierDeps::ClassResolution( - entry.GetDexTypeIndex(), entry.GetAccessFlags() - 1)); - return; - } - } - LOG(FATAL) << "Could not find any resolved classes"; - UNREACHABLE(); - }, buffer, &error_msg)); - - // Mess with fields. - ASSERT_FALSE(RunValidation([](VerifierDeps::DexFileDeps& deps) { - for (const auto& entry : deps.fields_) { - if (entry.IsResolved()) { - deps.fields_.insert(VerifierDeps::FieldResolution(entry.GetDexFieldIndex(), - VerifierDeps::kUnresolvedMarker, - entry.GetDeclaringClassIndex())); - return; - } - } - LOG(FATAL) << "Could not find any resolved fields"; - UNREACHABLE(); - }, buffer, &error_msg)); - ASSERT_FALSE(RunValidation([](VerifierDeps::DexFileDeps& deps) { - for (const auto& entry : deps.fields_) { - if (!entry.IsResolved()) { - constexpr dex::StringIndex kStringIndexZero(0); // We know there is a class there. - deps.fields_.insert(VerifierDeps::FieldResolution(0 /* we know there is a field there */, - VerifierDeps::kUnresolvedMarker - 1, - kStringIndexZero)); - return; - } - } - LOG(FATAL) << "Could not find any unresolved fields"; - UNREACHABLE(); - }, buffer, &error_msg)); - ASSERT_FALSE(RunValidation([](VerifierDeps::DexFileDeps& deps) { - for (const auto& entry : deps.fields_) { - if (entry.IsResolved()) { - deps.fields_.insert(VerifierDeps::FieldResolution(entry.GetDexFieldIndex(), - entry.GetAccessFlags() - 1, - entry.GetDeclaringClassIndex())); - return; - } - } - LOG(FATAL) << "Could not find any resolved fields"; - UNREACHABLE(); - }, buffer, &error_msg)); - ASSERT_FALSE(RunValidation([](VerifierDeps::DexFileDeps& deps) { - for (const auto& entry : deps.fields_) { - constexpr dex::StringIndex kNewTypeIndex(0); - if (entry.GetDeclaringClassIndex() != kNewTypeIndex) { - deps.fields_.insert(VerifierDeps::FieldResolution(entry.GetDexFieldIndex(), - entry.GetAccessFlags(), - kNewTypeIndex)); - return; - } - } - LOG(FATAL) << "Could not find any suitable fields"; - UNREACHABLE(); - }, buffer, &error_msg)); - - // Mess with methods. - ASSERT_FALSE(RunValidation([](VerifierDeps::DexFileDeps& deps) { - std::set<VerifierDeps::MethodResolution>* methods = &deps.methods_; - for (const auto& entry : *methods) { - if (entry.IsResolved()) { - methods->insert(VerifierDeps::MethodResolution(entry.GetDexMethodIndex(), - VerifierDeps::kUnresolvedMarker, - entry.GetDeclaringClassIndex())); - return; - } - } - LOG(FATAL) << "Could not find any resolved methods"; - UNREACHABLE(); - }, buffer, &error_msg)); - ASSERT_FALSE(RunValidation([](VerifierDeps::DexFileDeps& deps) { - std::set<VerifierDeps::MethodResolution>* methods = &deps.methods_; - for (const auto& entry : *methods) { - if (!entry.IsResolved()) { - constexpr dex::StringIndex kStringIndexZero(0); // We know there is a class there. - methods->insert(VerifierDeps::MethodResolution(0 /* we know there is a method there */, - VerifierDeps::kUnresolvedMarker - 1, - kStringIndexZero)); - return; - } - } - LOG(FATAL) << "Could not find any unresolved methods"; - UNREACHABLE(); - }, buffer, &error_msg)); - ASSERT_FALSE(RunValidation([](VerifierDeps::DexFileDeps& deps) { - std::set<VerifierDeps::MethodResolution>* methods = &deps.methods_; - for (const auto& entry : *methods) { - if (entry.IsResolved()) { - methods->insert(VerifierDeps::MethodResolution(entry.GetDexMethodIndex(), - entry.GetAccessFlags() - 1, - entry.GetDeclaringClassIndex())); - return; - } - } - LOG(FATAL) << "Could not find any resolved methods"; - UNREACHABLE(); - }, buffer, &error_msg)); - ASSERT_FALSE(RunValidation([](VerifierDeps::DexFileDeps& deps) { - std::set<VerifierDeps::MethodResolution>* methods = &deps.methods_; - for (const auto& entry : *methods) { - constexpr dex::StringIndex kNewTypeIndex(0); - if (entry.IsResolved() && entry.GetDeclaringClassIndex() != kNewTypeIndex) { - methods->insert(VerifierDeps::MethodResolution(entry.GetDexMethodIndex(), - entry.GetAccessFlags(), - kNewTypeIndex)); - return; - } - } - LOG(FATAL) << "Could not find any suitable methods"; - UNREACHABLE(); - }, buffer, &error_msg)); } TEST_F(VerifierDepsTest, CompilerDriver) { @@ -1439,20 +713,6 @@ TEST_F(VerifierDepsTest, CompilerDriver) { VerifierDeps decoded_deps(dex_files_, /*output_only=*/ false); bool parsed = decoded_deps.ParseStoredData(dex_files_, ArrayRef<const uint8_t>(buffer)); ASSERT_TRUE(parsed); - if (verify_failure) { - // Just taint the decoded VerifierDeps with one invalid entry. - 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); - } VerifyWithCompilerDriver(&decoded_deps); if (verify_failure) { diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h index d2059042c1..98efaa1511 100644 --- a/runtime/vdex_file.h +++ b/runtime/vdex_file.h @@ -114,8 +114,8 @@ class VdexFile { static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' }; // The format version of the verifier deps header and the verifier deps. - // Last update: Add boot checksum, class loader context. - static constexpr uint8_t kVerifierDepsVersion[] = { '0', '2', '1', '\0' }; + // Last update: Remove class/field/method resolution. + static constexpr uint8_t kVerifierDepsVersion[] = { '0', '2', '2', '\0' }; // The format version of the dex section header and the dex section, containing // both the dex code and the quickening data. diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index c33e646823..fea34ef34c 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -3756,9 +3756,6 @@ const RegType& MethodVerifier<kVerifierDebug>::ResolveClass(dex::TypeIndex class return *result; } - // Record result of class resolution attempt. - VerifierDeps::MaybeRecordClassResolution(*dex_file_, class_idx, klass); - // If requested, check if access is allowed. Unresolved types are included in this check, as the // interpreter only tests whether access is allowed when a class is not pre-verified and runs in // the access-checks interpreter. If result is primitive, skip the access check. @@ -3894,11 +3891,6 @@ ArtMethod* MethodVerifier<kVerifierDebug>::ResolveMethodAndCheckAccess( klass, dex_cache_.Get(), class_loader_.Get(), dex_method_idx); } - // Record result of method resolution attempt. The klass resolution has recorded whether - // the class is an interface or not and therefore the type of the lookup performed above. - // TODO: Maybe we should not record dependency if the invoke type does not match the lookup type. - VerifierDeps::MaybeRecordMethodResolution(*dex_file_, dex_method_idx, res_method); - bool must_fail = false; // This is traditional and helps with screwy bytecode. It will tell you that, yes, a method // exists, but that it's called incorrectly. This significantly helps debugging, as locally it's @@ -4674,9 +4666,6 @@ ArtField* MethodVerifier<kVerifierDebug>::GetStaticField(int field_idx) { ClassLinker* class_linker = GetClassLinker(); ArtField* field = class_linker->ResolveFieldJLS(field_idx, dex_cache_, class_loader_); - // Record result of the field resolution attempt. - VerifierDeps::MaybeRecordFieldResolution(*dex_file_, field_idx, field); - if (field == nullptr) { VLOG(verifier) << "Unable to resolve static field " << field_idx << " (" << dex_file_->GetFieldName(field_id) << ") in " @@ -4724,9 +4713,6 @@ ArtField* MethodVerifier<kVerifierDebug>::GetInstanceField(const RegType& obj_ty ClassLinker* class_linker = GetClassLinker(); ArtField* field = class_linker->ResolveFieldJLS(field_idx, dex_cache_, class_loader_); - // Record result of the field resolution attempt. - VerifierDeps::MaybeRecordFieldResolution(*dex_file_, field_idx, field); - if (field == nullptr) { VLOG(verifier) << "Unable to resolve instance field " << field_idx << " (" << dex_file_->GetFieldName(field_id) << ") in " diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc index d06e3d4487..dd68416b55 100644 --- a/runtime/verifier/verifier_deps.cc +++ b/runtime/verifier/verifier_deps.cc @@ -69,9 +69,6 @@ void VerifierDeps::MergeWith(std::unique_ptr<VerifierDeps> other, DCHECK(other_deps.strings_.empty()); my_deps->assignable_types_.merge(other_deps.assignable_types_); my_deps->unassignable_types_.merge(other_deps.unassignable_types_); - my_deps->classes_.merge(other_deps.classes_); - my_deps->fields_.merge(other_deps.fields_); - my_deps->methods_.merge(other_deps.methods_); BitVectorOr(my_deps->verified_classes_, other_deps.verified_classes_); BitVectorOr(my_deps->redefined_classes_, other_deps.redefined_classes_); } @@ -87,22 +84,6 @@ const VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex return (it == dex_deps_.end()) ? nullptr : it->second.get(); } -// Access flags that impact vdex verification. -static constexpr uint32_t kAccVdexAccessFlags = - kAccPublic | kAccPrivate | kAccProtected | kAccStatic | kAccInterface; - -template <typename Ptr> -uint16_t VerifierDeps::GetAccessFlags(Ptr element) { - static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant"); - if (element == nullptr) { - return VerifierDeps::kUnresolvedMarker; - } else { - uint16_t access_flags = Low16Bits(element->GetAccessFlags()) & kAccVdexAccessFlags; - CHECK_NE(access_flags, VerifierDeps::kUnresolvedMarker); - return access_flags; - } -} - dex::StringIndex VerifierDeps::GetClassDescriptorStringId(const DexFile& dex_file, ObjPtr<mirror::Class> klass) { DCHECK(klass != nullptr); @@ -126,61 +107,6 @@ dex::StringIndex VerifierDeps::GetClassDescriptorStringId(const DexFile& dex_fil return GetIdFromString(dex_file, klass->GetDescriptor(&temp)); } -// Try to find the string descriptor of the class. type_idx is a best guess of a matching string id. -static dex::StringIndex TryGetClassDescriptorStringId(const DexFile& dex_file, - dex::TypeIndex type_idx, - ObjPtr<mirror::Class> klass) - REQUIRES_SHARED(Locks::mutator_lock_) { - if (!klass->IsArrayClass()) { - const dex::TypeId& type_id = dex_file.GetTypeId(type_idx); - const DexFile& klass_dex = klass->GetDexFile(); - const dex::TypeId& klass_type_id = klass_dex.GetTypeId(klass->GetClassDef()->class_idx_); - if (strcmp(dex_file.GetTypeDescriptor(type_id), - klass_dex.GetTypeDescriptor(klass_type_id)) == 0) { - return type_id.descriptor_idx_; - } - } - return dex::StringIndex::Invalid(); -} - -dex::StringIndex VerifierDeps::GetMethodDeclaringClassStringId(const DexFile& dex_file, - uint32_t dex_method_index, - ArtMethod* method) { - static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant"); - if (method == nullptr) { - return dex::StringIndex(VerifierDeps::kUnresolvedMarker); - } - const dex::StringIndex string_id = TryGetClassDescriptorStringId( - dex_file, - dex_file.GetMethodId(dex_method_index).class_idx_, - method->GetDeclaringClass()); - if (string_id.IsValid()) { - // Got lucky using the original dex file, return based on the input dex file. - DCHECK_EQ(GetClassDescriptorStringId(dex_file, method->GetDeclaringClass()), string_id); - return string_id; - } - return GetClassDescriptorStringId(dex_file, method->GetDeclaringClass()); -} - -dex::StringIndex VerifierDeps::GetFieldDeclaringClassStringId(const DexFile& dex_file, - uint32_t dex_field_idx, - ArtField* field) { - static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant"); - if (field == nullptr) { - return dex::StringIndex(VerifierDeps::kUnresolvedMarker); - } - const dex::StringIndex string_id = TryGetClassDescriptorStringId( - dex_file, - dex_file.GetFieldId(dex_field_idx).class_idx_, - field->GetDeclaringClass()); - if (string_id.IsValid()) { - // Got lucky using the original dex file, return based on the input dex file. - DCHECK_EQ(GetClassDescriptorStringId(dex_file, field->GetDeclaringClass()), string_id); - return string_id; - } - return GetClassDescriptorStringId(dex_file, field->GetDeclaringClass()); -} - static inline VerifierDeps* GetMainVerifierDeps() { // The main VerifierDeps is the one set in the compiler callbacks, which at the // end of verification will have all the per-thread VerifierDeps merged into it. @@ -289,67 +215,6 @@ bool VerifierDeps::IsInClassPath(ObjPtr<mirror::Class> klass) const { return (GetDexFileDeps(*dex_file) == nullptr); } -void VerifierDeps::AddClassResolution(const DexFile& dex_file, - dex::TypeIndex type_idx, - ObjPtr<mirror::Class> klass) { - DexFileDeps* dex_deps = GetDexFileDeps(dex_file); - if (dex_deps == nullptr) { - // This invocation is from verification of a dex file which is not being compiled. - return; - } - - if (klass != nullptr && !IsInClassPath(klass)) { - // Class resolved into one of the DEX files which are being compiled. - // This is not a classpath dependency. - return; - } - - dex_deps->classes_.emplace(ClassResolution(type_idx, GetAccessFlags(klass))); -} - -void VerifierDeps::AddFieldResolution(const DexFile& dex_file, - uint32_t field_idx, - ArtField* field) { - DexFileDeps* dex_deps = GetDexFileDeps(dex_file); - if (dex_deps == nullptr) { - // This invocation is from verification of a dex file which is not being compiled. - return; - } - - if (field != nullptr && !IsInClassPath(field->GetDeclaringClass())) { - // Field resolved into one of the DEX files which are being compiled. - // This is not a classpath dependency. - return; - } - - dex_deps->fields_.emplace(FieldResolution(field_idx, - GetAccessFlags(field), - GetFieldDeclaringClassStringId(dex_file, - field_idx, - field))); -} - -void VerifierDeps::AddMethodResolution(const DexFile& dex_file, - uint32_t method_idx, - ArtMethod* method) { - DexFileDeps* dex_deps = GetDexFileDeps(dex_file); - if (dex_deps == nullptr) { - // This invocation is from verification of a dex file which is not being compiled. - return; - } - - if (method != nullptr && !IsInClassPath(method->GetDeclaringClass())) { - // Method resolved into one of the DEX files which are being compiled. - // This is not a classpath dependency. - return; - } - - MethodResolution method_tuple(method_idx, - GetAccessFlags(method), - GetMethodDeclaringClassStringId(dex_file, method_idx, method)); - dex_deps->methods_.insert(method_tuple); -} - ObjPtr<mirror::Class> VerifierDeps::FindOneClassPathBoundaryForInterface( ObjPtr<mirror::Class> destination, ObjPtr<mirror::Class> source) const { @@ -538,33 +403,6 @@ void VerifierDeps::RecordClassVerified(const DexFile& dex_file, const dex::Class dex_deps->verified_classes_[dex_file.GetIndexForClassDef(class_def)] = true; } -void VerifierDeps::MaybeRecordClassResolution(const DexFile& dex_file, - dex::TypeIndex type_idx, - ObjPtr<mirror::Class> klass) { - VerifierDeps* thread_deps = GetThreadLocalVerifierDeps(); - if (thread_deps != nullptr) { - thread_deps->AddClassResolution(dex_file, type_idx, klass); - } -} - -void VerifierDeps::MaybeRecordFieldResolution(const DexFile& dex_file, - uint32_t field_idx, - ArtField* field) { - VerifierDeps* thread_deps = GetThreadLocalVerifierDeps(); - if (thread_deps != nullptr) { - thread_deps->AddFieldResolution(dex_file, field_idx, field); - } -} - -void VerifierDeps::MaybeRecordMethodResolution(const DexFile& dex_file, - uint32_t method_idx, - ArtMethod* method) { - VerifierDeps* thread_deps = GetThreadLocalVerifierDeps(); - if (thread_deps != nullptr) { - thread_deps->AddMethodResolution(dex_file, method_idx, method); - } -} - void VerifierDeps::MaybeRecordAssignability(const DexFile& dex_file, ObjPtr<mirror::Class> destination, ObjPtr<mirror::Class> source, @@ -583,27 +421,12 @@ template<typename T> inline uint32_t Encode(T in); template<> inline uint32_t Encode<uint16_t>(uint16_t in) { return in; } -template<> inline uint32_t Encode<uint32_t>(uint32_t in) { - return in; -} -template<> inline uint32_t Encode<dex::TypeIndex>(dex::TypeIndex in) { - return in.index_; -} template<> inline uint32_t Encode<dex::StringIndex>(dex::StringIndex in) { return in.index_; } template<typename T> inline T Decode(uint32_t in); -template<> inline uint16_t Decode<uint16_t>(uint32_t in) { - return dchecked_integral_cast<uint16_t>(in); -} -template<> inline uint32_t Decode<uint32_t>(uint32_t in) { - return in; -} -template<> inline dex::TypeIndex Decode<dex::TypeIndex>(uint32_t in) { - return dex::TypeIndex(in); -} template<> inline dex::StringIndex Decode<dex::StringIndex>(uint32_t in) { return dex::StringIndex(in); } @@ -748,12 +571,6 @@ static inline bool DecodeStringVector(const uint8_t** in, return true; } -static inline std::string ToHex(uint32_t value) { - std::stringstream ss; - ss << std::hex << value << std::dec; - return ss.str(); -} - } // namespace void VerifierDeps::Encode(const std::vector<const DexFile*>& dex_files, @@ -763,9 +580,6 @@ void VerifierDeps::Encode(const std::vector<const DexFile*>& dex_files, EncodeStringVector(buffer, deps.strings_); EncodeSet(buffer, deps.assignable_types_); EncodeSet(buffer, deps.unassignable_types_); - EncodeSet(buffer, deps.classes_); - EncodeSet(buffer, deps.fields_); - EncodeSet(buffer, deps.methods_); EncodeUint16SparseBitVector(buffer, deps.verified_classes_, /* sparse_value= */ false); EncodeUint16SparseBitVector(buffer, deps.redefined_classes_, /* sparse_value= */ true); } @@ -783,9 +597,6 @@ bool VerifierDeps::DecodeDexFileDeps(DexFileDeps& deps, data_start, data_end, &deps.assignable_types_) && DecodeSet</*kFillSet=*/ !kOnlyVerifiedClasses>( data_start, data_end, &deps.unassignable_types_) && - DecodeSet</*kFillSet=*/ !kOnlyVerifiedClasses>(data_start, data_end, &deps.classes_) && - DecodeSet</*kFillSet=*/ !kOnlyVerifiedClasses>(data_start, data_end, &deps.fields_) && - DecodeSet</*kFillSet=*/ !kOnlyVerifiedClasses>(data_start, data_end, &deps.methods_) && DecodeUint16SparseBitVector</*kFillVector=*/ true>( data_start, data_end, num_class_defs, /*sparse_value=*/ false, &deps.verified_classes_) && DecodeUint16SparseBitVector</*kFillVector=*/ !kOnlyVerifiedClasses>( @@ -876,9 +687,6 @@ bool VerifierDeps::DexFileDeps::Equals(const VerifierDeps::DexFileDeps& rhs) con return (strings_ == rhs.strings_) && (assignable_types_ == rhs.assignable_types_) && (unassignable_types_ == rhs.unassignable_types_) && - (classes_ == rhs.classes_) && - (fields_ == rhs.fields_) && - (methods_ == rhs.methods_) && (verified_classes_ == rhs.verified_classes_); } @@ -925,50 +733,6 @@ void VerifierDeps::Dump(VariableIndentationOutputStream* vios) const { << "\n"; } - for (const ClassResolution& entry : dep.second->classes_) { - vios->Stream() - << dex_file.StringByTypeIdx(entry.GetDexTypeIndex()) - << (entry.IsResolved() ? " must be resolved " : "must not be resolved ") - << " with access flags " << std::hex << entry.GetAccessFlags() << std::dec - << "\n"; - } - - for (const FieldResolution& entry : dep.second->fields_) { - const dex::FieldId& field_id = dex_file.GetFieldId(entry.GetDexFieldIndex()); - vios->Stream() - << dex_file.GetFieldDeclaringClassDescriptor(field_id) << "->" - << dex_file.GetFieldName(field_id) << ":" - << dex_file.GetFieldTypeDescriptor(field_id) - << " is expected to be "; - if (!entry.IsResolved()) { - vios->Stream() << "unresolved\n"; - } else { - vios->Stream() - << "in class " - << GetStringFromId(dex_file, entry.GetDeclaringClassIndex()) - << ", and have the access flags " << std::hex << entry.GetAccessFlags() << std::dec - << "\n"; - } - } - - for (const MethodResolution& method : dep.second->methods_) { - const dex::MethodId& method_id = dex_file.GetMethodId(method.GetDexMethodIndex()); - vios->Stream() - << dex_file.GetMethodDeclaringClassDescriptor(method_id) << "->" - << dex_file.GetMethodName(method_id) - << dex_file.GetMethodSignature(method_id).ToString() - << " is expected to be "; - if (!method.IsResolved()) { - vios->Stream() << "unresolved\n"; - } else { - vios->Stream() - << "in class " - << GetStringFromId(dex_file, method.GetDeclaringClassIndex()) - << ", have the access flags " << std::hex << method.GetAccessFlags() << std::dec - << "\n"; - } - } - for (size_t idx = 0; idx < dep.second->verified_classes_.size(); idx++) { if (!dep.second->verified_classes_[idx]) { vios->Stream() @@ -1045,169 +809,6 @@ bool VerifierDeps::VerifyAssignability(Handle<mirror::ClassLoader> class_loader, return true; } -bool VerifierDeps::VerifyClasses(Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, - const std::set<ClassResolution>& classes, - Thread* self, - /* out */ std::string* error_msg) const { - StackHandleScope<1> hs(self); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - MutableHandle<mirror::Class> cls(hs.NewHandle<mirror::Class>(nullptr)); - for (const auto& entry : classes) { - std::string descriptor = dex_file.StringByTypeIdx(entry.GetDexTypeIndex()); - cls.Assign(FindClassAndClearException(class_linker, self, descriptor, class_loader)); - - if (entry.IsResolved()) { - if (cls == nullptr) { - *error_msg = "Could not resolve class " + descriptor; - return false; - } else if (entry.GetAccessFlags() != GetAccessFlags(cls.Get())) { - *error_msg = "Unexpected access flags on class " + descriptor - + " (expected=" + ToHex(entry.GetAccessFlags()) - + ", actual=" + ToHex(GetAccessFlags(cls.Get())) + ")"; - return false; - } - } else if (cls != nullptr) { - *error_msg = "Unexpected successful resolution of class " + descriptor; - return false; - } - } - return true; -} - -static std::string GetFieldDescription(const DexFile& dex_file, uint32_t index) { - const dex::FieldId& field_id = dex_file.GetFieldId(index); - return std::string(dex_file.GetFieldDeclaringClassDescriptor(field_id)) - + "->" - + dex_file.GetFieldName(field_id) - + ":" - + dex_file.GetFieldTypeDescriptor(field_id); -} - -bool VerifierDeps::VerifyFields(Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, - const std::set<FieldResolution>& fields, - Thread* self, - /* out */ std::string* error_msg) const { - // Check recorded fields are resolved the same way, have the same recorded class, - // and have the same recorded flags. - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - for (const auto& entry : fields) { - const dex::FieldId& field_id = dex_file.GetFieldId(entry.GetDexFieldIndex()); - std::string_view name(dex_file.StringDataByIdx(field_id.name_idx_)); - std::string_view type( - dex_file.StringDataByIdx(dex_file.GetTypeId(field_id.type_idx_).descriptor_idx_)); - // Only use field_id.class_idx_ when the entry is unresolved, which is rare. - // Otherwise, we might end up resolving an application class, which is expensive. - std::string expected_decl_klass = entry.IsResolved() - ? GetStringFromId(dex_file, entry.GetDeclaringClassIndex()) - : dex_file.StringByTypeIdx(field_id.class_idx_); - ObjPtr<mirror::Class> cls = FindClassAndClearException( - class_linker, self, expected_decl_klass.c_str(), class_loader); - if (cls == nullptr) { - *error_msg = "Could not resolve class " + expected_decl_klass; - return false; - } - DCHECK(cls->IsResolved()); - - ArtField* field = mirror::Class::FindField(self, cls, name, type); - if (entry.IsResolved()) { - std::string temp; - if (field == nullptr) { - *error_msg = "Could not resolve field " + - GetFieldDescription(dex_file, entry.GetDexFieldIndex()); - return false; - } else if (expected_decl_klass != field->GetDeclaringClass()->GetDescriptor(&temp)) { - *error_msg = "Unexpected declaring class for field resolution " - + GetFieldDescription(dex_file, entry.GetDexFieldIndex()) - + " (expected=" + expected_decl_klass - + ", actual=" + field->GetDeclaringClass()->GetDescriptor(&temp) + ")"; - return false; - } else if (entry.GetAccessFlags() != GetAccessFlags(field)) { - *error_msg = "Unexpected access flags for resolved field " - + GetFieldDescription(dex_file, entry.GetDexFieldIndex()) - + " (expected=" + ToHex(entry.GetAccessFlags()) - + ", actual=" + ToHex(GetAccessFlags(field)) + ")"; - return false; - } - } else if (field != nullptr) { - *error_msg = "Unexpected successful resolution of field " - + GetFieldDescription(dex_file, entry.GetDexFieldIndex()); - return false; - } - } - return true; -} - -static std::string GetMethodDescription(const DexFile& dex_file, uint32_t index) { - const dex::MethodId& method_id = dex_file.GetMethodId(index); - return std::string(dex_file.GetMethodDeclaringClassDescriptor(method_id)) - + "->" - + dex_file.GetMethodName(method_id) - + dex_file.GetMethodSignature(method_id).ToString(); -} - -bool VerifierDeps::VerifyMethods(Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, - const std::set<MethodResolution>& methods, - Thread* self, - /* out */ std::string* error_msg) const { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - PointerSize pointer_size = class_linker->GetImagePointerSize(); - - for (const auto& entry : methods) { - const dex::MethodId& method_id = dex_file.GetMethodId(entry.GetDexMethodIndex()); - - const char* name = dex_file.GetMethodName(method_id); - const Signature signature = dex_file.GetMethodSignature(method_id); - // Only use method_id.class_idx_ when the entry is unresolved, which is rare. - // Otherwise, we might end up resolving an application class, which is expensive. - std::string expected_decl_klass = entry.IsResolved() - ? GetStringFromId(dex_file, entry.GetDeclaringClassIndex()) - : dex_file.StringByTypeIdx(method_id.class_idx_); - - ObjPtr<mirror::Class> cls = FindClassAndClearException( - class_linker, self, expected_decl_klass.c_str(), class_loader); - if (cls == nullptr) { - *error_msg = "Could not resolve class " + expected_decl_klass; - return false; - } - DCHECK(cls->IsResolved()); - ArtMethod* method = nullptr; - if (cls->IsInterface()) { - method = cls->FindInterfaceMethod(name, signature, pointer_size); - } else { - method = cls->FindClassMethod(name, signature, pointer_size); - } - - if (entry.IsResolved()) { - std::string temp; - if (method == nullptr) { - *error_msg = "Could not resolve method " - + GetMethodDescription(dex_file, entry.GetDexMethodIndex()); - return false; - } else if (expected_decl_klass != method->GetDeclaringClass()->GetDescriptor(&temp)) { - *error_msg = "Unexpected declaring class for method resolution " - + GetMethodDescription(dex_file, entry.GetDexMethodIndex()) - + " (expected=" + expected_decl_klass - + ", actual=" + method->GetDeclaringClass()->GetDescriptor(&temp) + ")"; - return false; - } else if (entry.GetAccessFlags() != GetAccessFlags(method)) { - *error_msg = "Unexpected access flags for resolved method resolution " - + GetMethodDescription(dex_file, entry.GetDexMethodIndex()) - + " (expected=" + ToHex(entry.GetAccessFlags()) - + ", actual=" + ToHex(GetAccessFlags(method)) + ")"; - return false; - } - } else if (method != nullptr) { - *error_msg = "Unexpected successful resolution of method " - + GetMethodDescription(dex_file, entry.GetDexMethodIndex()); - return false; - } - } - return true; -} - bool VerifierDeps::IsInDexFiles(const char* descriptor, size_t hash, const std::vector<const DexFile*>& dex_files, @@ -1283,10 +884,7 @@ bool VerifierDeps::VerifyDexFile(Handle<mirror::ClassLoader> class_loader, deps.unassignable_types_, /* expected_assignability= */ false, self, - error_msg) && - VerifyClasses(class_loader, dex_file, deps.classes_, self, error_msg) && - VerifyFields(class_loader, dex_file, deps.fields_, self, error_msg) && - VerifyMethods(class_loader, dex_file, deps.methods_, self, error_msg); + error_msg); } } // namespace verifier diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h index 326ee53c05..15fb4a51d9 100644 --- a/runtime/verifier/verifier_deps.h +++ b/runtime/verifier/verifier_deps.h @@ -84,30 +84,6 @@ class VerifierDeps { static void MaybeRecordClassRedefinition(const DexFile& dex_file, const dex::ClassDef& class_def) 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, - dex::TypeIndex type_idx, - ObjPtr<mirror::Class> klass) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Locks::verifier_deps_lock_); - - // Record the outcome `field` of resolving field `field_idx` from `dex_file`. - // If `field` is null, the field is assumed unresolved. - static void MaybeRecordFieldResolution(const DexFile& dex_file, - uint32_t field_idx, - ArtField* field) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Locks::verifier_deps_lock_); - - // Record the outcome `method` of resolving method `method_idx` from `dex_file`. - // If `method` is null, the method is assumed unresolved. - static void MaybeRecordMethodResolution(const DexFile& dex_file, - uint32_t method_idx, - ArtMethod* method) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Locks::verifier_deps_lock_); - // Record the outcome `is_assignable` of type assignability test from `source` // to `destination` as defined by RegType::AssignableFrom. `dex_file` is the // owner of the method for which MethodVerifier performed the assignability test. @@ -154,48 +130,6 @@ class VerifierDeps { /*out*/std::vector<std::vector<bool>>* verified_classes_per_dex); private: - static constexpr uint16_t kUnresolvedMarker = static_cast<uint16_t>(-1); - - using ClassResolutionBase = std::tuple<dex::TypeIndex, uint16_t>; - struct ClassResolution : public ClassResolutionBase { - ClassResolution() = default; - ClassResolution(const ClassResolution&) = default; - ClassResolution(dex::TypeIndex type_idx, uint16_t access_flags) - : ClassResolutionBase(type_idx, access_flags) {} - - bool IsResolved() const { return GetAccessFlags() != kUnresolvedMarker; } - dex::TypeIndex GetDexTypeIndex() const { return std::get<0>(*this); } - uint16_t GetAccessFlags() const { return std::get<1>(*this); } - }; - - using FieldResolutionBase = std::tuple<uint32_t, uint16_t, dex::StringIndex>; - struct FieldResolution : public FieldResolutionBase { - FieldResolution() = default; - FieldResolution(const FieldResolution&) = default; - FieldResolution(uint32_t field_idx, uint16_t access_flags, dex::StringIndex declaring_class_idx) - : FieldResolutionBase(field_idx, access_flags, declaring_class_idx) {} - - bool IsResolved() const { return GetAccessFlags() != kUnresolvedMarker; } - uint32_t GetDexFieldIndex() const { return std::get<0>(*this); } - uint16_t GetAccessFlags() const { return std::get<1>(*this); } - dex::StringIndex GetDeclaringClassIndex() const { return std::get<2>(*this); } - }; - - using MethodResolutionBase = std::tuple<uint32_t, uint16_t, dex::StringIndex>; - struct MethodResolution : public MethodResolutionBase { - MethodResolution() = default; - MethodResolution(const MethodResolution&) = default; - MethodResolution(uint32_t method_idx, - uint16_t access_flags, - dex::StringIndex declaring_class_idx) - : MethodResolutionBase(method_idx, access_flags, declaring_class_idx) {} - - bool IsResolved() const { return GetAccessFlags() != kUnresolvedMarker; } - uint32_t GetDexMethodIndex() const { return std::get<0>(*this); } - uint16_t GetAccessFlags() const { return std::get<1>(*this); } - dex::StringIndex GetDeclaringClassIndex() const { return std::get<2>(*this); } - }; - using TypeAssignabilityBase = std::tuple<dex::StringIndex, dex::StringIndex>; struct TypeAssignability : public TypeAssignabilityBase { TypeAssignability() = default; @@ -223,11 +157,6 @@ class VerifierDeps { std::set<TypeAssignability> assignable_types_; std::set<TypeAssignability> unassignable_types_; - // Sets of recorded class/field/method resolutions. - std::set<ClassResolution> classes_; - std::set<FieldResolution> fields_; - std::set<MethodResolution> methods_; - // Bit vector indexed by class def indices indicating whether the corresponding // class was successfully verified. std::vector<bool> verified_classes_; @@ -277,46 +206,11 @@ class VerifierDeps { // Returns the string represented by `id`. std::string GetStringFromId(const DexFile& dex_file, dex::StringIndex string_id) const; - // Returns the bytecode access flags of `element` (bottom 16 bits), or - // `kUnresolvedMarker` if `element` is null. - template <typename Ptr> - static uint16_t GetAccessFlags(Ptr element) - REQUIRES_SHARED(Locks::mutator_lock_); - - // Returns a string ID of the descriptor of the declaring class of `element`, - // or `kUnresolvedMarker` if `element` is null. - dex::StringIndex GetMethodDeclaringClassStringId(const DexFile& dex_file, - uint32_t dex_method_idx, - ArtMethod* method) - REQUIRES_SHARED(Locks::mutator_lock_); - dex::StringIndex GetFieldDeclaringClassStringId(const DexFile& dex_file, - uint32_t dex_field_idx, - ArtField* field) - REQUIRES_SHARED(Locks::mutator_lock_); - // Returns a string ID of the descriptor of the class. dex::StringIndex GetClassDescriptorStringId(const DexFile& dex_file, ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::verifier_deps_lock_); - void AddClassResolution(const DexFile& dex_file, - dex::TypeIndex type_idx, - ObjPtr<mirror::Class> klass) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Locks::verifier_deps_lock_); - - void AddFieldResolution(const DexFile& dex_file, - uint32_t field_idx, - ArtField* field) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Locks::verifier_deps_lock_); - - void AddMethodResolution(const DexFile& dex_file, - uint32_t method_idx, - ArtMethod* method) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Locks::verifier_deps_lock_); - void AddAssignability(const DexFile& dex_file, ObjPtr<mirror::Class> destination, ObjPtr<mirror::Class> source, @@ -366,36 +260,6 @@ class VerifierDeps { /* out */ std::string* error_msg) const REQUIRES_SHARED(Locks::mutator_lock_); - // Verify that the set of resolved classes at the point of creation - // of this `VerifierDeps` is still the same. - bool VerifyClasses(Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, - const std::set<ClassResolution>& classes, - Thread* self, - /* out */ std::string* error_msg) const - REQUIRES_SHARED(Locks::mutator_lock_); - - // Verify that the set of resolved fields at the point of creation - // of this `VerifierDeps` is still the same, and each field resolves to the - // same field holder and access flags. - bool VerifyFields(Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, - const std::set<FieldResolution>& classes, - Thread* self, - /* out */ std::string* error_msg) const - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Locks::verifier_deps_lock_); - - // Verify that the set of resolved methods at the point of creation - // of this `VerifierDeps` is still the same, and each method resolves to the - // same method holder, access flags, and invocation kind. - bool VerifyMethods(Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, - const std::set<MethodResolution>& methods, - Thread* self, - /* out */ std::string* error_msg) const - REQUIRES_SHARED(Locks::mutator_lock_); - // Map from DexFiles into dependencies collected from verification of their methods. std::map<const DexFile*, std::unique_ptr<DexFileDeps>> dex_deps_; |