ART: Move DexFileVerifier class to cc file
Hide all details. None were accessible before anyways. Instead,
only expose art::dex::Verify.
Test: m test-art-host
Change-Id: I19a68440045622b78c1678c92027f6e0e1185d75
diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h
index 1628256..a3ee2bd 100644
--- a/libdexfile/dex/class_accessor.h
+++ b/libdexfile/dex/class_accessor.h
@@ -27,6 +27,7 @@
namespace dex {
struct ClassDef;
struct CodeItem;
+class DexFileVerifier;
} // namespace dex
class ClassIteratorData;
@@ -146,7 +147,7 @@
uint32_t code_off_ = 0u;
friend class ClassAccessor;
- friend class DexFileVerifier;
+ friend class dex::DexFileVerifier;
};
// A decoded version of the field of a class_data_item.
@@ -172,7 +173,7 @@
bool is_static_ = true;
friend class ClassAccessor;
- friend class DexFileVerifier;
+ friend class dex::DexFileVerifier;
};
template <typename DataType>
@@ -264,7 +265,7 @@
// At iterator_end_, the iterator is no longer valid.
const uint32_t iterator_end_;
- friend class DexFileVerifier;
+ friend class dex::DexFileVerifier;
};
// Not explicit specifically for range-based loops.
@@ -390,7 +391,7 @@
const uint32_t num_direct_methods_ = 0u;
const uint32_t num_virtual_methods_ = 0u;
- friend class DexFileVerifier;
+ friend class dex::DexFileVerifier;
};
} // namespace art
diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc
index 54b90d3..7ccc93f 100644
--- a/libdexfile/dex/dex_file_loader.cc
+++ b/libdexfile/dex/dex_file_loader.cc
@@ -370,12 +370,12 @@
dex_file.reset();
return nullptr;
}
- if (verify && !DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- location.c_str(),
- verify_checksum,
- error_msg)) {
+ if (verify && !dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ location.c_str(),
+ verify_checksum,
+ error_msg)) {
if (verify_result != nullptr) {
*verify_result = VerifyResult::kVerifyFailed;
}
diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc
index 580d0b7..96cc773 100644
--- a/libdexfile/dex/dex_file_verifier.cc
+++ b/libdexfile/dex/dex_file_verifier.cc
@@ -16,30 +16,279 @@
#include "dex_file_verifier.h"
-#include <inttypes.h>
-
#include <algorithm>
+#include <bitset>
+#include <limits>
#include <memory>
#include "android-base/logging.h"
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
+#include "base/hash_map.h"
#include "base/leb128.h"
+#include "base/safe_map.h"
#include "class_accessor-inl.h"
#include "code_item_accessors-inl.h"
#include "descriptors_names.h"
#include "dex_file-inl.h"
+#include "dex_file_types.h"
#include "modifiers.h"
#include "utf-inl.h"
namespace art {
+namespace dex {
+
+// Note: an anonymous namespace would be nice, but we need friend access into accessors.
using android::base::StringAppendV;
using android::base::StringPrintf;
static constexpr uint32_t kTypeIdLimit = std::numeric_limits<uint16_t>::max();
+class DexFileVerifier {
+ public:
+ DexFileVerifier(const DexFile* dex_file,
+ const uint8_t* begin,
+ size_t size,
+ const char* location,
+ bool verify_checksum)
+ : dex_file_(dex_file),
+ begin_(begin),
+ size_(size),
+ location_(location),
+ verify_checksum_(verify_checksum),
+ header_(&dex_file->GetHeader()),
+ ptr_(nullptr),
+ previous_item_(nullptr),
+ init_indices_{std::numeric_limits<size_t>::max(),
+ std::numeric_limits<size_t>::max(),
+ std::numeric_limits<size_t>::max(),
+ std::numeric_limits<size_t>::max()} {
+ }
+
+ bool Verify();
+
+ const std::string& FailureReason() const {
+ return failure_reason_;
+ }
+
+ private:
+ bool CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, bool is_return_type);
+ bool CheckListSize(const void* start, size_t count, size_t element_size, const char* label);
+ // Check a list. The head is assumed to be at *ptr, and elements to be of size element_size. If
+ // successful, the ptr will be moved forward the amount covered by the list.
+ bool CheckList(size_t element_size, const char* label, const uint8_t* *ptr);
+ // Checks whether the offset is zero (when size is zero) or that the offset falls within the area
+ // claimed by the file.
+ bool CheckValidOffsetAndSize(uint32_t offset, uint32_t size, size_t alignment, const char* label);
+ // Checks whether the size is less than the limit.
+ bool CheckSizeLimit(uint32_t size, uint32_t limit, const char* label);
+ bool CheckIndex(uint32_t field, uint32_t limit, const char* label);
+
+ bool CheckHeader();
+ bool CheckMap();
+
+ uint32_t ReadUnsignedLittleEndian(uint32_t size);
+ bool CheckAndGetHandlerOffsets(const dex::CodeItem* code_item,
+ uint32_t* handler_offsets, uint32_t handlers_size);
+ bool CheckClassDataItemField(uint32_t idx,
+ uint32_t access_flags,
+ uint32_t class_access_flags,
+ dex::TypeIndex class_type_index,
+ bool expect_static);
+ bool CheckClassDataItemMethod(uint32_t idx,
+ uint32_t access_flags,
+ uint32_t class_access_flags,
+ dex::TypeIndex class_type_index,
+ uint32_t code_offset,
+ ClassAccessor::Method* direct_method,
+ size_t* remaining_directs);
+ ALWAYS_INLINE
+ bool CheckOrder(const char* type_descr, uint32_t curr_index, uint32_t prev_index);
+ bool CheckStaticFieldTypes(const dex::ClassDef* class_def);
+
+ bool CheckPadding(size_t offset, uint32_t aligned_offset, DexFile::MapItemType type);
+ bool CheckEncodedValue();
+ bool CheckEncodedArray();
+ bool CheckEncodedAnnotation();
+
+ bool CheckIntraClassDataItem();
+ // Check all fields of the given type from the given iterator. Load the class data from the first
+ // field, if necessary (and return it), or use the given values.
+ template <bool kStatic>
+ bool CheckIntraClassDataItemFields(size_t count,
+ ClassAccessor::Field* field,
+ bool* have_class,
+ dex::TypeIndex* class_type_index,
+ const dex::ClassDef** class_def);
+ // Check all methods of the given type from the given iterator. Load the class data from the first
+ // method, if necessary (and return it), or use the given values.
+ bool CheckIntraClassDataItemMethods(ClassAccessor::Method* method,
+ size_t num_methods,
+ ClassAccessor::Method* direct_method,
+ size_t num_directs,
+ bool* have_class,
+ dex::TypeIndex* class_type_index,
+ const dex::ClassDef** class_def);
+
+ bool CheckIntraCodeItem();
+ bool CheckIntraStringDataItem();
+ bool CheckIntraDebugInfoItem();
+ bool CheckIntraAnnotationItem();
+ bool CheckIntraAnnotationsDirectoryItem();
+ bool CheckIntraHiddenapiClassData();
+
+ template <DexFile::MapItemType kType>
+ bool CheckIntraSectionIterate(size_t offset, uint32_t count);
+ template <DexFile::MapItemType kType>
+ bool CheckIntraIdSection(size_t offset, uint32_t count);
+ template <DexFile::MapItemType kType>
+ bool CheckIntraDataSection(size_t offset, uint32_t count);
+ bool CheckIntraSection();
+
+ bool CheckOffsetToTypeMap(size_t offset, uint16_t type);
+
+ // Note: as sometimes kDexNoIndex16, being 0xFFFF, is a valid return value, we need an
+ // additional out parameter to signal any errors loading an index.
+ dex::TypeIndex FindFirstClassDataDefiner(const uint8_t* ptr, bool* success);
+ dex::TypeIndex FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success);
+
+ bool CheckInterStringIdItem();
+ bool CheckInterTypeIdItem();
+ bool CheckInterProtoIdItem();
+ bool CheckInterFieldIdItem();
+ bool CheckInterMethodIdItem();
+ bool CheckInterClassDefItem();
+ bool CheckInterCallSiteIdItem();
+ bool CheckInterMethodHandleItem();
+ bool CheckInterAnnotationSetRefList();
+ bool CheckInterAnnotationSetItem();
+ bool CheckInterClassDataItem();
+ bool CheckInterAnnotationsDirectoryItem();
+
+ bool CheckInterSectionIterate(size_t offset, uint32_t count, DexFile::MapItemType type);
+ bool CheckInterSection();
+
+ // Load a string by (type) index. Checks whether the index is in bounds, printing the error if
+ // not. If there is an error, null is returned.
+ const char* CheckLoadStringByIdx(dex::StringIndex idx, const char* error_fmt);
+ const char* CheckLoadStringByTypeIdx(dex::TypeIndex type_idx, const char* error_fmt);
+
+ // Load a field/method/proto Id by index. Checks whether the index is in bounds, printing the
+ // error if not. If there is an error, null is returned.
+ const dex::FieldId* CheckLoadFieldId(uint32_t idx, const char* error_fmt);
+ const dex::MethodId* CheckLoadMethodId(uint32_t idx, const char* error_fmt);
+ const dex::ProtoId* CheckLoadProtoId(dex::ProtoIndex idx, const char* error_fmt);
+
+ void ErrorStringPrintf(const char* fmt, ...)
+ __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR;
+ bool FailureReasonIsSet() const { return failure_reason_.size() != 0; }
+
+ // Retrieve class index and class def from the given member. index is the member index, which is
+ // taken as either a field or a method index (as designated by is_field). The result, if the
+ // member and declaring class could be found, is stored in class_type_index and class_def.
+ // This is an expensive lookup, as we have to find the class def by type index, which is a
+ // linear search. The output values should thus be cached by the caller.
+ bool FindClassIndexAndDef(uint32_t index,
+ bool is_field,
+ dex::TypeIndex* class_type_index,
+ const dex::ClassDef** output_class_def);
+
+ // Check validity of the given access flags, interpreted for a field in the context of a class
+ // with the given second access flags.
+ bool CheckFieldAccessFlags(uint32_t idx,
+ uint32_t field_access_flags,
+ uint32_t class_access_flags,
+ std::string* error_message);
+
+ // Check validity of the given method and access flags, in the context of a class with the given
+ // second access flags.
+ bool CheckMethodAccessFlags(uint32_t method_index,
+ uint32_t method_access_flags,
+ uint32_t class_access_flags,
+ uint32_t constructor_flags_by_name,
+ bool has_code,
+ bool expect_direct,
+ std::string* error_message);
+
+ // Check validity of given method if it's a constructor or class initializer.
+ bool CheckConstructorProperties(uint32_t method_index, uint32_t constructor_flags);
+
+ void FindStringRangesForMethodNames();
+
+ template <typename ExtraCheckFn>
+ bool VerifyTypeDescriptor(dex::TypeIndex idx,
+ const char* error_msg1,
+ const char* error_msg2,
+ ExtraCheckFn extra_check);
+
+ const DexFile* const dex_file_;
+ const uint8_t* const begin_;
+ const size_t size_;
+ const char* const location_;
+ const bool verify_checksum_;
+ const DexFile::Header* const header_;
+
+ struct OffsetTypeMapEmptyFn {
+ // Make a hash map slot empty by making the offset 0. Offset 0 is a valid dex file offset that
+ // is in the offset of the dex file header. However, we only store data section items in the
+ // map, and these are after the header.
+ void MakeEmpty(std::pair<uint32_t, uint16_t>& pair) const {
+ pair.first = 0u;
+ }
+ // Check if a hash map slot is empty.
+ bool IsEmpty(const std::pair<uint32_t, uint16_t>& pair) const {
+ return pair.first == 0;
+ }
+ };
+ struct OffsetTypeMapHashCompareFn {
+ // Hash function for offset.
+ size_t operator()(const uint32_t key) const {
+ return key;
+ }
+ // std::equal function for offset.
+ bool operator()(const uint32_t a, const uint32_t b) const {
+ return a == b;
+ }
+ };
+ // Map from offset to dex file type, HashMap for performance reasons.
+ HashMap<uint32_t,
+ uint16_t,
+ OffsetTypeMapEmptyFn,
+ OffsetTypeMapHashCompareFn,
+ OffsetTypeMapHashCompareFn> offset_to_type_map_;
+ const uint8_t* ptr_;
+ const void* previous_item_;
+
+ std::string failure_reason_;
+
+ // Cached string indices for "interesting" entries wrt/ method names. Will be populated by
+ // FindStringRangesForMethodNames (which is automatically called before verifying the
+ // classdataitem section).
+ //
+ // Strings starting with '<' are in the range
+ // [angle_bracket_start_index_,angle_bracket_end_index_).
+ // angle_init_angle_index_ and angle_clinit_angle_index_ denote the indices of "<init>" and
+ // "<clinit>", respectively. If any value is not found, the corresponding index will be larger
+ // than any valid string index for this dex file.
+ struct {
+ size_t angle_bracket_start_index;
+ size_t angle_bracket_end_index;
+ size_t angle_init_angle_index;
+ size_t angle_clinit_angle_index;
+ } init_indices_;
+
+ // A bitvector for verified type descriptors. Each bit corresponds to a type index. A set
+ // bit denotes that the descriptor has been verified wrt/ IsValidDescriptor.
+ std::vector<char> verified_type_descriptors_;
+
+ // Set of type ids for which there are ClassDef elements in the dex file. Using a bitset
+ // avoids all allocations. The bitset should be implemented as 8K of storage, which is
+ // tight enough for all callers.
+ std::bitset<kTypeIdLimit + 1> defined_classes_;
+};
+
static bool IsValidOrNoTypeId(uint16_t low, uint16_t high) {
return (high == 0) || ((high == 0xffffU) && (low == 0xffffU));
}
@@ -210,21 +459,6 @@
return true;
}
-bool DexFileVerifier::Verify(const DexFile* dex_file,
- const uint8_t* begin,
- size_t size,
- const char* location,
- bool verify_checksum,
- std::string* error_msg) {
- std::unique_ptr<DexFileVerifier> verifier(
- new DexFileVerifier(dex_file, begin, size, location, verify_checksum));
- if (!verifier->Verify()) {
- *error_msg = verifier->FailureReason();
- return false;
- }
- return true;
-}
-
bool DexFileVerifier::CheckShortyDescriptorMatch(char shorty_char, const char* descriptor,
bool is_return_type) {
switch (shorty_char) {
@@ -2474,7 +2708,7 @@
// Sanity checks, should be optimized away.
DCHECK_LE(item->class_idx_.index_, kTypeIdLimit);
- static_assert(kTypeIdLimit < kTypeIdSize, "Unexpected type-id range.");
+ DCHECK_LT(kTypeIdLimit, defined_classes_.size());
if (defined_classes_[item->class_idx_.index_]) {
ErrorStringPrintf("Redefinition of class with type idx: '%d'", item->class_idx_.index_);
@@ -3557,4 +3791,20 @@
return true;
}
+bool Verify(const DexFile* dex_file,
+ const uint8_t* begin,
+ size_t size,
+ const char* location,
+ bool verify_checksum,
+ std::string* error_msg) {
+ std::unique_ptr<DexFileVerifier> verifier(
+ new DexFileVerifier(dex_file, begin, size, location, verify_checksum));
+ if (!verifier->Verify()) {
+ *error_msg = verifier->FailureReason();
+ return false;
+ }
+ return true;
+}
+
+} // namespace dex
} // namespace art
diff --git a/libdexfile/dex/dex_file_verifier.h b/libdexfile/dex/dex_file_verifier.h
index fe3aa84..8ae6e7a 100644
--- a/libdexfile/dex/dex_file_verifier.h
+++ b/libdexfile/dex/dex_file_verifier.h
@@ -17,268 +17,24 @@
#ifndef ART_LIBDEXFILE_DEX_DEX_FILE_VERIFIER_H_
#define ART_LIBDEXFILE_DEX_DEX_FILE_VERIFIER_H_
-#include <bitset>
-#include <limits>
+#include <string>
-#include "base/hash_map.h"
-#include "base/safe_map.h"
-#include "class_accessor.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include <inttypes.h>
namespace art {
-class DexFileVerifier {
- public:
- static bool Verify(const DexFile* dex_file,
- const uint8_t* begin,
- size_t size,
- const char* location,
- bool verify_checksum,
- std::string* error_msg);
+class DexFile;
- const std::string& FailureReason() const {
- return failure_reason_;
- }
+namespace dex {
- private:
- DexFileVerifier(const DexFile* dex_file,
- const uint8_t* begin,
- size_t size,
- const char* location,
- bool verify_checksum)
- : dex_file_(dex_file),
- begin_(begin),
- size_(size),
- location_(location),
- verify_checksum_(verify_checksum),
- header_(&dex_file->GetHeader()),
- ptr_(nullptr),
- previous_item_(nullptr),
- init_indices_{std::numeric_limits<size_t>::max(),
- std::numeric_limits<size_t>::max(),
- std::numeric_limits<size_t>::max(),
- std::numeric_limits<size_t>::max()} {
- }
+bool Verify(const DexFile* dex_file,
+ const uint8_t* begin,
+ size_t size,
+ const char* location,
+ bool verify_checksum,
+ std::string* error_msg);
- bool Verify();
-
- bool CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, bool is_return_type);
- bool CheckListSize(const void* start, size_t count, size_t element_size, const char* label);
- // Check a list. The head is assumed to be at *ptr, and elements to be of size element_size. If
- // successful, the ptr will be moved forward the amount covered by the list.
- bool CheckList(size_t element_size, const char* label, const uint8_t* *ptr);
- // Checks whether the offset is zero (when size is zero) or that the offset falls within the area
- // claimed by the file.
- bool CheckValidOffsetAndSize(uint32_t offset, uint32_t size, size_t alignment, const char* label);
- // Checks whether the size is less than the limit.
- bool CheckSizeLimit(uint32_t size, uint32_t limit, const char* label);
- bool CheckIndex(uint32_t field, uint32_t limit, const char* label);
-
- bool CheckHeader();
- bool CheckMap();
-
- uint32_t ReadUnsignedLittleEndian(uint32_t size);
- bool CheckAndGetHandlerOffsets(const dex::CodeItem* code_item,
- uint32_t* handler_offsets, uint32_t handlers_size);
- bool CheckClassDataItemField(uint32_t idx,
- uint32_t access_flags,
- uint32_t class_access_flags,
- dex::TypeIndex class_type_index,
- bool expect_static);
- bool CheckClassDataItemMethod(uint32_t idx,
- uint32_t access_flags,
- uint32_t class_access_flags,
- dex::TypeIndex class_type_index,
- uint32_t code_offset,
- ClassAccessor::Method* direct_method,
- size_t* remaining_directs);
- ALWAYS_INLINE
- bool CheckOrder(const char* type_descr, uint32_t curr_index, uint32_t prev_index);
- bool CheckStaticFieldTypes(const dex::ClassDef* class_def);
-
- bool CheckPadding(size_t offset, uint32_t aligned_offset, DexFile::MapItemType type);
- bool CheckEncodedValue();
- bool CheckEncodedArray();
- bool CheckEncodedAnnotation();
-
- bool CheckIntraClassDataItem();
- // Check all fields of the given type from the given iterator. Load the class data from the first
- // field, if necessary (and return it), or use the given values.
- template <bool kStatic>
- bool CheckIntraClassDataItemFields(size_t count,
- ClassAccessor::Field* field,
- bool* have_class,
- dex::TypeIndex* class_type_index,
- const dex::ClassDef** class_def);
- // Check all methods of the given type from the given iterator. Load the class data from the first
- // method, if necessary (and return it), or use the given values.
- bool CheckIntraClassDataItemMethods(ClassAccessor::Method* method,
- size_t num_methods,
- ClassAccessor::Method* direct_method,
- size_t num_directs,
- bool* have_class,
- dex::TypeIndex* class_type_index,
- const dex::ClassDef** class_def);
-
- bool CheckIntraCodeItem();
- bool CheckIntraStringDataItem();
- bool CheckIntraDebugInfoItem();
- bool CheckIntraAnnotationItem();
- bool CheckIntraAnnotationsDirectoryItem();
- bool CheckIntraHiddenapiClassData();
-
- template <DexFile::MapItemType kType>
- bool CheckIntraSectionIterate(size_t offset, uint32_t count);
- template <DexFile::MapItemType kType>
- bool CheckIntraIdSection(size_t offset, uint32_t count);
- template <DexFile::MapItemType kType>
- bool CheckIntraDataSection(size_t offset, uint32_t count);
- bool CheckIntraSection();
-
- bool CheckOffsetToTypeMap(size_t offset, uint16_t type);
-
- // Note: as sometimes kDexNoIndex16, being 0xFFFF, is a valid return value, we need an
- // additional out parameter to signal any errors loading an index.
- dex::TypeIndex FindFirstClassDataDefiner(const uint8_t* ptr, bool* success);
- dex::TypeIndex FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success);
-
- bool CheckInterStringIdItem();
- bool CheckInterTypeIdItem();
- bool CheckInterProtoIdItem();
- bool CheckInterFieldIdItem();
- bool CheckInterMethodIdItem();
- bool CheckInterClassDefItem();
- bool CheckInterCallSiteIdItem();
- bool CheckInterMethodHandleItem();
- bool CheckInterAnnotationSetRefList();
- bool CheckInterAnnotationSetItem();
- bool CheckInterClassDataItem();
- bool CheckInterAnnotationsDirectoryItem();
-
- bool CheckInterSectionIterate(size_t offset, uint32_t count, DexFile::MapItemType type);
- bool CheckInterSection();
-
- // Load a string by (type) index. Checks whether the index is in bounds, printing the error if
- // not. If there is an error, null is returned.
- const char* CheckLoadStringByIdx(dex::StringIndex idx, const char* error_fmt);
- const char* CheckLoadStringByTypeIdx(dex::TypeIndex type_idx, const char* error_fmt);
-
- // Load a field/method/proto Id by index. Checks whether the index is in bounds, printing the
- // error if not. If there is an error, null is returned.
- const dex::FieldId* CheckLoadFieldId(uint32_t idx, const char* error_fmt);
- const dex::MethodId* CheckLoadMethodId(uint32_t idx, const char* error_fmt);
- const dex::ProtoId* CheckLoadProtoId(dex::ProtoIndex idx, const char* error_fmt);
-
- void ErrorStringPrintf(const char* fmt, ...)
- __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR;
- bool FailureReasonIsSet() const { return failure_reason_.size() != 0; }
-
- // Retrieve class index and class def from the given member. index is the member index, which is
- // taken as either a field or a method index (as designated by is_field). The result, if the
- // member and declaring class could be found, is stored in class_type_index and class_def.
- // This is an expensive lookup, as we have to find the class def by type index, which is a
- // linear search. The output values should thus be cached by the caller.
- bool FindClassIndexAndDef(uint32_t index,
- bool is_field,
- dex::TypeIndex* class_type_index,
- const dex::ClassDef** output_class_def);
-
- // Check validity of the given access flags, interpreted for a field in the context of a class
- // with the given second access flags.
- bool CheckFieldAccessFlags(uint32_t idx,
- uint32_t field_access_flags,
- uint32_t class_access_flags,
- std::string* error_message);
-
- // Check validity of the given method and access flags, in the context of a class with the given
- // second access flags.
- bool CheckMethodAccessFlags(uint32_t method_index,
- uint32_t method_access_flags,
- uint32_t class_access_flags,
- uint32_t constructor_flags_by_name,
- bool has_code,
- bool expect_direct,
- std::string* error_message);
-
- // Check validity of given method if it's a constructor or class initializer.
- bool CheckConstructorProperties(uint32_t method_index, uint32_t constructor_flags);
-
- void FindStringRangesForMethodNames();
-
- template <typename ExtraCheckFn>
- bool VerifyTypeDescriptor(dex::TypeIndex idx,
- const char* error_msg1,
- const char* error_msg2,
- ExtraCheckFn extra_check);
-
- const DexFile* const dex_file_;
- const uint8_t* const begin_;
- const size_t size_;
- const char* const location_;
- const bool verify_checksum_;
- const DexFile::Header* const header_;
-
- struct OffsetTypeMapEmptyFn {
- // Make a hash map slot empty by making the offset 0. Offset 0 is a valid dex file offset that
- // is in the offset of the dex file header. However, we only store data section items in the
- // map, and these are after the header.
- void MakeEmpty(std::pair<uint32_t, uint16_t>& pair) const {
- pair.first = 0u;
- }
- // Check if a hash map slot is empty.
- bool IsEmpty(const std::pair<uint32_t, uint16_t>& pair) const {
- return pair.first == 0;
- }
- };
- struct OffsetTypeMapHashCompareFn {
- // Hash function for offset.
- size_t operator()(const uint32_t key) const {
- return key;
- }
- // std::equal function for offset.
- bool operator()(const uint32_t a, const uint32_t b) const {
- return a == b;
- }
- };
- // Map from offset to dex file type, HashMap for performance reasons.
- HashMap<uint32_t,
- uint16_t,
- OffsetTypeMapEmptyFn,
- OffsetTypeMapHashCompareFn,
- OffsetTypeMapHashCompareFn> offset_to_type_map_;
- const uint8_t* ptr_;
- const void* previous_item_;
-
- std::string failure_reason_;
-
- // Cached string indices for "interesting" entries wrt/ method names. Will be populated by
- // FindStringRangesForMethodNames (which is automatically called before verifying the
- // classdataitem section).
- //
- // Strings starting with '<' are in the range
- // [angle_bracket_start_index_,angle_bracket_end_index_).
- // angle_init_angle_index_ and angle_clinit_angle_index_ denote the indices of "<init>" and
- // "<clinit>", respectively. If any value is not found, the corresponding index will be larger
- // than any valid string index for this dex file.
- struct {
- size_t angle_bracket_start_index;
- size_t angle_bracket_end_index;
- size_t angle_init_angle_index;
- size_t angle_clinit_angle_index;
- } init_indices_;
-
- // A bitvector for verified type descriptors. Each bit corresponds to a type index. A set
- // bit denotes that the descriptor has been verified wrt/ IsValidDescriptor.
- std::vector<char> verified_type_descriptors_;
-
- // Set of type ids for which there are ClassDef elements in the dex file. Using a bitset
- // avoids all allocations. The bitset should be implemented as 8K of storage, which is
- // tight enough for all callers.
- static constexpr size_t kTypeIdSize = 65536u;
- std::bitset<kTypeIdSize> defined_classes_;
-};
-
+} // namespace dex
} // namespace art
#endif // ART_LIBDEXFILE_DEX_DEX_FILE_VERIFIER_H_
diff --git a/libdexfile/dex/dex_file_verifier_test.cc b/libdexfile/dex/dex_file_verifier_test.cc
index b2cff4f..37c06b1 100644
--- a/libdexfile/dex/dex_file_verifier_test.cc
+++ b/libdexfile/dex/dex_file_verifier_test.cc
@@ -21,6 +21,8 @@
#include <functional>
#include <memory>
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
#include "base/leb128.h"
#include "base/macros.h"
@@ -74,12 +76,12 @@
static constexpr bool kVerifyChecksum = true;
std::string error_msg;
- bool success = DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- location,
- kVerifyChecksum,
- &error_msg);
+ bool success = dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ location,
+ kVerifyChecksum,
+ &error_msg);
if (expected_error == nullptr) {
EXPECT_TRUE(success) << error_msg;
} else {
@@ -1617,35 +1619,35 @@
std::string error_msg;
// Good checksum: all pass.
- EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "good checksum, no verify",
- /*verify_checksum=*/ false,
- &error_msg));
- EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "good checksum, verify",
- /*verify_checksum=*/ true,
- &error_msg));
+ EXPECT_TRUE(dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ "good checksum, no verify",
+ /*verify_checksum=*/ false,
+ &error_msg));
+ EXPECT_TRUE(dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ "good checksum, verify",
+ /*verify_checksum=*/ true,
+ &error_msg));
// Bad checksum: !verify_checksum passes verify_checksum fails.
DexFile::Header* header = reinterpret_cast<DexFile::Header*>(
const_cast<uint8_t*>(dex_file->Begin()));
header->checksum_ = 0;
- EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad checksum, no verify",
- /*verify_checksum=*/ false,
- &error_msg));
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad checksum, verify",
- /*verify_checksum=*/ true,
- &error_msg));
+ EXPECT_TRUE(dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ "bad checksum, no verify",
+ /*verify_checksum=*/ false,
+ &error_msg));
+ EXPECT_FALSE(dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ "bad checksum, verify",
+ /*verify_checksum=*/ true,
+ &error_msg));
EXPECT_NE(error_msg.find("Bad checksum"), std::string::npos) << error_msg;
}
@@ -1687,12 +1689,12 @@
// Note: `dex_file` will be destroyed before `dex_bytes`.
std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
std::string error_msg;
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad static method name",
- /*verify_checksum=*/ true,
- &error_msg));
+ EXPECT_FALSE(dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ "bad static method name",
+ /*verify_checksum=*/ true,
+ &error_msg));
}
TEST_F(DexFileVerifierTest, BadVirtualMethodName) {
@@ -1731,12 +1733,12 @@
// Note: `dex_file` will be destroyed before `dex_bytes`.
std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
std::string error_msg;
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad virtual method name",
- /*verify_checksum=*/ true,
- &error_msg));
+ EXPECT_FALSE(dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ "bad virtual method name",
+ /*verify_checksum=*/ true,
+ &error_msg));
}
TEST_F(DexFileVerifierTest, BadClinitSignature) {
@@ -1775,12 +1777,12 @@
// Note: `dex_file` will be destroyed before `dex_bytes`.
std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
std::string error_msg;
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad clinit signature",
- /*verify_checksum=*/ true,
- &error_msg));
+ EXPECT_FALSE(dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ "bad clinit signature",
+ /*verify_checksum=*/ true,
+ &error_msg));
}
TEST_F(DexFileVerifierTest, BadClinitSignatureAgain) {
@@ -1819,12 +1821,12 @@
// Note: `dex_file` will be destroyed before `dex_bytes`.
std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
std::string error_msg;
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad clinit signature",
- /*verify_checksum=*/ true,
- &error_msg));
+ EXPECT_FALSE(dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ "bad clinit signature",
+ /*verify_checksum=*/ true,
+ &error_msg));
}
TEST_F(DexFileVerifierTest, BadInitSignature) {
@@ -1856,12 +1858,12 @@
// Note: `dex_file` will be destroyed before `dex_bytes`.
std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
std::string error_msg;
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad init signature",
- /*verify_checksum=*/ true,
- &error_msg));
+ EXPECT_FALSE(dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ "bad init signature",
+ /*verify_checksum=*/ true,
+ &error_msg));
}
static const char* kInvokeCustomDexFiles[] = {
@@ -2059,12 +2061,12 @@
// Note: `dex_file` will be destroyed before `dex_bytes`.
std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
std::string error_msg;
- EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "good checksum, verify",
- /*verify_checksum=*/ true,
- &error_msg));
+ EXPECT_TRUE(dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ "good checksum, verify",
+ /*verify_checksum=*/ true,
+ &error_msg));
// TODO(oth): Test corruptions (b/35308502)
}
}
@@ -2106,12 +2108,12 @@
// Note: `dex_file` will be destroyed before `dex_bytes`.
std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
std::string error_msg;
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad static field initial values array",
- /*verify_checksum=*/ true,
- &error_msg));
+ EXPECT_FALSE(dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ "bad static field initial values array",
+ /*verify_checksum=*/ true,
+ &error_msg));
}
TEST_F(DexFileVerifierTest, GoodStaticFieldInitialValuesArray) {
@@ -2162,12 +2164,12 @@
// Note: `dex_file` will be destroyed before `dex_bytes`.
std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
std::string error_msg;
- EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "good static field initial values array",
- /*verify_checksum=*/ true,
- &error_msg));
+ EXPECT_TRUE(dex::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ "good static field initial values array",
+ /*verify_checksum=*/ true,
+ &error_msg));
}
} // namespace art
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index e8b3435..eefbe41 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -76,12 +76,12 @@
static void DCheckVerifyDexFile(const art::DexFile& dex) {
if (art::kIsDebugBuild) {
std::string error;
- if (!art::DexFileVerifier::Verify(&dex,
- dex.Begin(),
- dex.Size(),
- "FixedUpDexFile_Verification.dex",
- /*verify_checksum=*/ true,
- &error)) {
+ if (!art::dex::Verify(&dex,
+ dex.Begin(),
+ dex.Size(),
+ "FixedUpDexFile_Verification.dex",
+ /*verify_checksum=*/ true,
+ &error)) {
LOG(FATAL) << "Failed to verify de-quickened dex file: " << error;
}
}