• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "vdex_file.h"
18 
19 #include <sys/mman.h>  // For the PROT_* and MAP_* constants.
20 #include <sys/stat.h>  // for mkdir()
21 #include <sys/types.h>
22 
23 #include <memory>
24 #include <unordered_set>
25 
26 #include "android-base/logging.h"
27 #include "android-base/stringprintf.h"
28 #include "base/bit_utils.h"
29 #include "base/leb128.h"
30 #include "base/macros.h"
31 #include "base/stl_util.h"
32 #include "base/systrace.h"
33 #include "base/unix_file/fd_file.h"
34 #include "base/zip_archive.h"
35 #include "class_linker.h"
36 #include "class_loader_context.h"
37 #include "dex/art_dex_file_loader.h"
38 #include "dex/class_accessor-inl.h"
39 #include "dex/dex_file_loader.h"
40 #include "gc/heap.h"
41 #include "gc/space/image_space.h"
42 #include "handle_scope-inl.h"
43 #include "log/log.h"
44 #include "mirror/class-inl.h"
45 #include "runtime.h"
46 #include "verifier/verifier_deps.h"
47 
48 namespace art HIDDEN {
49 
50 using android::base::StringPrintf;
51 
IsMagicValid() const52 bool VdexFile::VdexFileHeader::IsMagicValid() const {
53   return (memcmp(magic_, kVdexMagic, sizeof(kVdexMagic)) == 0);
54 }
55 
IsVdexVersionValid() const56 bool VdexFile::VdexFileHeader::IsVdexVersionValid() const {
57   return (memcmp(vdex_version_, kVdexVersion, sizeof(kVdexVersion)) == 0);
58 }
59 
VdexFileHeader(bool has_dex_section)60 VdexFile::VdexFileHeader::VdexFileHeader([[maybe_unused]] bool has_dex_section)
61     : number_of_sections_(static_cast<uint32_t>(VdexSection::kNumberOfSections)) {
62   memcpy(magic_, kVdexMagic, sizeof(kVdexMagic));
63   memcpy(vdex_version_, kVdexVersion, sizeof(kVdexVersion));
64   DCHECK(IsMagicValid());
65   DCHECK(IsVdexVersionValid());
66 }
67 
OpenAtAddress(uint8_t * mmap_addr,size_t mmap_size,bool mmap_reuse,const std::string & vdex_filename,bool low_4gb,std::string * error_msg)68 std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
69                                                   size_t mmap_size,
70                                                   bool mmap_reuse,
71                                                   const std::string& vdex_filename,
72                                                   bool low_4gb,
73                                                   std::string* error_msg) {
74   ScopedTrace trace(("VdexFile::OpenAtAddress " + vdex_filename).c_str());
75   if (!OS::FileExists(vdex_filename.c_str())) {
76     *error_msg = "File " + vdex_filename + " does not exist.";
77     return nullptr;
78   }
79 
80   std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex_filename.c_str()));
81   if (vdex_file == nullptr) {
82     *error_msg = "Could not open file for reading";
83     return nullptr;
84   }
85 
86   int64_t vdex_length = vdex_file->GetLength();
87   if (vdex_length == -1) {
88     *error_msg = "Could not read the length of file " + vdex_filename;
89     return nullptr;
90   }
91 
92   return OpenAtAddress(mmap_addr,
93                        mmap_size,
94                        mmap_reuse,
95                        vdex_file->Fd(),
96                        /*start=*/0,
97                        vdex_length,
98                        vdex_filename,
99                        low_4gb,
100                        error_msg);
101 }
102 
OpenAtAddress(uint8_t * mmap_addr,size_t mmap_size,bool mmap_reuse,int file_fd,off_t start,size_t vdex_length,const std::string & vdex_filename,bool low_4gb,std::string * error_msg)103 std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
104                                                   size_t mmap_size,
105                                                   bool mmap_reuse,
106                                                   int file_fd,
107                                                   off_t start,
108                                                   size_t vdex_length,
109                                                   const std::string& vdex_filename,
110                                                   bool low_4gb,
111                                                   std::string* error_msg) {
112   if (mmap_addr != nullptr && mmap_size < vdex_length) {
113     *error_msg = StringPrintf("Insufficient pre-allocated space to mmap vdex: %zu and %zu",
114                               mmap_size,
115                               vdex_length);
116     return nullptr;
117   }
118   CHECK_IMPLIES(mmap_reuse, mmap_addr != nullptr);
119   // Start as PROT_WRITE so we can mprotect back to it if we want to.
120   MemMap mmap = MemMap::MapFileAtAddress(mmap_addr,
121                                          vdex_length,
122                                          PROT_READ | PROT_WRITE,
123                                          MAP_PRIVATE,
124                                          file_fd,
125                                          start,
126                                          low_4gb,
127                                          vdex_filename.c_str(),
128                                          mmap_reuse,
129                                          /*reservation=*/nullptr,
130                                          error_msg);
131   if (!mmap.IsValid()) {
132     *error_msg = "Failed to mmap file " + vdex_filename + " : " + *error_msg;
133     return nullptr;
134   }
135 
136   std::unique_ptr<VdexFile> vdex(new VdexFile(std::move(mmap)));
137   if (!vdex->IsValid()) {
138     *error_msg = "Vdex file is not valid";
139     return nullptr;
140   }
141 
142   return vdex;
143 }
144 
OpenFromDm(const std::string & filename,const ZipArchive & archive,std::string * error_msg)145 std::unique_ptr<VdexFile> VdexFile::OpenFromDm(const std::string& filename,
146                                                const ZipArchive& archive,
147                                                std::string* error_msg) {
148   std::unique_ptr<ZipEntry> zip_entry(archive.Find(VdexFile::kVdexNameInDmFile, error_msg));
149   if (zip_entry == nullptr) {
150     *error_msg = ART_FORMAT("No {} file in DexMetadata archive. Not doing fast verification: {}",
151                             VdexFile::kVdexNameInDmFile,
152                             *error_msg);
153     return nullptr;
154   }
155   MemMap input_file = zip_entry->MapDirectlyOrExtract(
156       filename.c_str(), VdexFile::kVdexNameInDmFile, error_msg, alignof(VdexFile));
157   if (!input_file.IsValid()) {
158     *error_msg = "Could not open vdex file in DexMetadata archive: " + *error_msg;
159     return nullptr;
160   }
161   std::unique_ptr<VdexFile> vdex_file = std::make_unique<VdexFile>(std::move(input_file));
162   if (!vdex_file->IsValid()) {
163     *error_msg = "The dex metadata .vdex is not valid. Ignoring it.";
164     return nullptr;
165   }
166   if (vdex_file->HasDexSection()) {
167     *error_msg = "The dex metadata is not allowed to contain dex files";
168     android_errorWriteLog(0x534e4554, "178055795");  // Report to SafetyNet.
169     return nullptr;
170   }
171   return vdex_file;
172 }
173 
OpenFromDm(const std::string & filename,uint8_t * vdex_begin_,uint8_t * vdex_end_,std::string * error_msg)174 std::unique_ptr<VdexFile> VdexFile::OpenFromDm(const std::string& filename,
175                                                uint8_t* vdex_begin_,
176                                                uint8_t* vdex_end_,
177                                                std::string* error_msg) {
178   std::string vdex_filename = filename + OatFile::kZipSeparator + kVdexNameInDmFile;
179   // This overload of `OpenFromDm` is for loading both odex and vdex. We need to map the vdex at the
180   // address required by the odex, so the vdex must be uncompressed and page-aligned.
181   // To load vdex only, use the other overload.
182   FileWithRange vdex_file_with_range = OS::OpenFileDirectlyOrFromZip(
183       vdex_filename, OatFile::kZipSeparator, /*alignment=*/MemMap::GetPageSize(), error_msg);
184   if (vdex_file_with_range.file == nullptr) {
185     return nullptr;
186   }
187   std::unique_ptr<VdexFile> vdex_file =
188       VdexFile::OpenAtAddress(vdex_begin_,
189                               vdex_end_ - vdex_begin_,
190                               /*mmap_reuse=*/vdex_begin_ != nullptr,
191                               vdex_file_with_range.file->Fd(),
192                               vdex_file_with_range.start,
193                               vdex_file_with_range.length,
194                               vdex_filename,
195                               /*low_4gb=*/false,
196                               error_msg);
197   if (vdex_file == nullptr) {
198     return nullptr;
199   }
200   if (vdex_file->HasDexSection()) {
201     *error_msg = "The dex metadata is not allowed to contain dex files";
202     return nullptr;
203   }
204   return vdex_file;
205 }
206 
IsValid() const207 bool VdexFile::IsValid() const {
208   if (mmap_.Size() < sizeof(VdexFileHeader) || !GetVdexFileHeader().IsValid()) {
209     return false;
210   }
211 
212   // Invalidate vdex files that contain dex files in the no longer supported
213   // compact dex format. Revert this whenever the vdex version is bumped.
214   size_t i = 0;
215   for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr, i); dex_file_start != nullptr;
216        dex_file_start = GetNextDexFileData(dex_file_start, ++i)) {
217     if (!DexFileLoader::IsMagicValid(dex_file_start)) {
218       return false;
219     }
220   }
221   return true;
222 }
223 
GetNextDexFileData(const uint8_t * cursor,uint32_t dex_file_index) const224 const uint8_t* VdexFile::GetNextDexFileData(const uint8_t* cursor, uint32_t dex_file_index) const {
225   DCHECK(cursor == nullptr || (cursor > Begin() && cursor <= End()));
226   if (cursor == nullptr) {
227     // Beginning of the iteration, return the first dex file if there is one.
228     return HasDexSection() ? DexBegin() : nullptr;
229   } else if (dex_file_index >= GetNumberOfDexFiles()) {
230     return nullptr;
231   } else {
232     // Fetch the next dex file. Return null if there is none.
233     const uint8_t* data = cursor + reinterpret_cast<const DexFile::Header*>(cursor)->file_size_;
234     // Dex files are required to be 4 byte aligned. the OatWriter makes sure they are, see
235     // OatWriter::SeekToDexFiles.
236     return AlignUp(data, 4);
237   }
238 }
239 
GetNextTypeLookupTableData(const uint8_t * cursor,uint32_t dex_file_index) const240 const uint8_t* VdexFile::GetNextTypeLookupTableData(const uint8_t* cursor,
241                                                     uint32_t dex_file_index) const {
242   if (cursor == nullptr) {
243     // Beginning of the iteration, return the first dex file if there is one.
244     return HasTypeLookupTableSection() ? TypeLookupTableDataBegin() : nullptr;
245   } else if (dex_file_index >= GetNumberOfDexFiles()) {
246     return nullptr;
247   } else {
248     const uint8_t* data = cursor + sizeof(uint32_t) + reinterpret_cast<const uint32_t*>(cursor)[0];
249     // TypeLookupTables are required to be 4 byte aligned. the OatWriter makes sure they are.
250     // We don't check this here to be defensive against corrupted vdex files.
251     // Callers should check the returned value matches their expectations.
252     return data;
253   }
254 }
255 
OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>> * dex_files,std::string * error_msg) const256 bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
257                                std::string* error_msg) const {
258   size_t i = 0;
259   auto dex_file_container = std::make_shared<MemoryDexFileContainer>(Begin(), End());
260   for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr, i);
261        dex_file_start != nullptr;
262        dex_file_start = GetNextDexFileData(dex_file_start, ++i)) {
263     // TODO: Supply the location information for a vdex file.
264     static constexpr char kVdexLocation[] = "";
265     std::string location = DexFileLoader::GetMultiDexLocation(i, kVdexLocation);
266     ArtDexFileLoader dex_file_loader(dex_file_container, location);
267     std::unique_ptr<const DexFile> dex(dex_file_loader.OpenOne(dex_file_start - Begin(),
268                                                                GetLocationChecksum(i),
269                                                                /*oat_dex_file=*/nullptr,
270                                                                /*verify=*/false,
271                                                                /*verify_checksum=*/false,
272                                                                error_msg));
273     if (dex == nullptr) {
274       return false;
275     }
276     dex_files->push_back(std::move(dex));
277   }
278   return true;
279 }
280 
CreateDirectories(const std::string & child_path,std::string * error_msg)281 static bool CreateDirectories(const std::string& child_path, /* out */ std::string* error_msg) {
282   size_t last_slash_pos = child_path.find_last_of('/');
283   CHECK_NE(last_slash_pos, std::string::npos) << "Invalid path: " << child_path;
284   std::string parent_path = child_path.substr(0, last_slash_pos);
285   if (OS::DirectoryExists(parent_path.c_str())) {
286     return true;
287   } else if (CreateDirectories(parent_path, error_msg)) {
288     if (mkdir(parent_path.c_str(), 0700) == 0) {
289       return true;
290     }
291     *error_msg = "Could not create directory " + parent_path;
292     return false;
293   } else {
294     return false;
295   }
296 }
297 
WriteToDisk(const std::string & path,const std::vector<const DexFile * > & dex_files,const verifier::VerifierDeps & verifier_deps,std::string * error_msg)298 bool VdexFile::WriteToDisk(const std::string& path,
299                            const std::vector<const DexFile*>& dex_files,
300                            const verifier::VerifierDeps& verifier_deps,
301                            std::string* error_msg) {
302   std::vector<uint8_t> verifier_deps_data;
303   verifier_deps.Encode(dex_files, &verifier_deps_data);
304   uint32_t verifier_deps_size = verifier_deps_data.size();
305   // Add padding so the type lookup tables are 4 byte aligned.
306   uint32_t verifier_deps_with_padding_size = RoundUp(verifier_deps_data.size(), 4);
307   DCHECK_GE(verifier_deps_with_padding_size, verifier_deps_data.size());
308   verifier_deps_data.resize(verifier_deps_with_padding_size, 0);
309 
310   size_t type_lookup_table_size = 0u;
311   for (const DexFile* dex_file : dex_files) {
312     type_lookup_table_size +=
313         sizeof(uint32_t) + TypeLookupTable::RawDataLength(dex_file->NumClassDefs());
314   }
315 
316   VdexFile::VdexFileHeader vdex_header(/* has_dex_section= */ false);
317   VdexFile::VdexSectionHeader sections[static_cast<uint32_t>(VdexSection::kNumberOfSections)];
318 
319   // Set checksum section.
320   sections[VdexSection::kChecksumSection].section_kind = VdexSection::kChecksumSection;
321   sections[VdexSection::kChecksumSection].section_offset = GetChecksumsOffset();
322   sections[VdexSection::kChecksumSection].section_size =
323       sizeof(VdexFile::VdexChecksum) * dex_files.size();
324 
325   // Set dex section.
326   sections[VdexSection::kDexFileSection].section_kind = VdexSection::kDexFileSection;
327   sections[VdexSection::kDexFileSection].section_offset = 0u;
328   sections[VdexSection::kDexFileSection].section_size = 0u;
329 
330   // Set VerifierDeps section.
331   sections[VdexSection::kVerifierDepsSection].section_kind = VdexSection::kVerifierDepsSection;
332   sections[VdexSection::kVerifierDepsSection].section_offset =
333       GetChecksumsOffset() + sections[kChecksumSection].section_size;
334   sections[VdexSection::kVerifierDepsSection].section_size = verifier_deps_size;
335 
336   // Set TypeLookupTable section.
337   sections[VdexSection::kTypeLookupTableSection].section_kind =
338       VdexSection::kTypeLookupTableSection;
339   sections[VdexSection::kTypeLookupTableSection].section_offset =
340       sections[VdexSection::kVerifierDepsSection].section_offset + verifier_deps_with_padding_size;
341   sections[VdexSection::kTypeLookupTableSection].section_size = type_lookup_table_size;
342 
343   if (!CreateDirectories(path, error_msg)) {
344     return false;
345   }
346 
347   std::unique_ptr<File> out(OS::CreateEmptyFileWriteOnly(path.c_str()));
348   if (out == nullptr) {
349     *error_msg = "Could not open " + path + " for writing";
350     return false;
351   }
352 
353   // Write header.
354   if (!out->WriteFully(reinterpret_cast<const char*>(&vdex_header), sizeof(vdex_header))) {
355     *error_msg = "Could not write vdex header to " + path;
356     out->Unlink();
357     return false;
358   }
359 
360   // Write section infos.
361   if (!out->WriteFully(reinterpret_cast<const char*>(&sections), sizeof(sections))) {
362     *error_msg = "Could not write vdex sections to " + path;
363     out->Unlink();
364     return false;
365   }
366 
367   // Write checksum section.
368   for (const DexFile* dex_file : dex_files) {
369     uint32_t checksum = dex_file->GetLocationChecksum();
370     const uint32_t* checksum_ptr = &checksum;
371     static_assert(sizeof(*checksum_ptr) == sizeof(VdexFile::VdexChecksum));
372     if (!out->WriteFully(reinterpret_cast<const char*>(checksum_ptr),
373                          sizeof(VdexFile::VdexChecksum))) {
374       *error_msg = "Could not write dex checksums to " + path;
375       out->Unlink();
376       return false;
377     }
378   }
379 
380   if (!out->WriteFully(reinterpret_cast<const char*>(verifier_deps_data.data()),
381                        verifier_deps_with_padding_size)) {
382     *error_msg = "Could not write verifier deps to " + path;
383     out->Unlink();
384     return false;
385   }
386 
387   size_t written_type_lookup_table_size = 0;
388   for (const DexFile* dex_file : dex_files) {
389     TypeLookupTable type_lookup_table = TypeLookupTable::Create(*dex_file);
390     uint32_t size = type_lookup_table.RawDataLength();
391     DCHECK_ALIGNED(size, 4);
392     if (!out->WriteFully(reinterpret_cast<const char*>(&size), sizeof(uint32_t)) ||
393         !out->WriteFully(reinterpret_cast<const char*>(type_lookup_table.RawData()), size)) {
394       *error_msg = "Could not write type lookup table " + path;
395       out->Unlink();
396       return false;
397     }
398     written_type_lookup_table_size += sizeof(uint32_t) + size;
399   }
400   DCHECK_EQ(written_type_lookup_table_size, type_lookup_table_size);
401 
402   if (out->FlushClose() != 0) {
403     *error_msg = "Could not flush and close " + path;
404     out->Unlink();
405     return false;
406   }
407 
408   return true;
409 }
410 
MatchesDexFileChecksums(const std::vector<const DexFile::Header * > & dex_headers) const411 bool VdexFile::MatchesDexFileChecksums(const std::vector<const DexFile::Header*>& dex_headers)
412     const {
413   if (dex_headers.size() != GetNumberOfDexFiles()) {
414     LOG(WARNING) << "Mismatch of number of dex files in vdex (expected="
415         << GetNumberOfDexFiles() << ", actual=" << dex_headers.size() << ")";
416     return false;
417   }
418   const VdexChecksum* checksums = GetDexChecksumsArray();
419   for (size_t i = 0; i < dex_headers.size(); ++i) {
420     if (checksums[i] != dex_headers[i]->checksum_) {
421       LOG(WARNING) << "Mismatch of dex file checksum in vdex (index=" << i << ")";
422       return false;
423     }
424   }
425   return true;
426 }
427 
FindClassAndClearException(ClassLinker * class_linker,Thread * self,const char * descriptor,size_t descriptor_length,Handle<mirror::ClassLoader> class_loader)428 static ObjPtr<mirror::Class> FindClassAndClearException(ClassLinker* class_linker,
429                                                         Thread* self,
430                                                         const char* descriptor,
431                                                         size_t descriptor_length,
432                                                         Handle<mirror::ClassLoader> class_loader)
433     REQUIRES_SHARED(Locks::mutator_lock_) {
434   ObjPtr<mirror::Class> result =
435       class_linker->FindClass(self, descriptor, descriptor_length, class_loader);
436   if (result == nullptr) {
437     DCHECK(self->IsExceptionPending());
438     self->ClearException();
439   }
440   return result;
441 }
442 
GetStringFromIndex(const DexFile & dex_file,dex::StringIndex string_id,uint32_t number_of_extra_strings,const uint32_t * extra_strings_offsets,const uint8_t * verifier_deps,size_t * utf8_length)443 static const char* GetStringFromIndex(const DexFile& dex_file,
444                                       dex::StringIndex string_id,
445                                       uint32_t number_of_extra_strings,
446                                       const uint32_t* extra_strings_offsets,
447                                       const uint8_t* verifier_deps,
448                                       /*out*/ size_t* utf8_length) {
449   uint32_t num_ids_in_dex = dex_file.NumStringIds();
450   if (string_id.index_ < num_ids_in_dex) {
451     uint32_t utf16_length;
452     const char* str = dex_file.GetStringDataAndUtf16Length(string_id, &utf16_length);
453     *utf8_length = DexFile::Utf8Length(str, utf16_length);
454     return str;
455   } else {
456     CHECK_LT(string_id.index_ - num_ids_in_dex, number_of_extra_strings);
457     uint32_t offset = extra_strings_offsets[string_id.index_ - num_ids_in_dex];
458     const char* str = reinterpret_cast<const char*>(verifier_deps) + offset;
459     *utf8_length = strlen(str);
460     return str;
461   }
462 }
463 
464 // Returns an array of offsets where the assignability checks for each class
465 // definition are stored.
GetDexFileClassDefs(const uint8_t * verifier_deps,uint32_t index)466 static const uint32_t* GetDexFileClassDefs(const uint8_t* verifier_deps, uint32_t index) {
467   uint32_t dex_file_offset = reinterpret_cast<const uint32_t*>(verifier_deps)[index];
468   return reinterpret_cast<const uint32_t*>(verifier_deps + dex_file_offset);
469 }
470 
471 // Returns an array of offsets where extra strings are stored.
GetExtraStringsOffsets(const DexFile & dex_file,const uint8_t * verifier_deps,const uint32_t * dex_file_class_defs,uint32_t * number_of_extra_strings)472 static const uint32_t* GetExtraStringsOffsets(const DexFile& dex_file,
473                                               const uint8_t* verifier_deps,
474                                               const uint32_t* dex_file_class_defs,
475                                               /*out*/ uint32_t* number_of_extra_strings) {
476   // The information for strings is right after dex_file_class_defs, 4-byte
477   // aligned
478   uint32_t end_of_assignability_types = dex_file_class_defs[dex_file.NumClassDefs()];
479   const uint8_t* strings_data_start =
480       AlignUp(verifier_deps + end_of_assignability_types, sizeof(uint32_t));
481   // First entry is the number of extra strings for this dex file.
482   *number_of_extra_strings = *reinterpret_cast<const uint32_t*>(strings_data_start);
483   // Then an array of offsets in `verifier_deps` for the extra strings.
484   return reinterpret_cast<const uint32_t*>(strings_data_start + sizeof(uint32_t));
485 }
486 
ComputeClassStatus(Thread * self,Handle<mirror::Class> cls) const487 ClassStatus VdexFile::ComputeClassStatus(Thread* self, Handle<mirror::Class> cls) const {
488   const DexFile& dex_file = cls->GetDexFile();
489   uint16_t class_def_index = cls->GetDexClassDefIndex();
490 
491   // Find which dex file index from within the vdex file.
492   uint32_t index = 0;
493   for (; index < GetNumberOfDexFiles(); ++index) {
494     if (dex_file.GetLocationChecksum() == GetLocationChecksum(index)) {
495       break;
496     }
497   }
498 
499   DCHECK_NE(index, GetNumberOfDexFiles());
500 
501   const uint8_t* verifier_deps = GetVerifierDepsData().data();
502   const uint32_t* dex_file_class_defs = GetDexFileClassDefs(verifier_deps, index);
503 
504   // Fetch type checks offsets.
505   uint32_t class_def_offset = dex_file_class_defs[class_def_index];
506   if (class_def_offset == verifier::VerifierDeps::kNotVerifiedMarker) {
507     // Return a status that needs re-verification.
508     return ClassStatus::kResolved;
509   }
510   // End offset for this class's type checks. We know there is one and the loop
511   // will terminate.
512   uint32_t end_offset = verifier::VerifierDeps::kNotVerifiedMarker;
513   for (uint32_t i = class_def_index + 1; i < dex_file.NumClassDefs() + 1; ++i) {
514     end_offset = dex_file_class_defs[i];
515     if (end_offset != verifier::VerifierDeps::kNotVerifiedMarker) {
516       break;
517     }
518   }
519   DCHECK_NE(end_offset, verifier::VerifierDeps::kNotVerifiedMarker);
520 
521   uint32_t number_of_extra_strings = 0;
522   // Offset where extra strings are stored.
523   const uint32_t* extra_strings_offsets = GetExtraStringsOffsets(dex_file,
524                                                                  verifier_deps,
525                                                                  dex_file_class_defs,
526                                                                  &number_of_extra_strings);
527 
528   // Loop over and perform each assignability check.
529   StackHandleScope<3> hs(self);
530   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
531   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(cls->GetClassLoader()));
532   MutableHandle<mirror::Class> source(hs.NewHandle<mirror::Class>(nullptr));
533   MutableHandle<mirror::Class> destination(hs.NewHandle<mirror::Class>(nullptr));
534 
535   const uint8_t* cursor = verifier_deps + class_def_offset;
536   const uint8_t* end = verifier_deps + end_offset;
537   while (cursor < end) {
538     uint32_t destination_index;
539     uint32_t source_index;
540     if (UNLIKELY(!DecodeUnsignedLeb128Checked(&cursor, end, &destination_index) ||
541                  !DecodeUnsignedLeb128Checked(&cursor, end, &source_index))) {
542       // Error parsing the data, just return that we are not verified.
543       return ClassStatus::kResolved;
544     }
545     size_t destination_desc_length;
546     const char* destination_desc = GetStringFromIndex(dex_file,
547                                                       dex::StringIndex(destination_index),
548                                                       number_of_extra_strings,
549                                                       extra_strings_offsets,
550                                                       verifier_deps,
551                                                       &destination_desc_length);
552     destination.Assign(FindClassAndClearException(
553         class_linker, self, destination_desc, destination_desc_length, class_loader));
554 
555     size_t source_desc_length;
556     const char* source_desc = GetStringFromIndex(dex_file,
557                                                  dex::StringIndex(source_index),
558                                                  number_of_extra_strings,
559                                                  extra_strings_offsets,
560                                                  verifier_deps,
561                                                  &source_desc_length);
562     source.Assign(FindClassAndClearException(
563         class_linker, self, source_desc, source_desc_length, class_loader));
564 
565     if (destination == nullptr || source == nullptr) {
566       cls->SetHasTypeChecksFailure();
567       // The interpreter / compiler can handle a missing class.
568       continue;
569     }
570 
571     DCHECK(destination->IsResolved() && source->IsResolved());
572     if (!destination->IsAssignableFrom(source.Get())) {
573       VLOG(verifier) << "Vdex checking failed for " << cls->PrettyClass()
574                      << ": expected " << destination->PrettyClass()
575                      << " to be assignable from " << source->PrettyClass();
576       // An implicit assignability check is failing in the code, return that the
577       // class is not verified.
578       return ClassStatus::kResolved;
579     }
580   }
581 
582   return ClassStatus::kVerifiedNeedsAccessChecks;
583 }
584 
585 }  // namespace art
586