• 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 
22 #include <memory>
23 #include <unordered_set>
24 
25 #include <android-base/logging.h>
26 #include <android-base/stringprintf.h>
27 #include <log/log.h>
28 
29 #include "base/bit_utils.h"
30 #include "base/leb128.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 "mirror/class-inl.h"
43 #include "quicken_info.h"
44 #include "handle_scope-inl.h"
45 #include "runtime.h"
46 #include "verifier/verifier_deps.h"
47 
48 namespace art {
49 
50 using android::base::StringPrintf;
51 
52 constexpr uint8_t VdexFile::VdexFileHeader::kVdexInvalidMagic[4];
53 constexpr uint8_t VdexFile::VdexFileHeader::kVdexMagic[4];
54 constexpr uint8_t VdexFile::VdexFileHeader::kVdexVersion[4];
55 
IsMagicValid() const56 bool VdexFile::VdexFileHeader::IsMagicValid() const {
57   return (memcmp(magic_, kVdexMagic, sizeof(kVdexMagic)) == 0);
58 }
59 
IsVdexVersionValid() const60 bool VdexFile::VdexFileHeader::IsVdexVersionValid() const {
61   return (memcmp(vdex_version_, kVdexVersion, sizeof(kVdexVersion)) == 0);
62 }
63 
VdexFileHeader(bool has_dex_section ATTRIBUTE_UNUSED)64 VdexFile::VdexFileHeader::VdexFileHeader(bool has_dex_section ATTRIBUTE_UNUSED)
65     : number_of_sections_(static_cast<uint32_t>(VdexSection::kNumberOfSections)) {
66   memcpy(magic_, kVdexMagic, sizeof(kVdexMagic));
67   memcpy(vdex_version_, kVdexVersion, sizeof(kVdexVersion));
68   DCHECK(IsMagicValid());
69   DCHECK(IsVdexVersionValid());
70 }
71 
OpenAtAddress(uint8_t * mmap_addr,size_t mmap_size,bool mmap_reuse,const std::string & vdex_filename,bool writable,bool low_4gb,std::string * error_msg)72 std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
73                                                   size_t mmap_size,
74                                                   bool mmap_reuse,
75                                                   const std::string& vdex_filename,
76                                                   bool writable,
77                                                   bool low_4gb,
78                                                   std::string* error_msg) {
79   ScopedTrace trace(("VdexFile::OpenAtAddress " + vdex_filename).c_str());
80   if (!OS::FileExists(vdex_filename.c_str())) {
81     *error_msg = "File " + vdex_filename + " does not exist.";
82     return nullptr;
83   }
84 
85   std::unique_ptr<File> vdex_file;
86   if (writable) {
87     vdex_file.reset(OS::OpenFileReadWrite(vdex_filename.c_str()));
88   } else {
89     vdex_file.reset(OS::OpenFileForReading(vdex_filename.c_str()));
90   }
91   if (vdex_file == nullptr) {
92     *error_msg = "Could not open file " + vdex_filename +
93                  (writable ? " for read/write" : "for reading");
94     return nullptr;
95   }
96 
97   int64_t vdex_length = vdex_file->GetLength();
98   if (vdex_length == -1) {
99     *error_msg = "Could not read the length of file " + vdex_filename;
100     return nullptr;
101   }
102 
103   return OpenAtAddress(mmap_addr,
104                        mmap_size,
105                        mmap_reuse,
106                        vdex_file->Fd(),
107                        vdex_length,
108                        vdex_filename,
109                        writable,
110                        low_4gb,
111                        error_msg);
112 }
113 
OpenAtAddress(uint8_t * mmap_addr,size_t mmap_size,bool mmap_reuse,int file_fd,size_t vdex_length,const std::string & vdex_filename,bool writable,bool low_4gb,std::string * error_msg)114 std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
115                                                   size_t mmap_size,
116                                                   bool mmap_reuse,
117                                                   int file_fd,
118                                                   size_t vdex_length,
119                                                   const std::string& vdex_filename,
120                                                   bool writable,
121                                                   bool low_4gb,
122                                                   std::string* error_msg) {
123   if (mmap_addr != nullptr && mmap_size < vdex_length) {
124     *error_msg = StringPrintf("Insufficient pre-allocated space to mmap vdex: %zu and %zu",
125                               mmap_size,
126                               vdex_length);
127     return nullptr;
128   }
129   CHECK_IMPLIES(mmap_reuse, mmap_addr != nullptr);
130   // Start as PROT_WRITE so we can mprotect back to it if we want to.
131   MemMap mmap = MemMap::MapFileAtAddress(
132       mmap_addr,
133       vdex_length,
134       PROT_READ | PROT_WRITE,
135       writable ? MAP_SHARED : MAP_PRIVATE,
136       file_fd,
137       /* start= */ 0u,
138       low_4gb,
139       vdex_filename.c_str(),
140       mmap_reuse,
141       /* reservation= */ nullptr,
142       error_msg);
143   if (!mmap.IsValid()) {
144     *error_msg = "Failed to mmap file " + vdex_filename + " : " + *error_msg;
145     return nullptr;
146   }
147 
148   std::unique_ptr<VdexFile> vdex(new VdexFile(std::move(mmap)));
149   if (!vdex->IsValid()) {
150     *error_msg = "Vdex file is not valid";
151     return nullptr;
152   }
153 
154   return vdex;
155 }
156 
OpenFromDm(const std::string & filename,const ZipArchive & archive)157 std::unique_ptr<VdexFile> VdexFile::OpenFromDm(const std::string& filename,
158                                                const ZipArchive& archive) {
159   std::string error_msg;
160   std::unique_ptr<ZipEntry> zip_entry(archive.Find(VdexFile::kVdexNameInDmFile, &error_msg));
161   if (zip_entry == nullptr) {
162     LOG(INFO) << "No " << VdexFile::kVdexNameInDmFile << " file in DexMetadata archive. "
163               << "Not doing fast verification.";
164     return nullptr;
165   }
166   MemMap input_file = zip_entry->MapDirectlyOrExtract(
167       filename.c_str(),
168       VdexFile::kVdexNameInDmFile,
169       &error_msg,
170       alignof(VdexFile));
171   if (!input_file.IsValid()) {
172     LOG(WARNING) << "Could not open vdex file in DexMetadata archive: " << error_msg;
173     return nullptr;
174   }
175   std::unique_ptr<VdexFile> vdex_file = std::make_unique<VdexFile>(std::move(input_file));
176   if (!vdex_file->IsValid()) {
177     LOG(WARNING) << "The dex metadata .vdex is not valid. Ignoring it.";
178     return nullptr;
179   }
180   if (vdex_file->HasDexSection()) {
181     LOG(ERROR) << "The dex metadata is not allowed to contain dex files";
182     android_errorWriteLog(0x534e4554, "178055795");  // Report to SafetyNet.
183     return nullptr;
184   }
185   return vdex_file;
186 }
187 
GetNextDexFileData(const uint8_t * cursor,uint32_t dex_file_index) const188 const uint8_t* VdexFile::GetNextDexFileData(const uint8_t* cursor, uint32_t dex_file_index) const {
189   DCHECK(cursor == nullptr || (cursor > Begin() && cursor <= End()));
190   if (cursor == nullptr) {
191     // Beginning of the iteration, return the first dex file if there is one.
192     return HasDexSection() ? DexBegin() : nullptr;
193   } else if (dex_file_index >= GetNumberOfDexFiles()) {
194     return nullptr;
195   } else {
196     // Fetch the next dex file. Return null if there is none.
197     const uint8_t* data = cursor + reinterpret_cast<const DexFile::Header*>(cursor)->file_size_;
198     // Dex files are required to be 4 byte aligned. the OatWriter makes sure they are, see
199     // OatWriter::SeekToDexFiles.
200     return AlignUp(data, 4);
201   }
202 }
203 
GetNextTypeLookupTableData(const uint8_t * cursor,uint32_t dex_file_index) const204 const uint8_t* VdexFile::GetNextTypeLookupTableData(const uint8_t* cursor,
205                                                     uint32_t dex_file_index) const {
206   if (cursor == nullptr) {
207     // Beginning of the iteration, return the first dex file if there is one.
208     return HasTypeLookupTableSection() ? TypeLookupTableDataBegin() : nullptr;
209   } else if (dex_file_index >= GetNumberOfDexFiles()) {
210     return nullptr;
211   } else {
212     const uint8_t* data = cursor + sizeof(uint32_t) + reinterpret_cast<const uint32_t*>(cursor)[0];
213     // TypeLookupTables are required to be 4 byte aligned. the OatWriter makes sure they are.
214     // We don't check this here to be defensive against corrupted vdex files.
215     // Callers should check the returned value matches their expectations.
216     return data;
217   }
218 }
219 
OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>> * dex_files,std::string * error_msg) const220 bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
221                                std::string* error_msg) const {
222   const ArtDexFileLoader dex_file_loader;
223   size_t i = 0;
224   for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr, i);
225        dex_file_start != nullptr;
226        dex_file_start = GetNextDexFileData(dex_file_start, ++i)) {
227     size_t size = reinterpret_cast<const DexFile::Header*>(dex_file_start)->file_size_;
228     // TODO: Supply the location information for a vdex file.
229     static constexpr char kVdexLocation[] = "";
230     std::string location = DexFileLoader::GetMultiDexLocation(i, kVdexLocation);
231     std::unique_ptr<const DexFile> dex(dex_file_loader.OpenWithDataSection(
232         dex_file_start,
233         size,
234         /*data_base=*/ nullptr,
235         /*data_size=*/ 0u,
236         location,
237         GetLocationChecksum(i),
238         /*oat_dex_file=*/ nullptr,
239         /*verify=*/ false,
240         /*verify_checksum=*/ false,
241         error_msg));
242     if (dex == nullptr) {
243       return false;
244     }
245     dex_files->push_back(std::move(dex));
246   }
247   return true;
248 }
249 
CreateDirectories(const std::string & child_path,std::string * error_msg)250 static bool CreateDirectories(const std::string& child_path, /* out */ std::string* error_msg) {
251   size_t last_slash_pos = child_path.find_last_of('/');
252   CHECK_NE(last_slash_pos, std::string::npos) << "Invalid path: " << child_path;
253   std::string parent_path = child_path.substr(0, last_slash_pos);
254   if (OS::DirectoryExists(parent_path.c_str())) {
255     return true;
256   } else if (CreateDirectories(parent_path, error_msg)) {
257     if (mkdir(parent_path.c_str(), 0700) == 0) {
258       return true;
259     }
260     *error_msg = "Could not create directory " + parent_path;
261     return false;
262   } else {
263     return false;
264   }
265 }
266 
WriteToDisk(const std::string & path,const std::vector<const DexFile * > & dex_files,const verifier::VerifierDeps & verifier_deps,std::string * error_msg)267 bool VdexFile::WriteToDisk(const std::string& path,
268                            const std::vector<const DexFile*>& dex_files,
269                            const verifier::VerifierDeps& verifier_deps,
270                            std::string* error_msg) {
271   std::vector<uint8_t> verifier_deps_data;
272   verifier_deps.Encode(dex_files, &verifier_deps_data);
273   uint32_t verifier_deps_size = verifier_deps_data.size();
274   // Add padding so the type lookup tables are 4 byte aligned.
275   uint32_t verifier_deps_with_padding_size = RoundUp(verifier_deps_data.size(), 4);
276   DCHECK_GE(verifier_deps_with_padding_size, verifier_deps_data.size());
277   verifier_deps_data.resize(verifier_deps_with_padding_size, 0);
278 
279   size_t type_lookup_table_size = 0u;
280   for (const DexFile* dex_file : dex_files) {
281     type_lookup_table_size +=
282         sizeof(uint32_t) + TypeLookupTable::RawDataLength(dex_file->NumClassDefs());
283   }
284 
285   VdexFile::VdexFileHeader vdex_header(/* has_dex_section= */ false);
286   VdexFile::VdexSectionHeader sections[static_cast<uint32_t>(VdexSection::kNumberOfSections)];
287 
288   // Set checksum section.
289   sections[VdexSection::kChecksumSection].section_kind = VdexSection::kChecksumSection;
290   sections[VdexSection::kChecksumSection].section_offset = GetChecksumsOffset();
291   sections[VdexSection::kChecksumSection].section_size =
292       sizeof(VdexFile::VdexChecksum) * dex_files.size();
293 
294   // Set dex section.
295   sections[VdexSection::kDexFileSection].section_kind = VdexSection::kDexFileSection;
296   sections[VdexSection::kDexFileSection].section_offset = 0u;
297   sections[VdexSection::kDexFileSection].section_size = 0u;
298 
299   // Set VerifierDeps section.
300   sections[VdexSection::kVerifierDepsSection].section_kind = VdexSection::kVerifierDepsSection;
301   sections[VdexSection::kVerifierDepsSection].section_offset =
302       GetChecksumsOffset() + sections[kChecksumSection].section_size;
303   sections[VdexSection::kVerifierDepsSection].section_size = verifier_deps_size;
304 
305   // Set TypeLookupTable section.
306   sections[VdexSection::kTypeLookupTableSection].section_kind =
307       VdexSection::kTypeLookupTableSection;
308   sections[VdexSection::kTypeLookupTableSection].section_offset =
309       sections[VdexSection::kVerifierDepsSection].section_offset + verifier_deps_with_padding_size;
310   sections[VdexSection::kTypeLookupTableSection].section_size = type_lookup_table_size;
311 
312   if (!CreateDirectories(path, error_msg)) {
313     return false;
314   }
315 
316   std::unique_ptr<File> out(OS::CreateEmptyFileWriteOnly(path.c_str()));
317   if (out == nullptr) {
318     *error_msg = "Could not open " + path + " for writing";
319     return false;
320   }
321 
322   // Write header.
323   if (!out->WriteFully(reinterpret_cast<const char*>(&vdex_header), sizeof(vdex_header))) {
324     *error_msg = "Could not write vdex header to " + path;
325     out->Unlink();
326     return false;
327   }
328 
329   // Write section infos.
330   if (!out->WriteFully(reinterpret_cast<const char*>(&sections), sizeof(sections))) {
331     *error_msg = "Could not write vdex sections to " + path;
332     out->Unlink();
333     return false;
334   }
335 
336   // Write checksum section.
337   for (const DexFile* dex_file : dex_files) {
338     uint32_t checksum = dex_file->GetLocationChecksum();
339     const uint32_t* checksum_ptr = &checksum;
340     static_assert(sizeof(*checksum_ptr) == sizeof(VdexFile::VdexChecksum));
341     if (!out->WriteFully(reinterpret_cast<const char*>(checksum_ptr),
342                          sizeof(VdexFile::VdexChecksum))) {
343       *error_msg = "Could not write dex checksums to " + path;
344       out->Unlink();
345       return false;
346     }
347   }
348 
349   if (!out->WriteFully(reinterpret_cast<const char*>(verifier_deps_data.data()),
350                        verifier_deps_with_padding_size)) {
351     *error_msg = "Could not write verifier deps to " + path;
352     out->Unlink();
353     return false;
354   }
355 
356   size_t written_type_lookup_table_size = 0;
357   for (const DexFile* dex_file : dex_files) {
358     TypeLookupTable type_lookup_table = TypeLookupTable::Create(*dex_file);
359     uint32_t size = type_lookup_table.RawDataLength();
360     DCHECK_ALIGNED(size, 4);
361     if (!out->WriteFully(reinterpret_cast<const char*>(&size), sizeof(uint32_t)) ||
362         !out->WriteFully(reinterpret_cast<const char*>(type_lookup_table.RawData()), size)) {
363       *error_msg = "Could not write type lookup table " + path;
364       out->Unlink();
365       return false;
366     }
367     written_type_lookup_table_size += sizeof(uint32_t) + size;
368   }
369   DCHECK_EQ(written_type_lookup_table_size, type_lookup_table_size);
370 
371   if (out->FlushClose() != 0) {
372     *error_msg = "Could not flush and close " + path;
373     out->Unlink();
374     return false;
375   }
376 
377   return true;
378 }
379 
MatchesDexFileChecksums(const std::vector<const DexFile::Header * > & dex_headers) const380 bool VdexFile::MatchesDexFileChecksums(const std::vector<const DexFile::Header*>& dex_headers)
381     const {
382   if (dex_headers.size() != GetNumberOfDexFiles()) {
383     LOG(WARNING) << "Mismatch of number of dex files in vdex (expected="
384         << GetNumberOfDexFiles() << ", actual=" << dex_headers.size() << ")";
385     return false;
386   }
387   const VdexChecksum* checksums = GetDexChecksumsArray();
388   for (size_t i = 0; i < dex_headers.size(); ++i) {
389     if (checksums[i] != dex_headers[i]->checksum_) {
390       LOG(WARNING) << "Mismatch of dex file checksum in vdex (index=" << i << ")";
391       return false;
392     }
393   }
394   return true;
395 }
396 
FindClassAndClearException(ClassLinker * class_linker,Thread * self,const char * name,Handle<mirror::ClassLoader> class_loader)397 static ObjPtr<mirror::Class> FindClassAndClearException(ClassLinker* class_linker,
398                                                         Thread* self,
399                                                         const char* name,
400                                                         Handle<mirror::ClassLoader> class_loader)
401     REQUIRES_SHARED(Locks::mutator_lock_) {
402   ObjPtr<mirror::Class> result = class_linker->FindClass(self, name, class_loader);
403   if (result == nullptr) {
404     DCHECK(self->IsExceptionPending());
405     self->ClearException();
406   }
407   return result;
408 }
409 
GetStringFromId(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)410 static const char* GetStringFromId(const DexFile& dex_file,
411                                    dex::StringIndex string_id,
412                                    uint32_t number_of_extra_strings,
413                                    const uint32_t* extra_strings_offsets,
414                                    const uint8_t* verifier_deps) {
415   uint32_t num_ids_in_dex = dex_file.NumStringIds();
416   if (string_id.index_ < num_ids_in_dex) {
417     return dex_file.StringDataByIdx(string_id);
418   } else {
419     CHECK_LT(string_id.index_ - num_ids_in_dex, number_of_extra_strings);
420     uint32_t offset = extra_strings_offsets[string_id.index_ - num_ids_in_dex];
421     return reinterpret_cast<const char*>(verifier_deps) + offset;
422   }
423 }
424 
425 // Returns an array of offsets where the assignability checks for each class
426 // definition are stored.
GetDexFileClassDefs(const uint8_t * verifier_deps,uint32_t index)427 static const uint32_t* GetDexFileClassDefs(const uint8_t* verifier_deps, uint32_t index) {
428   uint32_t dex_file_offset = reinterpret_cast<const uint32_t*>(verifier_deps)[index];
429   return reinterpret_cast<const uint32_t*>(verifier_deps + dex_file_offset);
430 }
431 
432 // 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)433 static const uint32_t* GetExtraStringsOffsets(const DexFile& dex_file,
434                                               const uint8_t* verifier_deps,
435                                               const uint32_t* dex_file_class_defs,
436                                               /*out*/ uint32_t* number_of_extra_strings) {
437   // The information for strings is right after dex_file_class_defs, 4-byte
438   // aligned
439   uint32_t end_of_assignability_types = dex_file_class_defs[dex_file.NumClassDefs()];
440   const uint8_t* strings_data_start =
441       AlignUp(verifier_deps + end_of_assignability_types, sizeof(uint32_t));
442   // First entry is the number of extra strings for this dex file.
443   *number_of_extra_strings = *reinterpret_cast<const uint32_t*>(strings_data_start);
444   // Then an array of offsets in `verifier_deps` for the extra strings.
445   return reinterpret_cast<const uint32_t*>(strings_data_start + sizeof(uint32_t));
446 }
447 
ComputeClassStatus(Thread * self,Handle<mirror::Class> cls) const448 ClassStatus VdexFile::ComputeClassStatus(Thread* self, Handle<mirror::Class> cls) const {
449   const DexFile& dex_file = cls->GetDexFile();
450   uint16_t class_def_index = cls->GetDexClassDefIndex();
451 
452   // Find which dex file index from within the vdex file.
453   uint32_t index = 0;
454   for (; index < GetNumberOfDexFiles(); ++index) {
455     if (dex_file.GetLocationChecksum() == GetLocationChecksum(index)) {
456       break;
457     }
458   }
459 
460   DCHECK_NE(index, GetNumberOfDexFiles());
461 
462   const uint8_t* verifier_deps = GetVerifierDepsData().data();
463   const uint32_t* dex_file_class_defs = GetDexFileClassDefs(verifier_deps, index);
464 
465   // Fetch type checks offsets.
466   uint32_t class_def_offset = dex_file_class_defs[class_def_index];
467   if (class_def_offset == verifier::VerifierDeps::kNotVerifiedMarker) {
468     // Return a status that needs re-verification.
469     return ClassStatus::kResolved;
470   }
471   // End offset for this class's type checks. We know there is one and the loop
472   // will terminate.
473   uint32_t end_offset = verifier::VerifierDeps::kNotVerifiedMarker;
474   for (uint32_t i = class_def_index + 1; i < dex_file.NumClassDefs() + 1; ++i) {
475     end_offset = dex_file_class_defs[i];
476     if (end_offset != verifier::VerifierDeps::kNotVerifiedMarker) {
477       break;
478     }
479   }
480   DCHECK_NE(end_offset, verifier::VerifierDeps::kNotVerifiedMarker);
481 
482   uint32_t number_of_extra_strings = 0;
483   // Offset where extra strings are stored.
484   const uint32_t* extra_strings_offsets = GetExtraStringsOffsets(dex_file,
485                                                                  verifier_deps,
486                                                                  dex_file_class_defs,
487                                                                  &number_of_extra_strings);
488 
489   // Loop over and perform each assignability check.
490   StackHandleScope<3> hs(self);
491   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
492   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(cls->GetClassLoader()));
493   MutableHandle<mirror::Class> source(hs.NewHandle<mirror::Class>(nullptr));
494   MutableHandle<mirror::Class> destination(hs.NewHandle<mirror::Class>(nullptr));
495 
496   const uint8_t* cursor = verifier_deps + class_def_offset;
497   const uint8_t* end = verifier_deps + end_offset;
498   while (cursor < end) {
499     uint32_t destination_index;
500     uint32_t source_index;
501     if (UNLIKELY(!DecodeUnsignedLeb128Checked(&cursor, end, &destination_index) ||
502                  !DecodeUnsignedLeb128Checked(&cursor, end, &source_index))) {
503       // Error parsing the data, just return that we are not verified.
504       return ClassStatus::kResolved;
505     }
506     const char* destination_desc = GetStringFromId(dex_file,
507                                                    dex::StringIndex(destination_index),
508                                                    number_of_extra_strings,
509                                                    extra_strings_offsets,
510                                                    verifier_deps);
511     destination.Assign(
512         FindClassAndClearException(class_linker, self, destination_desc, class_loader));
513 
514     const char* source_desc = GetStringFromId(dex_file,
515                                               dex::StringIndex(source_index),
516                                               number_of_extra_strings,
517                                               extra_strings_offsets,
518                                               verifier_deps);
519     source.Assign(FindClassAndClearException(class_linker, self, source_desc, class_loader));
520 
521     if (destination == nullptr || source == nullptr) {
522       // The interpreter / compiler can handle a missing class.
523       continue;
524     }
525 
526     DCHECK(destination->IsResolved() && source->IsResolved());
527     if (!destination->IsAssignableFrom(source.Get())) {
528       VLOG(verifier) << "Vdex checking failed for " << cls->PrettyClass()
529                      << ": expected " << destination->PrettyClass()
530                      << " to be assignable from " << source->PrettyClass();
531       // An implicit assignability check is failing in the code, return that the
532       // class is not verified.
533       return ClassStatus::kResolved;
534     }
535   }
536 
537   return ClassStatus::kVerifiedNeedsAccessChecks;
538 }
539 
540 }  // namespace art
541