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

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


#include "verifier_deps.h"

#include <cstring>
#include <sstream>

#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/indenter.h"
#include "base/leb128.h"
#include "base/mutex-inl.h"
#include "compiler_callbacks.h"
#include "dex/class_accessor-inl.h"
#include "dex/dex_file-inl.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "oat/oat_file.h"
#include "obj_ptr-inl.h"
#include "reg_type.h"
#include "reg_type_cache-inl.h"
#include "runtime.h"

namespace art HIDDEN {
namespace verifier {

VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files, bool output_only)
    : output_only_(output_only) {
  for (const DexFile* dex_file : dex_files) {
    DCHECK(GetDexFileDeps(*dex_file) == nullptr);
    std::unique_ptr<DexFileDeps> deps(new DexFileDeps(dex_file->NumClassDefs()));
    dex_deps_.emplace(dex_file, std::move(deps));
  }
}

// Perform logical OR on two bit vectors and assign back to LHS, i.e. `to_update |= other`.
// Size of the two vectors must be equal.
// Size of `other` must be equal to size of `to_update`.
static inline void BitVectorOr(std::vector<bool>& to_update, const std::vector<bool>&&nbsp;other) {
  DCHECK_EQ(to_update.size(), other.size());
  std::transform(
      other.begin(), other.end(), to_update.begin(), to_update.begin(), std::logical_or<bool>());
}

void VerifierDeps::MergeWith(std::unique_ptr<VerifierDeps> other,
                             const std::vector<const DexFile*>& dex_files) {
  DCHECK(other != nullptr);
  DCHECK_EQ(dex_deps_.size(), other->dex_deps_.size());
  for (const DexFile* dex_file : dex_files) {
    DexFileDeps* my_deps = GetDexFileDeps(*dex_file);
    DexFileDeps& other_deps = *other->GetDexFileDeps(*dex_file);
    // We currently collect extra strings only on the main `VerifierDeps`,
    // which should be the one passed as `this` in this method.
    DCHECK(other_deps.strings_.empty());
    // Size is the number of class definitions in the dex file, and must be the
    // same between the two `VerifierDeps`.
    DCHECK_EQ(my_deps->assignable_types_.size(), other_deps.assignable_types_.size());
    for (uint32_t i = 0; i < my_deps->assignable_types_.size(); ++i) {
      my_deps->assignable_types_[i].merge(other_deps.assignable_types_[i]);
    }
    BitVectorOr(my_deps->verified_classes_, other_deps.verified_classes_);
  }
}

VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex_file) {
  auto it = dex_deps_.find(&dex_file);
  return (it == dex_deps_.end()) ? nullptr : it->second.get();
}

const VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex_file) const {
  auto it = dex_deps_.find(&dex_file);
  return (it == dex_deps_.end()) ? nullptr : it->second.get();
}

dex::StringIndex VerifierDeps::GetClassDescriptorStringId(const DexFile& dex_file,
                                                          ObjPtr<mirror::Class> klass) {
  DCHECK(klass != nullptr);
  ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
  // Array and proxy classes do not have a dex cache.
  if (!klass->IsArrayClass() && !klass->IsProxyClass()) {
    DCHECK(dex_cache != nullptr) << klass->PrettyClass();
    if (dex_cache->GetDexFile() == &dex_file) {
      // FindStringId is slow, try to go through the class def if we have one.
      const dex::ClassDef* class_def = klass->GetClassDef();
      DCHECK(class_def != nullptr) << klass->PrettyClass();
      const dex::TypeId& type_id = dex_file.GetTypeId(class_def->class_idx_);
      if (kIsDebugBuild) {
        std::string temp;
        CHECK_EQ(GetIdFromString(dex_file, klass->GetDescriptor(&temp)), type_id.descriptor_idx_);
      }
      return type_id.descriptor_idx_;
    }
  }
  std::string temp;
  return GetIdFromString(dex_file, klass->GetDescriptor(&temp));
}

static inline VerifierDeps* GetMainVerifierDeps(VerifierDeps* local_deps) {
  // 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.
  CompilerCallbacks* callbacks = Runtime::Current()->GetCompilerCallbacks();
  if (callbacks == nullptr) {
    DCHECK(!Runtime::Current()->IsAotCompiler());
    return local_deps;
  }
  DCHECK(Runtime::Current()->IsAotCompiler());
  return callbacks->GetVerifierDeps();
}

static bool FindExistingStringId(const std::vector<std::string>& strings,
                                 const std::string& str,
                                 uint32_t* found_id) {
  uint32_t num_extra_ids = strings.size();
  for (size_t i = 0; i < num_extra_ids; ++i) {
    if (strings[i] == str) {
      *found_id = i;
      return true;
    }
  }
  return false;
}

dex::StringIndex VerifierDeps::GetIdFromString(const DexFile& dex_file, const std::string& str) {
  const dex::StringId* string_id = dex_file.FindStringId(str.c_str());
  if (string_id != nullptr) {
    // String is in the DEX file. Return its ID.
    return dex_file.GetIndexForStringId(*string_id);
  }

  // String is not in the DEX file. Assign a new ID to it which is higher than
  // the number of strings in the DEX file.

  // We use the main `VerifierDeps` for adding new strings to simplify
  // synchronization/merging of these entries between threads.
  VerifierDeps* singleton = GetMainVerifierDeps(this);
  DexFileDeps* deps = singleton->GetDexFileDeps(dex_file);
  DCHECK(deps != nullptr);

  uint32_t num_ids_in_dex = dex_file.NumStringIds();
  uint32_t found_id;

  {
    ReaderMutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
    if (FindExistingStringId(deps->strings_, str, &found_id)) {
      return dex::StringIndex(num_ids_in_dex + found_id);
    }
  }
  {
    WriterMutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
    if (FindExistingStringId(deps->strings_, str, &found_id)) {
      return dex::StringIndex(num_ids_in_dex + found_id);
    }
    deps->strings_.push_back(str);
    dex::StringIndex new_id(num_ids_in_dex + deps->strings_.size() - 1);
    CHECK_GE(new_id.index_, num_ids_in_dex);  // check for overflows
    DCHECK_EQ(str, singleton->GetStringFromIndex(dex_file, new_id));
    return new_id;
  }
}

const char* VerifierDeps::GetStringFromIndex(const DexFile& dex_file,
                                             dex::StringIndex string_idx,
                                             /*out*/ size_t* utf8_length) const {
  uint32_t num_ids_in_dex = dex_file.NumStringIds();
  if (string_idx.index_ < num_ids_in_dex) {
    uint32_t utf16_length;
    const char* str = dex_file.GetStringDataAndUtf16Length(string_idx, &utf16_length);
    if (utf8_length != nullptr) {
      *utf8_length = DexFile::Utf8Length(str, utf16_length);
    }
    return str;
  } else {
    const DexFileDeps* deps = GetDexFileDeps(dex_file);
    DCHECK(deps != nullptr);
    size_t index = string_idx.index_ - num_ids_in_dex;
    CHECK_LT(index, deps->strings_.size());
    const std::string& str = deps->strings_[index];
    if (utf8_length != nullptr) {
      *utf8_length = str.length();
    }
    return str.c_str();
  }
}

void VerifierDeps::AddAssignability(const DexFile& dex_file,
                                    const dex::ClassDef& class_def,
                                    ObjPtr<mirror::Class> destination,
                                    ObjPtr<mirror::Class> source) {
  // Test that the method is only called on reference types.
  // Note that concurrent verification of `destination` and `source` may have
  // set their status to erroneous. However, the tests performed below rely
  // merely on no issues with linking (valid access flags, superclass and
  // implemented interfaces). If the class at any point reached the IsResolved
  // status, the requirement holds. This is guaranteed by RegTypeCache::ResolveClass.
  DCHECK(destination != nullptr);
  DCHECK(source != nullptr);

  if (destination->IsPrimitive() || source->IsPrimitive()) {
    // Primitive types are trivially non-assignable to anything else.
    // We do not need to record trivial assignability, as it will
    // not change across releases.
    return;
  }

  if (destination == source || destination->IsObjectClass()) {
    // Cases when `destination` is trivially assignable from `source`.
    return;
  }

  if (destination->IsArrayClass() && source->IsArrayClass()) {
    // Both types are arrays. Break down to component types and add recursively.
    // This helps filter out destinations from compiled DEX files (see below)
    // and deduplicate entries with the same canonical component type.
    ObjPtr<mirror::Class> destination_component = destination->GetComponentType();
    ObjPtr<mirror::Class> source_component = source->GetComponentType();

    // Only perform the optimization if both types are resolved which guarantees
    // that they linked successfully, as required at the top of this method.
    if (destination_component->IsResolved() && source_component->IsResolved()) {
      AddAssignability(dex_file, class_def, destination_component, source_component);
      return;
    }
  }

  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;
  }

  // Get string IDs for both descriptors and store in the appropriate set.
  dex::StringIndex destination_id = GetClassDescriptorStringId(dex_file, destination);
  dex::StringIndex source_id = GetClassDescriptorStringId(dex_file, source);

  uint16_t index = dex_file.GetIndexForClassDef(class_def);
  dex_deps->assignable_types_[index].emplace(TypeAssignability(destination_id, source_id));
}

void VerifierDeps::AddAssignability(const DexFile& dex_file,
                                    const dex::ClassDef& class_def,
                                    const RegType& destination,
                                    const RegType& source) {
  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;
  }

  CHECK(destination.IsUnresolvedReference() || destination.HasClass());
  CHECK(!destination.IsUnresolvedMergedReference());

  if (source.IsUnresolvedReference() || source.IsJavaLangObject() || source.HasClass()) {
    DCHECK_IMPLIES(source.IsJavaLangObject(), destination.IsUnresolvedReference());
    // Get string IDs for both descriptors and store in the appropriate set.
    dex::StringIndex destination_id =
        GetIdFromString(dex_file, std::string(destination.GetDescriptor()));
    dex::StringIndex source_id = GetIdFromString(dex_file, std::string(source.GetDescriptor()));
    uint16_t index = dex_file.GetIndexForClassDef(class_def);
    dex_deps->assignable_types_[index].emplace(TypeAssignability(destination_id, source_id));
  } else if (source.IsZeroOrNull()) {
    // Nothing to record, null is always assignable.
  } else {
    CHECK(source.IsUnresolvedMergedReference()) << source.Dump();
    const UnresolvedMergedReferenceType& merge =
        *down_cast<const UnresolvedMergedReferenceType*>(&source);
    AddAssignability(dex_file, class_def, destination, merge.GetResolvedPart());
    for (uint32_t idx : merge.GetUnresolvedTypes().Indexes()) {
      AddAssignability(dex_file, class_def, destination, merge.GetRegTypeCache()->GetFromId(idx));
    }
  }
}

void VerifierDeps::MaybeRecordVerificationStatus(VerifierDeps* verifier_deps,
                                                 const DexFile& dex_file,
                                                 const dex::ClassDef& class_def,
                                                 FailureKind failure_kind) {
  if (verifier_deps != nullptr) {
    switch (failure_kind) {
      case verifier::FailureKind::kHardFailure:
      case verifier::FailureKind::kSoftFailure: {
        // Class will be verified at runtime.
        DexFileDeps* dex_deps = verifier_deps->GetDexFileDeps(dex_file);
        uint16_t index = dex_file.GetIndexForClassDef(class_def);
        dex_deps->assignable_types_[index].clear();
        break;
      }
      case verifier::FailureKind::kAccessChecksFailure:
      case verifier::FailureKind::kTypeChecksFailure:
      case verifier::FailureKind::kNoFailure: {
        verifier_deps->RecordClassVerified(dex_file, class_def);
        break;
      }
    }
  }
}

void VerifierDeps::RecordClassVerified(const DexFile& dex_file, const dex::ClassDef& class_def) {
  DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
  DCHECK_EQ(dex_deps->verified_classes_.size(), dex_file.NumClassDefs());
  dex_deps->verified_classes_[dex_file.GetIndexForClassDef(class_def)] = true;
}

bool VerifierDeps::HasRecordedVerifiedStatus(const DexFile& dex_file,
                                             const dex::ClassDef& class_def) {
  DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
  DCHECK_EQ(dex_deps->verified_classes_.size(), dex_file.NumClassDefs());
  return dex_deps->verified_classes_[dex_file.GetIndexForClassDef(class_def)];
}

void VerifierDeps::MaybeRecordAssignability(VerifierDeps* verifier_deps,
                                            const DexFile& dex_file,
                                            const dex::ClassDef& class_def,
                                            ObjPtr<mirror::Class> destination,
                                            ObjPtr<mirror::Class> source) {
  if (verifier_deps != nullptr) {
    verifier_deps->AddAssignability(dex_file, class_def, destination, source);
  }
}

void VerifierDeps::MaybeRecordAssignability(VerifierDeps* verifier_deps,
                                            const DexFile& dex_file,
                                            const dex::ClassDef& class_def,
                                            const RegType& destination,
                                            const RegType& source) {
  if (verifier_deps != nullptr) {
    verifier_deps->AddAssignability(dex_file, class_def, destination, source);
  }
}

namespace {

template <typename T>
inline uint32_t Encode(T in);

template <>
inline uint32_t Encode<dex::StringIndex>(dex::StringIndex in) {
  return in.index_;
}

template <typename T>
inline T Decode(uint32_t in);

template <>
inline dex::StringIndex Decode<dex::StringIndex>(uint32_t in) {
  return dex::StringIndex(in);
}

template <typename T1, typename T2>
static inline void EncodeTuple(std::vector<uint8_t>* out, const std::tuple<T1, T2>& t) {
  EncodeUnsignedLeb128(out, Encode(std::get<0>(t)));
  EncodeUnsignedLeb128(out, Encode(std::get<1>(t)));
}

template <typename T1, typename T2>
static inline bool DecodeTuple(const uint8_t** in, const uint8_t* end, std::tuple<T1, T2>* t) {
  uint32_t v1, v2;
  if (UNLIKELY(!DecodeUnsignedLeb128Checked(in, end, &v1)) ||
      UNLIKELY(!DecodeUnsignedLeb128Checked(in, end, &v2))) {
    return false;
  }
  *t = std::make_tuple(Decode<T1>(v1), Decode<T2>(v2));
  return true;
}

template <typename T1, typename T2, typename T3>
static inline void EncodeTuple(std::vector<uint8_t>* out, const std::tuple<T1, T2, T3>& t) {
  EncodeUnsignedLeb128(out, Encode(std::get<0>(t)));
  EncodeUnsignedLeb128(out, Encode(std::get<1>(t)));
  EncodeUnsignedLeb128(out, Encode(std::get<2>(t)));
}

template <typename T1, typename T2, typename T3>
static inline bool DecodeTuple(const uint8_t** in, const uint8_t* end, std::tuple<T1, T2, T3>* t) {
  uint32_t v1, v2, v3;
  if (UNLIKELY(!DecodeUnsignedLeb128Checked(in, end, &v1)) ||
      UNLIKELY(!DecodeUnsignedLeb128Checked(in, end, &v2)) ||
      UNLIKELY(!DecodeUnsignedLeb128Checked(in, end, &v3))) {
    return false;
  }
  *t = std::make_tuple(Decode<T1>(v1), Decode<T2>(v2), Decode<T3>(v3));
  return true;
}

static void SetUint32InUint8Array(std::vector<uint8_t>* out,
                                  uint32_t uint8_offset,
                                  uint32_t uint32_offset,
                                  uint32_t value) {
  DCHECK(IsAligned<sizeof(uint32_t)>(out->data() + uint8_offset));
  (reinterpret_cast<uint32_t*>(out->data() + uint8_offset))[uint32_offset] = value;
}

template <typename T>
static void EncodeSetVector(std::vector<uint8_t>* out,
                            const std::vector<std::set<T>>& vector,
                            const std::vector<bool>& verified_classes) {
  uint32_t offsets_index = out->size();
  // Make room for offsets for each class, +1 for marking the end of the
  // assignability types data.
  out->resize(out->size() + (vector.size() + 1) * sizeof(uint32_t));
  uint32_t class_def_index = 0;
  for (const std::set<T>& set : vector) {
    if (verified_classes[class_def_index]) {
      // Store the offset of the set for this class.
      SetUint32InUint8Array(out, offsets_index, class_def_index, out->size());
      for (const T& entry : set) {
        EncodeTuple(out, entry);
      }
    } else {
      SetUint32InUint8Array(out, offsets_index, class_def_index, VerifierDeps::kNotVerifiedMarker);
    }
    class_def_index++;
  }
  SetUint32InUint8Array(out, offsets_index, class_def_index, out->size());
}

template <bool kFillSet, typename T>
static bool DecodeSetVector(const uint8_t** cursor,
                            const uint8_t* start,
                            const uint8_t* end,
                            std::vector<std::set<T>>* vector,
                            std::vector<bool>* verified_classes,
                            size_t num_class_defs) {
  const uint32_t* offsets = reinterpret_cast<const uint32_t*>(*cursor);
  uint32_t next_valid_offset_index = 1;
  // Put the cursor after the offsets of each class, +1 for the offset of the
  // end of the assignable types data.
  *cursor += (num_class_defs + 1) * sizeof(uint32_t);
  for (uint32_t i = 0; i < num_class_defs; ++i) {
    uint32_t offset = offsets[i];
    if (offset == VerifierDeps::kNotVerifiedMarker) {
      (*verified_classes)[i] = false;
      continue;
    }
    (*verified_classes)[i] = true;
    *cursor = start + offset;
    // Fetch the assignability checks.
    std::set<T>& set = (*vector)[i];
    // Find the offset of the next entry. This will tell us where to stop when
    // reading the checks. Note that the last entry in the `offsets` array points
    // to the end of the assignability types data, so the loop will terminate correctly.
    while (next_valid_offset_index <= i ||
           offsets[next_valid_offset_index] == VerifierDeps::kNotVerifiedMarker) {
      next_valid_offset_index++;
    }
    const uint8_t* set_end = start + offsets[next_valid_offset_index];
    // Decode each check.
    while (*cursor < set_end) {
      T tuple;
      if (UNLIKELY(!DecodeTuple(cursor, end, &tuple))) {
        return false;
      }
      if (kFillSet) {
        set.emplace(tuple);
      }
    }
  }
  // Align the cursor to start decoding the strings.
  *cursor = AlignUp(*cursor, sizeof(uint32_t));
  return true;
}

static inline void EncodeStringVector(std::vector<uint8_t>* out,
                                      const std::vector<std::string>& strings) {
  uint32_t offsets_index = out->size();
  // Make room for offsets for each string, +1 for putting the number of
  // strings.
  out->resize(out->size() + (strings.size() + 1) * sizeof(uint32_t));
  (reinterpret_cast<uint32_t*>(out->data() + offsets_index))[0] = strings.size();
  uint32_t string_index = 1;
  for (const std::string& str : strings) {
    // Store the offset of the string.
    (reinterpret_cast<uint32_t*>(out->data() + offsets_index))[string_index++] = out->size();

    // Store the string data.
    const uint8_t* data = reinterpret_cast<const uint8_t*>(str.c_str());
    size_t length = str.length() + 1;
    out->insert(out->end(), data, data + length);
    DCHECK_EQ(0u, out->back());
  }
}

template <bool kFillVector>
static inline bool DecodeStringVector(const uint8_t** cursor,
                                      const uint8_t* start,
                                      const uint8_t* end,
                                      std::vector<std::string>* strings) {
  DCHECK(strings->empty());
  uint32_t num_strings = reinterpret_cast<const uint32_t*>(*cursor)[0];
  if (kFillVector) {
    strings->reserve(num_strings);
  }
  const uint8_t* offsets = *cursor;
  *cursor += sizeof(uint32_t) + num_strings * sizeof(uint32_t);
  for (uint32_t i = 0; i < num_strings; ++i) {
    uint32_t string_offset = reinterpret_cast<const uint32_t*>(offsets)[i + 1];
    const char* string_start = reinterpret_cast<const char*>(start + string_offset);
    const char* string_end =
        reinterpret_cast<const char*>(memchr(string_start, 0, end - start - string_offset));
    if (UNLIKELY(string_end == nullptr)) {
      return false;
    }
    size_t string_length = string_end - string_start;
    if (kFillVector) {
      strings->emplace_back(string_start, string_length);
    }
    *cursor = reinterpret_cast<const uint8_t*>(string_end + 1);
  }
  return true;
}

}  // namespace

void VerifierDeps::Encode(const std::vector<const DexFile*>& dex_files,
                          std::vector<uint8_t>* buffer) const {
  DCHECK(buffer->empty());
  buffer->resize(dex_files.size() * sizeof(uint32_t));
  uint32_t dex_file_index = 0;
  for (const DexFile* dex_file : dex_files) {
    // Four byte alignment before encoding the data.
    buffer->resize(RoundUp(buffer->size(), sizeof(uint32_t)));
    (reinterpret_cast<uint32_t*>(buffer->data()))[dex_file_index++] = buffer->size();
    const DexFileDeps& deps = *GetDexFileDeps(*dex_file);
    EncodeSetVector(buffer, deps.assignable_types_, deps.verified_classes_);
    // Four byte alignment before encoding strings.
    buffer->resize(RoundUp(buffer->size(), sizeof(uint32_t)));
    EncodeStringVector(buffer, deps.strings_);
  }
}

template <bool kOnlyVerifiedClasses>
bool VerifierDeps::DecodeDexFileDeps(DexFileDeps& deps,
                                     const uint8_t** cursor,
                                     const uint8_t* data_start,
                                     const uint8_t* data_end,
                                     size_t num_class_defs) {
  return DecodeSetVector</*kFillSet=*/!kOnlyVerifiedClasses>(cursor,
                                                             data_start,
                                                             data_end,
                                                             &deps.assignable_types_,
                                                             &deps.verified_classes_,
                                                             num_class_defs) &&
         DecodeStringVector</*kFillVector=*/!kOnlyVerifiedClasses>(
             cursor, data_start, data_end, &deps.strings_);
}

bool VerifierDeps::ParseStoredData(const std::vector<const DexFile*>& dex_files,
                                   ArrayRef<const uint8_t> data) {
  if (data.empty()) {
    // Return eagerly, as the first thing we expect from VerifierDeps data is
    // the number of created strings, even if there is no dependency.
    // Currently, only the boot image does not have any VerifierDeps data.
    return true;
  }
  const uint8_t* data_start = data.data();
  const uint8_t* data_end = data_start + data.size();
  const uint8_t* cursor = data_start;
  uint32_t dex_file_index = 0;
  for (const DexFile* dex_file : dex_files) {
    DexFileDeps* deps = GetDexFileDeps(*dex_file);
    // Fetch the offset of this dex file's verifier data.
    cursor = data_start + reinterpret_cast<const uint32_t*>(data_start)[dex_file_index++];
    size_t num_class_defs = dex_file->NumClassDefs();
    if (UNLIKELY(!DecodeDexFileDeps</*kOnlyVerifiedClasses=*/false>(
            *deps, &cursor, data_start, data_end, num_class_defs))) {
      LOG(ERROR) << "Failed to parse dex file dependencies for " << dex_file->GetLocation();
      return false;
    }
  }
  // TODO: We should check that `data_start == data_end`. Why are we passing excessive data?
  return true;
}

bool VerifierDeps::ParseVerifiedClasses(
    const std::vector<const DexFile*>& dex_files,
    ArrayRef<const uint8_t> data,
    /*out*/ std::vector<std::vector<bool>>* verified_classes_per_dex) {
  DCHECK(!data.empty());
  DCHECK(!dex_files.empty());
  DCHECK(verified_classes_per_dex->empty());

  verified_classes_per_dex->reserve(dex_files.size());

  const uint8_t* data_start = data.data();
  const uint8_t* data_end = data_start + data.size();
  const uint8_t* cursor = data_start;
  uint32_t dex_file_index = 0;
  for (const DexFile* dex_file : dex_files) {
    DexFileDeps deps(/*num_class_defs=*/0u);  // Do not initialize vectors.
    // Fetch the offset of this dex file's verifier data.
    cursor = data_start + reinterpret_cast<const uint32_t*>(data_start)[dex_file_index++];
    size_t num_class_defs = dex_file->NumClassDefs();
    deps.verified_classes_.resize(num_class_defs);
    if (UNLIKELY(!DecodeDexFileDeps</*kOnlyVerifiedClasses=*/true>(
            deps, &cursor, data_start, data_end, num_class_defs))) {
      LOG(ERROR) << "Failed to parse dex file dependencies for " << dex_file->GetLocation();
      return false;
    }
    verified_classes_per_dex->push_back(std::move(deps.verified_classes_));
  }
  // TODO: We should check that `data_start == data_end`. Why are we passing excessive data?
  return true;
}

bool VerifierDeps::Equals(const VerifierDeps& rhs) const {
  if (dex_deps_.size() != rhs.dex_deps_.size()) {
    return false;
  }

  auto lhs_it = dex_deps_.begin();
  auto rhs_it = rhs.dex_deps_.begin();

  for (; (lhs_it != dex_deps_.end()) && (rhs_it != rhs.dex_deps_.end()); lhs_it++, rhs_it++) {
    const DexFile* lhs_dex_file = lhs_it->first;
    const DexFile* rhs_dex_file = rhs_it->first;
    if (lhs_dex_file != rhs_dex_file) {
      return false;
    }

    DexFileDeps* lhs_deps = lhs_it->second.get();
    DexFileDeps* rhs_deps = rhs_it->second.get();
    if (!lhs_deps->Equals(*rhs_deps)) {
      return false;
    }
  }

  DCHECK((lhs_it == dex_deps_.end()) && (rhs_it == rhs.dex_deps_.end()));
  return true;
}

bool VerifierDeps::DexFileDeps::Equals(const VerifierDeps::DexFileDeps& rhs) const {
  return (strings_ == rhs.strings_) && (assignable_types_ == rhs.assignable_types_) &&
         (verified_classes_ == rhs.verified_classes_);
}

void VerifierDeps::Dump(VariableIndentationOutputStream* vios) const {
  // Sort dex files by their location to ensure deterministic ordering.
  using DepsEntry = std::pair<const DexFile*, const DexFileDeps*>;
  std::vector<DepsEntry> dex_deps;
  dex_deps.reserve(dex_deps_.size());
  for (const auto& dep : dex_deps_) {
    dex_deps.emplace_back(dep.first, dep.second.get());
  }
  std::sort(dex_deps.begin(), dex_deps.end(), [](const DepsEntry& lhs, const DepsEntry& rhs) {
    return lhs.first->GetLocation() < rhs.first->GetLocation();
  });
  for (const auto& dep : dex_deps) {
    const DexFile& dex_file = *dep.first;
    vios->Stream() << "Dependencies of " << dex_file.GetLocation() << ":\n";

    ScopedIndentation indent(vios);

    for (const std::string& str : dep.second->strings_) {
      vios->Stream() << "Extra string: " << str << "\n";
    }

    for (size_t idx = 0; idx < dep.second->assignable_types_.size(); idx++) {
      vios->Stream() << "Dependencies of " << dex_file.GetClassDescriptor(dex_file.GetClassDef(idx))
                     << ":\n";
      for (const TypeAssignability& entry : dep.second->assignable_types_[idx]) {
        vios->Stream() << GetStringFromIndex(dex_file, entry.GetSource())
                       << " must be assignable to "
                       << GetStringFromIndex(dex_file, entry.GetDestination()) << "\n";
      }
    }

    for (size_t idx = 0; idx < dep.second->verified_classes_.size(); idx++) {
      if (!dep.second->verified_classes_[idx]) {
        vios->Stream() << dex_file.GetClassDescriptor(dex_file.GetClassDef(idx))
                       << " will be verified at runtime\n";
      }
    }
  }
}

bool VerifierDeps::ValidateDependenciesAndUpdateStatus(
    Thread* self,
    Handle<mirror::ClassLoader> class_loader,
    const std::vector<const DexFile*>& dex_files) {
  bool all_validated = true;
  for (const auto* dex_file : dex_files) {
    DexFileDeps* my_deps = GetDexFileDeps(*dex_file);
    if (!VerifyDexFileAndUpdateStatus(class_loader, *dex_file, *my_deps, self)) {
      all_validated = false;
    }
  }
  return all_validated;
}

// TODO: share that helper with other parts of the compiler that have
// the same lookup pattern.
static ObjPtr<mirror::Class> FindClassAndClearException(ClassLinker* class_linker,
                                                        Thread* self,
                                                        const char* descriptor,
                                                        size_t descriptor_length,
                                                        Handle<mirror::ClassLoader> class_loader)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  ObjPtr<mirror::Class> result =
      class_linker->FindClass(self, descriptor, descriptor_length, class_loader);
  if (result == nullptr) {
    DCHECK(self->IsExceptionPending());
    self->ClearException();
  }
  return result;
}

bool VerifierDeps::VerifyDexFileAndUpdateStatus(
    Handle<mirror::ClassLoader> class_loader,
    const DexFile& dex_file,
    DexFileDeps& deps,
    Thread* self) {
  StackHandleScope<2> hs(self);
  const std::vector<std::set<TypeAssignability>>& assignables = deps.assignable_types_;
  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
  MutableHandle<mirror::Class> source(hs.NewHandle<mirror::Class>(nullptr));
  MutableHandle<mirror::Class> destination(hs.NewHandle<mirror::Class>(nullptr));

  uint32_t class_def_index = 0u;
  bool all_validated = true;
  uint32_t number_of_warnings = 0;
  static constexpr uint32_t kMaxWarnings = 5;
  for (const auto& vec : assignables) {
    for (const auto& entry : vec) {
      size_t destination_desc_length;
      const char* destination_desc =
          GetStringFromIndex(dex_file, entry.GetDestination(), &destination_desc_length);
      destination.Assign(FindClassAndClearException(
          class_linker, self, destination_desc, destination_desc_length, class_loader));
      size_t source_desc_length;
      const char* source_desc =
          GetStringFromIndex(dex_file, entry.GetSource(), &source_desc_length);
      source.Assign(FindClassAndClearException(
          class_linker, self, source_desc, source_desc_length, class_loader));

      if (destination == nullptr || source == nullptr) {
        deps.verified_classes_[class_def_index] = false;
        // We currently don't use assignability information for unresolved
        // types, as the status of the class using unresolved types will be soft
        // fail in the vdex.
        continue;
      }

      DCHECK(destination->IsResolved() && source->IsResolved());
      if (!destination->IsAssignableFrom(source.Get())) {
        deps.verified_classes_[class_def_index] = false;
        all_validated = false;
        if (number_of_warnings++ < kMaxWarnings) {
          LOG(WARNING) << "Class "
                       << dex_file.PrettyType(dex_file.GetClassDef(class_def_index).class_idx_)
                       << " could not be fast verified because one of its methods wrongly expected "
                       << destination_desc << " to be assignable from " << source_desc;
        }
        break;
      }
    }
    class_def_index++;
  }
  return all_validated;
}

}  // namespace verifier
}  // namespace art

Messung V0.5 in Prozent
C=91 H=96 G=93

¤ Dauer der Verarbeitung: 0.3 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.