Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/art/art/dex2oat/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 25 kB image not shown  

Quelle  verifier_deps_test.cc

  Sprache: C
 

/*
 * 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.
 */


// Test is in compiler, as it uses compiler related code.
#include "verifier/verifier_deps.h"

#include "aot_class_linker.h"
#include "art_method-inl.h"
#include "base/indenter.h"
#include "class_linker.h"
#include "common_compiler_driver_test.h"
#include "compiler_callbacks.h"
#include "dex/class_accessor-inl.h"
#include "dex/class_iterator.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_types.h"
#include "dex/verification_results.h"
#include "driver/compiler_driver-inl.h"
#include "driver/compiler_options.h"
#include "handle_scope-inl.h"
#include "mirror/class_loader.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "utils/atomic_dex_ref_map-inl.h"
#include "verifier/method_verifier-inl.h"
#include "verifier/reg_type_cache.h"

namespace art {
namespace verifier {

class VerifierDepsCompilerCallbacks : public CompilerCallbacks {
 public:
  VerifierDepsCompilerCallbacks()
      : CompilerCallbacks(CompilerCallbacks::CallbackMode::kCompileApp),
        deps_(nullptr) {}

  ClassLinker* CreateAotClassLinker(InternTable* intern_table) override {
    return new AotClassLinker(intern_table);
  }

  void AddUncompilableMethod([[maybe_unused]] MethodReference ref) override {}
  void AddUncompilableClass([[maybe_unused]] ClassReference ref) override {}
  void ClassRejected([[maybe_unused]] ClassReference ref) override {}
  bool IsUncompilableMethod([[maybe_unused]] MethodReference ref) override { return false; }

  verifier::VerifierDeps* GetVerifierDeps() const override { return deps_; }
  void SetVerifierDeps(verifier::VerifierDeps* deps) override { deps_ = deps; }

 private:
  verifier::VerifierDeps* deps_;
};

class VerifierDepsTest : public CommonCompilerDriverTest {
 public:
  VerifierDepsTest() {
    this->use_boot_image_ = true;  // Make the Runtime creation cheaper.
  }

  void SetUpRuntimeOptions(RuntimeOptions* options) override {
    CommonCompilerTest::SetUpRuntimeOptions(options);
    callbacks_.reset(new VerifierDepsCompilerCallbacks());
  }

  ObjPtr<mirror::Class> FindClassByName(ScopedObjectAccess& soa, const std::string&&nbsp;name)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    StackHandleScope<1> hs(soa.Self());
    Handle<mirror::ClassLoader> class_loader_handle(
        hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
    ObjPtr<mirror::Class> klass =
        class_linker_->FindClass(soa.Self(), name.c_str(), name.length(), class_loader_handle);
    if (klass == nullptr) {
      DCHECK(soa.Self()->IsExceptionPending());
      soa.Self()->ClearException();
    }
    return klass;
  }

  void SetupCompilerDriver() {
    compiler_options_->image_type_ = CompilerOptions::ImageType::kNone;
    compiler_driver_->InitializeThreadPools();
  }

  void VerifyWithCompilerDriver(verifier::VerifierDeps* verifier_deps) {
    TimingLogger timings("Verify"falsefalse);
    // The compiler driver handles the verifier deps in the callbacks, so
    // remove what this class did for unit testing.
    if (verifier_deps == nullptr) {
      // Create some verifier deps by default if they are not already specified.
      verifier_deps = new verifier::VerifierDeps(dex_files_);
      verifier_deps_.reset(verifier_deps);
    }
    callbacks_->SetVerifierDeps(verifier_deps);
    compiler_driver_->Verify(class_loader_, dex_files_, &timings);
    callbacks_->SetVerifierDeps(nullptr);
  }

  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, const char* name1, const char* name2 = nullptr)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    class_loader_ = (name2 == nullptr) ? LoadDex(name1) : LoadMultiDex(name1, name2);
    dex_files_ = GetDexFiles(class_loader_);
    primary_dex_file_ = dex_files_.front();

    SetVerifierDeps(dex_files_);
    StackHandleScope<1> hs(soa.Self());
    Handle<mirror::ClassLoader> loader =
        hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_));
    for (const DexFile* dex_file : dex_files_) {
      class_linker_->RegisterDexFile(*dex_file, loader.Get());
    }
    SetDexFilesForOatFile(dex_files_);
  }

  void LoadDexFile(ScopedObjectAccess& soa) REQUIRES_SHARED(Locks::mutator_lock_) {
    LoadDexFile(soa, "VerifierDeps");
    CHECK_EQ(dex_files_.size(), 1u);
    klass_Main_ = FindClassByName(soa, "LMain;");
    CHECK(klass_Main_ != nullptr);
  }

  bool VerifyMethod(const std::string& method_name) {
    ScopedObjectAccess soa(Thread::Current());
    LoadDexFile(soa);

    StackHandleScope<2> hs(soa.Self());
    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 dex::ClassDef* class_def = klass_Main_->GetClassDef();
    ClassAccessor accessor(*primary_dex_file_, *class_def);

    bool has_failures = true;
    bool found_method = false;

    for (const ClassAccessor::Method& method : accessor.GetMethods()) {
      ArtMethod* resolved_method =
          class_linker_->ResolveMethodId(
              method.GetIndex(),
              dex_cache_handle,
              class_loader_handle);
      CHECK(resolved_method != nullptr);
      if (method_name == resolved_method->GetName()) {
        ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
        RegTypeCache reg_types(
            soa.Self(), class_linker_, arena_pool, class_loader_handle, primary_dex_file_);
        std::unique_ptr<MethodVerifier> verifier(
            MethodVerifier::CreateVerifier(soa.Self(),
                                           ®_types,
                                           callbacks_->GetVerifierDeps(),
                                           dex_cache_handle,
                                           *class_def,
                                           method.GetCodeItem(),
                                           method.GetIndex(),
                                           method.GetAccessFlags(),
                                           /* verify_to_dump= */ false,
                                           /* api_level= */ 0));
        verifier->Verify();
        soa.Self()->SetVerifierDeps(nullptr);
        has_failures = verifier->HasFailures();
        found_method = true;
      }
    }
    CHECK(found_method) << "Expected to find method " << method_name;
    return !has_failures;
  }

  void VerifyDexFile(const char* multidex = nullptr) {
    {
      ScopedObjectAccess soa(Thread::Current());
      LoadDexFile(soa, "VerifierDeps", multidex);
    }
    SetupCompilerDriver();
    VerifyWithCompilerDriver(/* verifier_deps= */ nullptr);
  }

  bool TestAssignabilityRecording(const std::string& dst, const std::string& src) {
    ScopedObjectAccess soa(Thread::Current());
    LoadDexFile(soa);
    StackHandleScope<1> hs(soa.Self());
    Handle<mirror::Class> klass_dst = hs.NewHandle(FindClassByName(soa, dst));
    DCHECK(klass_dst != nullptr) << dst;
    ObjPtr<mirror::Class> klass_src = FindClassByName(soa, src);
    DCHECK(klass_src != nullptr) << src;
    verifier_deps_->AddAssignability(*primary_dex_file_,
                                     primary_dex_file_->GetClassDef(0),
                                     klass_dst.Get(),
                                     klass_src);
    return true;
  }

  // Check that the status of classes in `class_loader_` match the
  // expected status in `deps`.
  void VerifyClassStatus(const verifier::VerifierDeps& deps) {
    ScopedObjectAccess soa(Thread::Current());
    StackHandleScope<2> hs(soa.Self());
    Handle<mirror::ClassLoader> class_loader_handle(
        hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
    MutableHandle<mirror::Class> cls(hs.NewHandle<mirror::Class>(nullptr));
    for (const DexFile* dex_file : dex_files_) {
      const std::vector<bool>& verified_classes = deps.GetVerifiedClasses(*dex_file);
      ASSERT_EQ(verified_classes.size(), dex_file->NumClassDefs());
      for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
        cls.Assign(class_linker_->FindClass(
            soa.Self(), *dex_file, dex_file->GetClassDef(i).class_idx_, class_loader_handle));
        if (cls == nullptr) {
          CHECK(soa.Self()->IsExceptionPending());
          soa.Self()->ClearException();
        } else if (&cls->GetDexFile() != dex_file) {
          // Ignore classes from different dex files.
        } else if (verified_classes[i]) {
          ASSERT_EQ(cls->GetStatus(), ClassStatus::kVerifiedNeedsAccessChecks);
        } else {
          ASSERT_LT(cls->GetStatus(), ClassStatus::kVerified);
        }
      }
    }
  }

  uint16_t GetClassDefIndex(const std::string& cls, const DexFile& dex_file) {
    const dex::TypeId* type_id = dex_file.FindTypeId(cls.c_str());
    DCHECK(type_id != nullptr);
    dex::TypeIndex type_idx = dex_file.GetIndexForTypeId(*type_id);
    const dex::ClassDef* class_def = dex_file.FindClassDef(type_idx);
    DCHECK(class_def != nullptr);
    return dex_file.GetIndexForClassDef(*class_def);
  }

  bool HasVerifiedClass(const std::string& cls) {
    return HasVerifiedClass(cls, *primary_dex_file_);
  }

  bool HasUnverifiedClass(const std::string& cls) {
    return !HasVerifiedClass(cls, *primary_dex_file_);
  }

  bool HasUnverifiedClass(const std::string& cls, const DexFile& dex_file) {
    return !HasVerifiedClass(cls, dex_file);
  }

  bool HasVerifiedClass(const std::string& cls, const DexFile& dex_file) {
    uint16_t class_def_idx = GetClassDefIndex(cls, dex_file);
    return verifier_deps_->GetVerifiedClasses(dex_file)[class_def_idx];
  }

  // 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) const {
    for (auto& dex_dep : verifier_deps_->dex_deps_) {
      const DexFile& dex_file = *dex_dep.first;
      auto& storage = dex_dep.second->assignable_types_;
      for (auto& set : storage) {
        for (auto& entry : set) {
          std::string actual_destination =
              verifier_deps_->GetStringFromIndex(dex_file, entry.GetDestination());
          std::string actual_source =
              verifier_deps_->GetStringFromIndex(dex_file, entry.GetSource());
          if ((expected_destination == actual_destination) && (expected_source == actual_source)) {
            return true;
          }
        }
      }
    }
    return false;
  }

  size_t NumberOfCompiledDexFiles() {
    return verifier_deps_->dex_deps_.size();
  }

  bool HasBoolValue(const std::vector<bool>& vec, bool value) {
    return std::count(vec.begin(), vec.end(), value) > 0;
  }

  bool HasEachKindOfRecord() {
    bool has_strings = false;
    bool has_assignability = false;
    bool has_verified_classes = false;
    bool has_unverified_classes = false;

    for (auto& entry : verifier_deps_->dex_deps_) {
      has_strings |= !entry.second->strings_.empty();
      has_assignability |= !entry.second->assignable_types_.empty();
      has_verified_classes |= HasBoolValue(entry.second->verified_classes_, true);
      has_unverified_classes |= HasBoolValue(entry.second->verified_classes_, false);
    }

    return has_strings &&
           has_assignability &&
           has_verified_classes &&
           has_unverified_classes;
  }

  // Load the dex file again with a new class loader, decode the VerifierDeps
  // in `buffer`, allow the caller to modify the deps and then run validation.
  template<typename Fn>
  bool RunValidation(Fn fn, const std::vector<uint8_t>& buffer) {
    ScopedObjectAccess soa(Thread::Current());

    jobject second_loader = LoadDex("VerifierDeps");
    const auto& second_dex_files = GetDexFiles(second_loader);

    VerifierDeps decoded_deps(second_dex_files, /*output_only=*/ false);
    bool parsed = decoded_deps.ParseStoredData(second_dex_files, ArrayRef<const uint8_t>(buffer));
    CHECK(parsed);
    VerifierDeps::DexFileDeps* decoded_dex_deps =
        decoded_deps.GetDexFileDeps(*second_dex_files.front());

    // Let the test modify the dependencies.
    fn(*decoded_dex_deps);

    StackHandleScope<1> hs(soa.Self());
    Handle<mirror::ClassLoader> new_class_loader =
        hs.NewHandle<mirror::ClassLoader>(soa.Decode<mirror::ClassLoader>(second_loader));

    return decoded_deps.ValidateDependenciesAndUpdateStatus(soa.Self(),
                                                            new_class_loader,
                                                            second_dex_files);
  }

  std::unique_ptr<verifier::VerifierDeps> verifier_deps_;
  std::vector<const DexFile*> dex_files_;
  const DexFile* primary_dex_file_;
  jobject class_loader_;
  ObjPtr<mirror::Class> klass_Main_;
};

TEST_F(VerifierDepsTest, StringToId) {
  ScopedObjectAccess soa(Thread::Current());
  LoadDexFile(soa);

  dex::StringIndex id_Main1 = verifier_deps_->GetIdFromString(*primary_dex_file_, "LMain;");
  ASSERT_LT(id_Main1.index_, primary_dex_file_->NumStringIds());
  ASSERT_STREQ("LMain;", verifier_deps_->GetStringFromIndex(*primary_dex_file_, id_Main1));

  dex::StringIndex id_Main2 = verifier_deps_->GetIdFromString(*primary_dex_file_, "LMain;");
  ASSERT_LT(id_Main2.index_, primary_dex_file_->NumStringIds());
  ASSERT_STREQ("LMain;", verifier_deps_->GetStringFromIndex(*primary_dex_file_, id_Main2));

  dex::StringIndex id_Lorem1 = verifier_deps_->GetIdFromString(*primary_dex_file_, "Lorem ipsum");
  ASSERT_GE(id_Lorem1.index_, primary_dex_file_->NumStringIds());
  ASSERT_STREQ("Lorem ipsum", verifier_deps_->GetStringFromIndex(*primary_dex_file_, id_Lorem1));

  dex::StringIndex id_Lorem2 = verifier_deps_->GetIdFromString(*primary_dex_file_, "Lorem ipsum");
  ASSERT_GE(id_Lorem2.index_, primary_dex_file_->NumStringIds());
  ASSERT_STREQ("Lorem ipsum", verifier_deps_->GetStringFromIndex(*primary_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;"));
  ASSERT_TRUE(HasAssignable("Ljava/util/TimeZone;""Ljava/util/SimpleTimeZone;"));
}

TEST_F(VerifierDepsTest, Assignable_BothArrays_Resolved) {
  ASSERT_TRUE(TestAssignabilityRecording(/* dst= */ "[[Ljava/util/TimeZone;",
                                         /* src= */ "[[Ljava/util/SimpleTimeZone;"));
  // 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;"));
  ASSERT_FALSE(HasAssignable("[Ljava/util/TimeZone;""[Ljava/util/SimpleTimeZone;"));
  ASSERT_TRUE(HasAssignable("Ljava/util/TimeZone;""Ljava/util/SimpleTimeZone;"));
}

TEST_F(VerifierDepsTest, ReturnType_Reference) {
  ASSERT_TRUE(VerifyMethod("ReturnType_Reference"));
  ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;""Ljava/lang/IllegalStateException;"));
}

TEST_F(VerifierDepsTest, InvokeArgumentType) {
  ASSERT_TRUE(VerifyMethod("InvokeArgumentType"));
  ASSERT_TRUE(HasAssignable("Ljava/util/TimeZone;""Ljava/util/SimpleTimeZone;"));
}

TEST_F(VerifierDepsTest, MergeTypes_RegisterLines) {
  ASSERT_TRUE(VerifyMethod("MergeTypes_RegisterLines"));
  ASSERT_TRUE(HasAssignable("Ljava/lang/Exception;""LMySocketTimeoutException;"));
  ASSERT_TRUE(HasAssignable(
      "Ljava/lang/Exception;""Ljava/util/concurrent/TimeoutException;"));
}

TEST_F(VerifierDepsTest, MergeTypes_IfInstanceOf) {
  ASSERT_TRUE(VerifyMethod("MergeTypes_IfInstanceOf"));
  ASSERT_TRUE(HasAssignable("Ljava/lang/Exception;""Ljava/net/SocketTimeoutException;"));
  ASSERT_TRUE(HasAssignable(
      "Ljava/lang/Exception;""Ljava/util/concurrent/TimeoutException;"));
}

TEST_F(VerifierDepsTest, MergeTypes_Unresolved) {
  ASSERT_TRUE(VerifyMethod("MergeTypes_Unresolved"));
  ASSERT_TRUE(HasAssignable("Ljava/lang/Exception;""Ljava/net/SocketTimeoutException;"));
  ASSERT_TRUE(HasAssignable(
      "Ljava/lang/Exception;""Ljava/util/concurrent/TimeoutException;"));
}

TEST_F(VerifierDepsTest, Throw) {
  ASSERT_TRUE(VerifyMethod("Throw"));
  ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;""Ljava/lang/IllegalStateException;"));
}

TEST_F(VerifierDepsTest, MoveException_Resolved) {
  ASSERT_TRUE(VerifyMethod("MoveException_Resolved"));

  // Testing that all exception types are assignable to Throwable.
  ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;""Ljava/io/InterruptedIOException;"));
  ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;""Ljava/net/SocketTimeoutException;"));
  ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;""Ljava/util/zip/ZipException;"));

  // Testing that the merge type is assignable to Throwable.
  ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;""Ljava/io/IOException;"));

  // Merging of exception types.
  ASSERT_TRUE(HasAssignable("Ljava/io/IOException;""Ljava/io/InterruptedIOException;"));
  ASSERT_TRUE(HasAssignable("Ljava/io/IOException;""Ljava/util/zip/ZipException;"));
  ASSERT_TRUE(HasAssignable(
      "Ljava/io/InterruptedIOException;""Ljava/net/SocketTimeoutException;"));
}

TEST_F(VerifierDepsTest, InstanceField_Resolved_DeclaredInReferenced) {
  ASSERT_TRUE(VerifyMethod("InstanceField_Resolved_DeclaredInReferenced"));
  ASSERT_TRUE(HasAssignable(
      "Ljava/io/InterruptedIOException;""LMySocketTimeoutException;"));
}

TEST_F(VerifierDepsTest, InstanceField_Resolved_DeclaredInSuperclass1) {
  ASSERT_TRUE(VerifyMethod("InstanceField_Resolved_DeclaredInSuperclass1"));
  ASSERT_TRUE(HasAssignable(
      "Ljava/io/InterruptedIOException;""LMySocketTimeoutException;"));
}

TEST_F(VerifierDepsTest, InstanceField_Resolved_DeclaredInSuperclass2) {
  ASSERT_TRUE(VerifyMethod("InstanceField_Resolved_DeclaredInSuperclass2"));
  ASSERT_TRUE(HasAssignable(
      "Ljava/io/InterruptedIOException;""LMySocketTimeoutException;"));
}

TEST_F(VerifierDepsTest, InvokeVirtual_Resolved_DeclaredInReferenced) {
  ASSERT_TRUE(VerifyMethod("InvokeVirtual_Resolved_DeclaredInReferenced"));
  // Type dependency on `this` argument.
  ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;""LMySocketTimeoutException;"));
}

TEST_F(VerifierDepsTest, InvokeVirtual_Resolved_DeclaredInSuperclass1) {
  ASSERT_TRUE(VerifyMethod("InvokeVirtual_Resolved_DeclaredInSuperclass1"));
  // Type dependency on `this` argument.
  ASSERT_TRUE(HasAssignable("Ljava/lang/Throwable;""LMySocketTimeoutException;"));
}

TEST_F(VerifierDepsTest, InvokeSuper_ThisAssignable) {
  ASSERT_TRUE(VerifyMethod("InvokeSuper_ThisAssignable"));
  ASSERT_TRUE(HasAssignable("Ljava/lang/Runnable;""LMain;"));
}

TEST_F(VerifierDepsTest, EncodeDecode) {
  VerifyDexFile();

  ASSERT_EQ(1u, NumberOfCompiledDexFiles());
  ASSERT_TRUE(HasEachKindOfRecord());

  std::vector<uint8_t> buffer;
  verifier_deps_->Encode(dex_files_, &buffer);
  ASSERT_FALSE(buffer.empty());

  VerifierDeps decoded_deps(dex_files_, /*output_only=*/ false);
  bool parsed = decoded_deps.ParseStoredData(dex_files_, ArrayRef<const uint8_t>(buffer));
  ASSERT_TRUE(parsed);
  ASSERT_TRUE(verifier_deps_->Equals(decoded_deps));
}

TEST_F(VerifierDepsTest, EncodeDecodeMulti) {
  VerifyDexFile("MultiDex");

  ASSERT_GT(NumberOfCompiledDexFiles(), 1u);
  std::vector<uint8_t> buffer;
  verifier_deps_->Encode(dex_files_, &buffer);
  ASSERT_FALSE(buffer.empty());

  // Create new DexFile, to mess with std::map order: the verifier deps used
  // to iterate over the map, which doesn't guarantee insertion order. We fixed
  // this by passing the expected order when encoding/decoding.
  std::vector<std::unique_ptr<const DexFile>> first_dex_files = OpenTestDexFiles("VerifierDeps");
  std::vector<std::unique_ptr<const DexFile>> second_dex_files = OpenTestDexFiles("MultiDex");
  std::vector<const DexFile*> dex_files;
  dex_files.reserve(first_dex_files.size() + second_dex_files.size());
  for (auto& dex_file : first_dex_files) {
    dex_files.push_back(dex_file.get());
  }
  for (auto& dex_file : second_dex_files) {
    dex_files.push_back(dex_file.get());
  }

  // Dump the new verifier deps to ensure it can properly read the data.
  VerifierDeps decoded_deps(dex_files, /*output_only=*/ false);
  bool parsed = decoded_deps.ParseStoredData(dex_files, ArrayRef<const uint8_t>(buffer));
  ASSERT_TRUE(parsed);
  std::ostringstream stream;
  VariableIndentationOutputStream os(&stream);
  decoded_deps.Dump(&os);
}

TEST_F(VerifierDepsTest, UnverifiedClasses) {
  VerifyDexFile();
  ASSERT_FALSE(HasUnverifiedClass("LMyThread;"));
  // Test that a class with a soft failure is recorded.
  ASSERT_TRUE(HasUnverifiedClass("LMain;"));
  // Test that a class with hard failure is recorded.
  ASSERT_TRUE(HasUnverifiedClass("LMyVerificationFailure;"));
  // Test that a class with unresolved super and hard failure is recorded.
  ASSERT_TRUE(HasUnverifiedClass("LMyClassWithNoSuperButFailures;"));
  // Test that a class with unresolved super can be verified.
  ASSERT_TRUE(HasVerifiedClass("LMyClassWithNoSuper;"));
}

TEST_F(VerifierDepsTest, UnverifiedOrder) {
  ScopedObjectAccess soa(Thread::Current());
  jobject loader = LoadDex("VerifierDeps");
  std::vector<const DexFile*> dex_files = GetDexFiles(loader);
  ASSERT_GT(dex_files.size(), 0u);
  const DexFile* dex_file = dex_files[0];
  VerifierDeps deps1(dex_files);
  deps1.MaybeRecordVerificationStatus(&deps1,
                                      *dex_file,
                                      dex_file->GetClassDef(0u),
                                      verifier::FailureKind::kHardFailure);
  deps1.MaybeRecordVerificationStatus(&deps1,
                                      *dex_file,
                                      dex_file->GetClassDef(1u),
                                      verifier::FailureKind::kHardFailure);
  VerifierDeps deps2(dex_files);
  deps2.MaybeRecordVerificationStatus(&deps2,
                                      *dex_file,
                                      dex_file->GetClassDef(1u),
                                      verifier::FailureKind::kHardFailure);
  deps2.MaybeRecordVerificationStatus(&deps2,
                                      *dex_file,
                                      dex_file->GetClassDef(0u),
                                      verifier::FailureKind::kHardFailure);
  std::vector<uint8_t> buffer1;
  deps1.Encode(dex_files, &buffer1);
  std::vector<uint8_t> buffer2;
  deps2.Encode(dex_files, &buffer2);
  EXPECT_EQ(buffer1, buffer2);
}

TEST_F(VerifierDepsTest, VerifyDeps) {
  VerifyDexFile();
  ASSERT_EQ(1u, NumberOfCompiledDexFiles());
  ASSERT_TRUE(HasEachKindOfRecord());

  // When validating, we create a new class loader, as
  // the existing `class_loader_` may contain erroneous classes,
  // that ClassLinker::FindClass won't return.

  std::vector<uint8_t> buffer;
  verifier_deps_->Encode(dex_files_, &buffer);
  ASSERT_FALSE(buffer.empty());

  // Check that dependencies are satisfied after decoding `buffer`.
  ASSERT_TRUE(RunValidation([](VerifierDeps::DexFileDeps&) {}, buffer));
}

TEST_F(VerifierDepsTest, CompilerDriver) {
  SetupCompilerDriver();

  // Test both multi-dex and single-dex configuration.
  for (const char* multi : { "MultiDex"static_cast<const char*>(nullptr) }) {
    // Test that the compiler driver behaves as expected when the dependencies
    // verify and when they don't verify.
    for (bool verify_failure : { falsetrue }) {
      {
        ScopedObjectAccess soa(Thread::Current());
        LoadDexFile(soa, "VerifierDeps", multi);
      }
      VerifyWithCompilerDriver(/* verifier_deps= */ nullptr);

      std::vector<uint8_t> buffer;
      verifier_deps_->Encode(dex_files_, &buffer);

      {
        ScopedObjectAccess soa(Thread::Current());
        LoadDexFile(soa, "VerifierDeps", multi);
      }
      VerifierDeps decoded_deps(dex_files_, /*output_only=*/ false);
      bool parsed = decoded_deps.ParseStoredData(dex_files_, ArrayRef<const uint8_t>(buffer));
      ASSERT_TRUE(parsed);
      VerifyWithCompilerDriver(&decoded_deps);

      if (verify_failure) {
        ASSERT_FALSE(verifier_deps_ == nullptr);
        ASSERT_FALSE(verifier_deps_->Equals(decoded_deps));
      } else {
        VerifyClassStatus(decoded_deps);
      }
    }
  }
}

TEST_F(VerifierDepsTest, MultiDexVerification) {
  VerifyDexFile("VerifierDepsMulti");
  ASSERT_EQ(NumberOfCompiledDexFiles(), 2u);

  ASSERT_TRUE(HasUnverifiedClass("LMySoftVerificationFailure;", *dex_files_[1]));
  ASSERT_TRUE(HasUnverifiedClass("LMySub1SoftVerificationFailure;", *dex_files_[0]));
  ASSERT_TRUE(HasUnverifiedClass("LMySub2SoftVerificationFailure;", *dex_files_[0]));

  std::vector<uint8_t> buffer;
  verifier_deps_->Encode(dex_files_, &buffer);
  ASSERT_FALSE(buffer.empty());
}

}  // namespace verifier
}  // namespace art

Messung V0.5 in Prozent
C=89 H=87 G=87

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.