xref: /aosp_15_r20/art/runtime/verifier/verifier_deps.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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 "verifier_deps.h"
18 
19 #include <cstring>
20 #include <sstream>
21 
22 #include "art_field-inl.h"
23 #include "art_method-inl.h"
24 #include "base/indenter.h"
25 #include "base/leb128.h"
26 #include "base/mutex-inl.h"
27 #include "compiler_callbacks.h"
28 #include "dex/class_accessor-inl.h"
29 #include "dex/dex_file-inl.h"
30 #include "mirror/class-inl.h"
31 #include "mirror/class_loader.h"
32 #include "oat/oat_file.h"
33 #include "obj_ptr-inl.h"
34 #include "reg_type.h"
35 #include "reg_type_cache-inl.h"
36 #include "runtime.h"
37 
38 namespace art HIDDEN {
39 namespace verifier {
40 
VerifierDeps(const std::vector<const DexFile * > & dex_files,bool output_only)41 VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files, bool output_only)
42     : output_only_(output_only) {
43   for (const DexFile* dex_file : dex_files) {
44     DCHECK(GetDexFileDeps(*dex_file) == nullptr);
45     std::unique_ptr<DexFileDeps> deps(new DexFileDeps(dex_file->NumClassDefs()));
46     dex_deps_.emplace(dex_file, std::move(deps));
47   }
48 }
49 
50 // Perform logical OR on two bit vectors and assign back to LHS, i.e. `to_update |= other`.
51 // Size of the two vectors must be equal.
52 // Size of `other` must be equal to size of `to_update`.
BitVectorOr(std::vector<bool> & to_update,const std::vector<bool> & other)53 static inline void BitVectorOr(std::vector<bool>& to_update, const std::vector<bool>& other) {
54   DCHECK_EQ(to_update.size(), other.size());
55   std::transform(
56       other.begin(), other.end(), to_update.begin(), to_update.begin(), std::logical_or<bool>());
57 }
58 
MergeWith(std::unique_ptr<VerifierDeps> other,const std::vector<const DexFile * > & dex_files)59 void VerifierDeps::MergeWith(std::unique_ptr<VerifierDeps> other,
60                              const std::vector<const DexFile*>& dex_files) {
61   DCHECK(other != nullptr);
62   DCHECK_EQ(dex_deps_.size(), other->dex_deps_.size());
63   for (const DexFile* dex_file : dex_files) {
64     DexFileDeps* my_deps = GetDexFileDeps(*dex_file);
65     DexFileDeps& other_deps = *other->GetDexFileDeps(*dex_file);
66     // We currently collect extra strings only on the main `VerifierDeps`,
67     // which should be the one passed as `this` in this method.
68     DCHECK(other_deps.strings_.empty());
69     // Size is the number of class definitions in the dex file, and must be the
70     // same between the two `VerifierDeps`.
71     DCHECK_EQ(my_deps->assignable_types_.size(), other_deps.assignable_types_.size());
72     for (uint32_t i = 0; i < my_deps->assignable_types_.size(); ++i) {
73       my_deps->assignable_types_[i].merge(other_deps.assignable_types_[i]);
74     }
75     BitVectorOr(my_deps->verified_classes_, other_deps.verified_classes_);
76   }
77 }
78 
GetDexFileDeps(const DexFile & dex_file)79 VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex_file) {
80   auto it = dex_deps_.find(&dex_file);
81   return (it == dex_deps_.end()) ? nullptr : it->second.get();
82 }
83 
GetDexFileDeps(const DexFile & dex_file) const84 const VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex_file) const {
85   auto it = dex_deps_.find(&dex_file);
86   return (it == dex_deps_.end()) ? nullptr : it->second.get();
87 }
88 
GetClassDescriptorStringId(const DexFile & dex_file,ObjPtr<mirror::Class> klass)89 dex::StringIndex VerifierDeps::GetClassDescriptorStringId(const DexFile& dex_file,
90                                                           ObjPtr<mirror::Class> klass) {
91   DCHECK(klass != nullptr);
92   ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
93   // Array and proxy classes do not have a dex cache.
94   if (!klass->IsArrayClass() && !klass->IsProxyClass()) {
95     DCHECK(dex_cache != nullptr) << klass->PrettyClass();
96     if (dex_cache->GetDexFile() == &dex_file) {
97       // FindStringId is slow, try to go through the class def if we have one.
98       const dex::ClassDef* class_def = klass->GetClassDef();
99       DCHECK(class_def != nullptr) << klass->PrettyClass();
100       const dex::TypeId& type_id = dex_file.GetTypeId(class_def->class_idx_);
101       if (kIsDebugBuild) {
102         std::string temp;
103         CHECK_EQ(GetIdFromString(dex_file, klass->GetDescriptor(&temp)), type_id.descriptor_idx_);
104       }
105       return type_id.descriptor_idx_;
106     }
107   }
108   std::string temp;
109   return GetIdFromString(dex_file, klass->GetDescriptor(&temp));
110 }
111 
GetMainVerifierDeps(VerifierDeps * local_deps)112 static inline VerifierDeps* GetMainVerifierDeps(VerifierDeps* local_deps) {
113   // The main VerifierDeps is the one set in the compiler callbacks, which at the
114   // end of verification will have all the per-thread VerifierDeps merged into it.
115   CompilerCallbacks* callbacks = Runtime::Current()->GetCompilerCallbacks();
116   if (callbacks == nullptr) {
117     DCHECK(!Runtime::Current()->IsAotCompiler());
118     return local_deps;
119   }
120   DCHECK(Runtime::Current()->IsAotCompiler());
121   return callbacks->GetVerifierDeps();
122 }
123 
FindExistingStringId(const std::vector<std::string> & strings,const std::string & str,uint32_t * found_id)124 static bool FindExistingStringId(const std::vector<std::string>& strings,
125                                  const std::string& str,
126                                  uint32_t* found_id) {
127   uint32_t num_extra_ids = strings.size();
128   for (size_t i = 0; i < num_extra_ids; ++i) {
129     if (strings[i] == str) {
130       *found_id = i;
131       return true;
132     }
133   }
134   return false;
135 }
136 
GetIdFromString(const DexFile & dex_file,const std::string & str)137 dex::StringIndex VerifierDeps::GetIdFromString(const DexFile& dex_file, const std::string& str) {
138   const dex::StringId* string_id = dex_file.FindStringId(str.c_str());
139   if (string_id != nullptr) {
140     // String is in the DEX file. Return its ID.
141     return dex_file.GetIndexForStringId(*string_id);
142   }
143 
144   // String is not in the DEX file. Assign a new ID to it which is higher than
145   // the number of strings in the DEX file.
146 
147   // We use the main `VerifierDeps` for adding new strings to simplify
148   // synchronization/merging of these entries between threads.
149   VerifierDeps* singleton = GetMainVerifierDeps(this);
150   DexFileDeps* deps = singleton->GetDexFileDeps(dex_file);
151   DCHECK(deps != nullptr);
152 
153   uint32_t num_ids_in_dex = dex_file.NumStringIds();
154   uint32_t found_id;
155 
156   {
157     ReaderMutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
158     if (FindExistingStringId(deps->strings_, str, &found_id)) {
159       return dex::StringIndex(num_ids_in_dex + found_id);
160     }
161   }
162   {
163     WriterMutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
164     if (FindExistingStringId(deps->strings_, str, &found_id)) {
165       return dex::StringIndex(num_ids_in_dex + found_id);
166     }
167     deps->strings_.push_back(str);
168     dex::StringIndex new_id(num_ids_in_dex + deps->strings_.size() - 1);
169     CHECK_GE(new_id.index_, num_ids_in_dex);  // check for overflows
170     DCHECK_EQ(str, singleton->GetStringFromIndex(dex_file, new_id));
171     return new_id;
172   }
173 }
174 
GetStringFromIndex(const DexFile & dex_file,dex::StringIndex string_idx,size_t * utf8_length) const175 const char* VerifierDeps::GetStringFromIndex(const DexFile& dex_file,
176                                              dex::StringIndex string_idx,
177                                              /*out*/ size_t* utf8_length) const {
178   uint32_t num_ids_in_dex = dex_file.NumStringIds();
179   if (string_idx.index_ < num_ids_in_dex) {
180     uint32_t utf16_length;
181     const char* str = dex_file.GetStringDataAndUtf16Length(string_idx, &utf16_length);
182     if (utf8_length != nullptr) {
183       *utf8_length = DexFile::Utf8Length(str, utf16_length);
184     }
185     return str;
186   } else {
187     const DexFileDeps* deps = GetDexFileDeps(dex_file);
188     DCHECK(deps != nullptr);
189     size_t index = string_idx.index_ - num_ids_in_dex;
190     CHECK_LT(index, deps->strings_.size());
191     const std::string& str = deps->strings_[index];
192     if (utf8_length != nullptr) {
193       *utf8_length = str.length();
194     }
195     return str.c_str();
196   }
197 }
198 
AddAssignability(const DexFile & dex_file,const dex::ClassDef & class_def,ObjPtr<mirror::Class> destination,ObjPtr<mirror::Class> source)199 void VerifierDeps::AddAssignability(const DexFile& dex_file,
200                                     const dex::ClassDef& class_def,
201                                     ObjPtr<mirror::Class> destination,
202                                     ObjPtr<mirror::Class> source) {
203   // Test that the method is only called on reference types.
204   // Note that concurrent verification of `destination` and `source` may have
205   // set their status to erroneous. However, the tests performed below rely
206   // merely on no issues with linking (valid access flags, superclass and
207   // implemented interfaces). If the class at any point reached the IsResolved
208   // status, the requirement holds. This is guaranteed by RegTypeCache::ResolveClass.
209   DCHECK(destination != nullptr);
210   DCHECK(source != nullptr);
211 
212   if (destination->IsPrimitive() || source->IsPrimitive()) {
213     // Primitive types are trivially non-assignable to anything else.
214     // We do not need to record trivial assignability, as it will
215     // not change across releases.
216     return;
217   }
218 
219   if (destination == source || destination->IsObjectClass()) {
220     // Cases when `destination` is trivially assignable from `source`.
221     return;
222   }
223 
224   if (destination->IsArrayClass() && source->IsArrayClass()) {
225     // Both types are arrays. Break down to component types and add recursively.
226     // This helps filter out destinations from compiled DEX files (see below)
227     // and deduplicate entries with the same canonical component type.
228     ObjPtr<mirror::Class> destination_component = destination->GetComponentType();
229     ObjPtr<mirror::Class> source_component = source->GetComponentType();
230 
231     // Only perform the optimization if both types are resolved which guarantees
232     // that they linked successfully, as required at the top of this method.
233     if (destination_component->IsResolved() && source_component->IsResolved()) {
234       AddAssignability(dex_file, class_def, destination_component, source_component);
235       return;
236     }
237   }
238 
239   DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
240   if (dex_deps == nullptr) {
241     // This invocation is from verification of a DEX file which is not being compiled.
242     return;
243   }
244 
245   // Get string IDs for both descriptors and store in the appropriate set.
246   dex::StringIndex destination_id = GetClassDescriptorStringId(dex_file, destination);
247   dex::StringIndex source_id = GetClassDescriptorStringId(dex_file, source);
248 
249   uint16_t index = dex_file.GetIndexForClassDef(class_def);
250   dex_deps->assignable_types_[index].emplace(TypeAssignability(destination_id, source_id));
251 }
252 
AddAssignability(const DexFile & dex_file,const dex::ClassDef & class_def,const RegType & destination,const RegType & source)253 void VerifierDeps::AddAssignability(const DexFile& dex_file,
254                                     const dex::ClassDef& class_def,
255                                     const RegType& destination,
256                                     const RegType& source) {
257   DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
258   if (dex_deps == nullptr) {
259     // This invocation is from verification of a DEX file which is not being compiled.
260     return;
261   }
262 
263   CHECK(destination.IsUnresolvedReference() || destination.HasClass());
264   CHECK(!destination.IsUnresolvedMergedReference());
265 
266   if (source.IsUnresolvedReference() || source.IsJavaLangObject() || source.HasClass()) {
267     DCHECK_IMPLIES(source.IsJavaLangObject(), destination.IsUnresolvedReference());
268     // Get string IDs for both descriptors and store in the appropriate set.
269     dex::StringIndex destination_id =
270         GetIdFromString(dex_file, std::string(destination.GetDescriptor()));
271     dex::StringIndex source_id = GetIdFromString(dex_file, std::string(source.GetDescriptor()));
272     uint16_t index = dex_file.GetIndexForClassDef(class_def);
273     dex_deps->assignable_types_[index].emplace(TypeAssignability(destination_id, source_id));
274   } else if (source.IsZeroOrNull()) {
275     // Nothing to record, null is always assignable.
276   } else {
277     CHECK(source.IsUnresolvedMergedReference()) << source.Dump();
278     const UnresolvedMergedReferenceType& merge =
279         *down_cast<const UnresolvedMergedReferenceType*>(&source);
280     AddAssignability(dex_file, class_def, destination, merge.GetResolvedPart());
281     for (uint32_t idx : merge.GetUnresolvedTypes().Indexes()) {
282       AddAssignability(dex_file, class_def, destination, merge.GetRegTypeCache()->GetFromId(idx));
283     }
284   }
285 }
286 
MaybeRecordVerificationStatus(VerifierDeps * verifier_deps,const DexFile & dex_file,const dex::ClassDef & class_def,FailureKind failure_kind)287 void VerifierDeps::MaybeRecordVerificationStatus(VerifierDeps* verifier_deps,
288                                                  const DexFile& dex_file,
289                                                  const dex::ClassDef& class_def,
290                                                  FailureKind failure_kind) {
291   if (verifier_deps != nullptr) {
292     switch (failure_kind) {
293       case verifier::FailureKind::kHardFailure:
294       case verifier::FailureKind::kSoftFailure: {
295         // Class will be verified at runtime.
296         DexFileDeps* dex_deps = verifier_deps->GetDexFileDeps(dex_file);
297         uint16_t index = dex_file.GetIndexForClassDef(class_def);
298         dex_deps->assignable_types_[index].clear();
299         break;
300       }
301       case verifier::FailureKind::kAccessChecksFailure:
302       case verifier::FailureKind::kTypeChecksFailure:
303       case verifier::FailureKind::kNoFailure: {
304         verifier_deps->RecordClassVerified(dex_file, class_def);
305         break;
306       }
307     }
308   }
309 }
310 
RecordClassVerified(const DexFile & dex_file,const dex::ClassDef & class_def)311 void VerifierDeps::RecordClassVerified(const DexFile& dex_file, const dex::ClassDef& class_def) {
312   DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
313   DCHECK_EQ(dex_deps->verified_classes_.size(), dex_file.NumClassDefs());
314   dex_deps->verified_classes_[dex_file.GetIndexForClassDef(class_def)] = true;
315 }
316 
HasRecordedVerifiedStatus(const DexFile & dex_file,const dex::ClassDef & class_def)317 bool VerifierDeps::HasRecordedVerifiedStatus(const DexFile& dex_file,
318                                              const dex::ClassDef& class_def) {
319   DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
320   DCHECK_EQ(dex_deps->verified_classes_.size(), dex_file.NumClassDefs());
321   return dex_deps->verified_classes_[dex_file.GetIndexForClassDef(class_def)];
322 }
323 
MaybeRecordAssignability(VerifierDeps * verifier_deps,const DexFile & dex_file,const dex::ClassDef & class_def,ObjPtr<mirror::Class> destination,ObjPtr<mirror::Class> source)324 void VerifierDeps::MaybeRecordAssignability(VerifierDeps* verifier_deps,
325                                             const DexFile& dex_file,
326                                             const dex::ClassDef& class_def,
327                                             ObjPtr<mirror::Class> destination,
328                                             ObjPtr<mirror::Class> source) {
329   if (verifier_deps != nullptr) {
330     verifier_deps->AddAssignability(dex_file, class_def, destination, source);
331   }
332 }
333 
MaybeRecordAssignability(VerifierDeps * verifier_deps,const DexFile & dex_file,const dex::ClassDef & class_def,const RegType & destination,const RegType & source)334 void VerifierDeps::MaybeRecordAssignability(VerifierDeps* verifier_deps,
335                                             const DexFile& dex_file,
336                                             const dex::ClassDef& class_def,
337                                             const RegType& destination,
338                                             const RegType& source) {
339   if (verifier_deps != nullptr) {
340     verifier_deps->AddAssignability(dex_file, class_def, destination, source);
341   }
342 }
343 
344 namespace {
345 
346 template <typename T>
347 inline uint32_t Encode(T in);
348 
349 template <>
Encode(dex::StringIndex in)350 inline uint32_t Encode<dex::StringIndex>(dex::StringIndex in) {
351   return in.index_;
352 }
353 
354 template <typename T>
355 inline T Decode(uint32_t in);
356 
357 template <>
Decode(uint32_t in)358 inline dex::StringIndex Decode<dex::StringIndex>(uint32_t in) {
359   return dex::StringIndex(in);
360 }
361 
362 template <typename T1, typename T2>
EncodeTuple(std::vector<uint8_t> * out,const std::tuple<T1,T2> & t)363 static inline void EncodeTuple(std::vector<uint8_t>* out, const std::tuple<T1, T2>& t) {
364   EncodeUnsignedLeb128(out, Encode(std::get<0>(t)));
365   EncodeUnsignedLeb128(out, Encode(std::get<1>(t)));
366 }
367 
368 template <typename T1, typename T2>
DecodeTuple(const uint8_t ** in,const uint8_t * end,std::tuple<T1,T2> * t)369 static inline bool DecodeTuple(const uint8_t** in, const uint8_t* end, std::tuple<T1, T2>* t) {
370   uint32_t v1, v2;
371   if (UNLIKELY(!DecodeUnsignedLeb128Checked(in, end, &v1)) ||
372       UNLIKELY(!DecodeUnsignedLeb128Checked(in, end, &v2))) {
373     return false;
374   }
375   *t = std::make_tuple(Decode<T1>(v1), Decode<T2>(v2));
376   return true;
377 }
378 
379 template <typename T1, typename T2, typename T3>
EncodeTuple(std::vector<uint8_t> * out,const std::tuple<T1,T2,T3> & t)380 static inline void EncodeTuple(std::vector<uint8_t>* out, const std::tuple<T1, T2, T3>& t) {
381   EncodeUnsignedLeb128(out, Encode(std::get<0>(t)));
382   EncodeUnsignedLeb128(out, Encode(std::get<1>(t)));
383   EncodeUnsignedLeb128(out, Encode(std::get<2>(t)));
384 }
385 
386 template <typename T1, typename T2, typename T3>
DecodeTuple(const uint8_t ** in,const uint8_t * end,std::tuple<T1,T2,T3> * t)387 static inline bool DecodeTuple(const uint8_t** in, const uint8_t* end, std::tuple<T1, T2, T3>* t) {
388   uint32_t v1, v2, v3;
389   if (UNLIKELY(!DecodeUnsignedLeb128Checked(in, end, &v1)) ||
390       UNLIKELY(!DecodeUnsignedLeb128Checked(in, end, &v2)) ||
391       UNLIKELY(!DecodeUnsignedLeb128Checked(in, end, &v3))) {
392     return false;
393   }
394   *t = std::make_tuple(Decode<T1>(v1), Decode<T2>(v2), Decode<T3>(v3));
395   return true;
396 }
397 
SetUint32InUint8Array(std::vector<uint8_t> * out,uint32_t uint8_offset,uint32_t uint32_offset,uint32_t value)398 static void SetUint32InUint8Array(std::vector<uint8_t>* out,
399                                   uint32_t uint8_offset,
400                                   uint32_t uint32_offset,
401                                   uint32_t value) {
402   DCHECK(IsAligned<sizeof(uint32_t)>(out->data() + uint8_offset));
403   (reinterpret_cast<uint32_t*>(out->data() + uint8_offset))[uint32_offset] = value;
404 }
405 
406 template <typename T>
EncodeSetVector(std::vector<uint8_t> * out,const std::vector<std::set<T>> & vector,const std::vector<bool> & verified_classes)407 static void EncodeSetVector(std::vector<uint8_t>* out,
408                             const std::vector<std::set<T>>& vector,
409                             const std::vector<bool>& verified_classes) {
410   uint32_t offsets_index = out->size();
411   // Make room for offsets for each class, +1 for marking the end of the
412   // assignability types data.
413   out->resize(out->size() + (vector.size() + 1) * sizeof(uint32_t));
414   uint32_t class_def_index = 0;
415   for (const std::set<T>& set : vector) {
416     if (verified_classes[class_def_index]) {
417       // Store the offset of the set for this class.
418       SetUint32InUint8Array(out, offsets_index, class_def_index, out->size());
419       for (const T& entry : set) {
420         EncodeTuple(out, entry);
421       }
422     } else {
423       SetUint32InUint8Array(out, offsets_index, class_def_index, VerifierDeps::kNotVerifiedMarker);
424     }
425     class_def_index++;
426   }
427   SetUint32InUint8Array(out, offsets_index, class_def_index, out->size());
428 }
429 
430 template <bool kFillSet, typename T>
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)431 static bool DecodeSetVector(const uint8_t** cursor,
432                             const uint8_t* start,
433                             const uint8_t* end,
434                             std::vector<std::set<T>>* vector,
435                             std::vector<bool>* verified_classes,
436                             size_t num_class_defs) {
437   const uint32_t* offsets = reinterpret_cast<const uint32_t*>(*cursor);
438   uint32_t next_valid_offset_index = 1;
439   // Put the cursor after the offsets of each class, +1 for the offset of the
440   // end of the assignable types data.
441   *cursor += (num_class_defs + 1) * sizeof(uint32_t);
442   for (uint32_t i = 0; i < num_class_defs; ++i) {
443     uint32_t offset = offsets[i];
444     if (offset == VerifierDeps::kNotVerifiedMarker) {
445       (*verified_classes)[i] = false;
446       continue;
447     }
448     (*verified_classes)[i] = true;
449     *cursor = start + offset;
450     // Fetch the assignability checks.
451     std::set<T>& set = (*vector)[i];
452     // Find the offset of the next entry. This will tell us where to stop when
453     // reading the checks. Note that the last entry in the `offsets` array points
454     // to the end of the assignability types data, so the loop will terminate correctly.
455     while (next_valid_offset_index <= i ||
456            offsets[next_valid_offset_index] == VerifierDeps::kNotVerifiedMarker) {
457       next_valid_offset_index++;
458     }
459     const uint8_t* set_end = start + offsets[next_valid_offset_index];
460     // Decode each check.
461     while (*cursor < set_end) {
462       T tuple;
463       if (UNLIKELY(!DecodeTuple(cursor, end, &tuple))) {
464         return false;
465       }
466       if (kFillSet) {
467         set.emplace(tuple);
468       }
469     }
470   }
471   // Align the cursor to start decoding the strings.
472   *cursor = AlignUp(*cursor, sizeof(uint32_t));
473   return true;
474 }
475 
EncodeStringVector(std::vector<uint8_t> * out,const std::vector<std::string> & strings)476 static inline void EncodeStringVector(std::vector<uint8_t>* out,
477                                       const std::vector<std::string>& strings) {
478   uint32_t offsets_index = out->size();
479   // Make room for offsets for each string, +1 for putting the number of
480   // strings.
481   out->resize(out->size() + (strings.size() + 1) * sizeof(uint32_t));
482   (reinterpret_cast<uint32_t*>(out->data() + offsets_index))[0] = strings.size();
483   uint32_t string_index = 1;
484   for (const std::string& str : strings) {
485     // Store the offset of the string.
486     (reinterpret_cast<uint32_t*>(out->data() + offsets_index))[string_index++] = out->size();
487 
488     // Store the string data.
489     const uint8_t* data = reinterpret_cast<const uint8_t*>(str.c_str());
490     size_t length = str.length() + 1;
491     out->insert(out->end(), data, data + length);
492     DCHECK_EQ(0u, out->back());
493   }
494 }
495 
496 template <bool kFillVector>
DecodeStringVector(const uint8_t ** cursor,const uint8_t * start,const uint8_t * end,std::vector<std::string> * strings)497 static inline bool DecodeStringVector(const uint8_t** cursor,
498                                       const uint8_t* start,
499                                       const uint8_t* end,
500                                       std::vector<std::string>* strings) {
501   DCHECK(strings->empty());
502   uint32_t num_strings = reinterpret_cast<const uint32_t*>(*cursor)[0];
503   if (kFillVector) {
504     strings->reserve(num_strings);
505   }
506   const uint8_t* offsets = *cursor;
507   *cursor += sizeof(uint32_t) + num_strings * sizeof(uint32_t);
508   for (uint32_t i = 0; i < num_strings; ++i) {
509     uint32_t string_offset = reinterpret_cast<const uint32_t*>(offsets)[i + 1];
510     const char* string_start = reinterpret_cast<const char*>(start + string_offset);
511     const char* string_end =
512         reinterpret_cast<const char*>(memchr(string_start, 0, end - start - string_offset));
513     if (UNLIKELY(string_end == nullptr)) {
514       return false;
515     }
516     size_t string_length = string_end - string_start;
517     if (kFillVector) {
518       strings->emplace_back(string_start, string_length);
519     }
520     *cursor = reinterpret_cast<const uint8_t*>(string_end + 1);
521   }
522   return true;
523 }
524 
525 }  // namespace
526 
Encode(const std::vector<const DexFile * > & dex_files,std::vector<uint8_t> * buffer) const527 void VerifierDeps::Encode(const std::vector<const DexFile*>& dex_files,
528                           std::vector<uint8_t>* buffer) const {
529   DCHECK(buffer->empty());
530   buffer->resize(dex_files.size() * sizeof(uint32_t));
531   uint32_t dex_file_index = 0;
532   for (const DexFile* dex_file : dex_files) {
533     // Four byte alignment before encoding the data.
534     buffer->resize(RoundUp(buffer->size(), sizeof(uint32_t)));
535     (reinterpret_cast<uint32_t*>(buffer->data()))[dex_file_index++] = buffer->size();
536     const DexFileDeps& deps = *GetDexFileDeps(*dex_file);
537     EncodeSetVector(buffer, deps.assignable_types_, deps.verified_classes_);
538     // Four byte alignment before encoding strings.
539     buffer->resize(RoundUp(buffer->size(), sizeof(uint32_t)));
540     EncodeStringVector(buffer, deps.strings_);
541   }
542 }
543 
544 template <bool kOnlyVerifiedClasses>
DecodeDexFileDeps(DexFileDeps & deps,const uint8_t ** cursor,const uint8_t * data_start,const uint8_t * data_end,size_t num_class_defs)545 bool VerifierDeps::DecodeDexFileDeps(DexFileDeps& deps,
546                                      const uint8_t** cursor,
547                                      const uint8_t* data_start,
548                                      const uint8_t* data_end,
549                                      size_t num_class_defs) {
550   return DecodeSetVector</*kFillSet=*/!kOnlyVerifiedClasses>(cursor,
551                                                              data_start,
552                                                              data_end,
553                                                              &deps.assignable_types_,
554                                                              &deps.verified_classes_,
555                                                              num_class_defs) &&
556          DecodeStringVector</*kFillVector=*/!kOnlyVerifiedClasses>(
557              cursor, data_start, data_end, &deps.strings_);
558 }
559 
ParseStoredData(const std::vector<const DexFile * > & dex_files,ArrayRef<const uint8_t> data)560 bool VerifierDeps::ParseStoredData(const std::vector<const DexFile*>& dex_files,
561                                    ArrayRef<const uint8_t> data) {
562   if (data.empty()) {
563     // Return eagerly, as the first thing we expect from VerifierDeps data is
564     // the number of created strings, even if there is no dependency.
565     // Currently, only the boot image does not have any VerifierDeps data.
566     return true;
567   }
568   const uint8_t* data_start = data.data();
569   const uint8_t* data_end = data_start + data.size();
570   const uint8_t* cursor = data_start;
571   uint32_t dex_file_index = 0;
572   for (const DexFile* dex_file : dex_files) {
573     DexFileDeps* deps = GetDexFileDeps(*dex_file);
574     // Fetch the offset of this dex file's verifier data.
575     cursor = data_start + reinterpret_cast<const uint32_t*>(data_start)[dex_file_index++];
576     size_t num_class_defs = dex_file->NumClassDefs();
577     if (UNLIKELY(!DecodeDexFileDeps</*kOnlyVerifiedClasses=*/false>(
578             *deps, &cursor, data_start, data_end, num_class_defs))) {
579       LOG(ERROR) << "Failed to parse dex file dependencies for " << dex_file->GetLocation();
580       return false;
581     }
582   }
583   // TODO: We should check that `data_start == data_end`. Why are we passing excessive data?
584   return true;
585 }
586 
ParseVerifiedClasses(const std::vector<const DexFile * > & dex_files,ArrayRef<const uint8_t> data,std::vector<std::vector<bool>> * verified_classes_per_dex)587 bool VerifierDeps::ParseVerifiedClasses(
588     const std::vector<const DexFile*>& dex_files,
589     ArrayRef<const uint8_t> data,
590     /*out*/ std::vector<std::vector<bool>>* verified_classes_per_dex) {
591   DCHECK(!data.empty());
592   DCHECK(!dex_files.empty());
593   DCHECK(verified_classes_per_dex->empty());
594 
595   verified_classes_per_dex->reserve(dex_files.size());
596 
597   const uint8_t* data_start = data.data();
598   const uint8_t* data_end = data_start + data.size();
599   const uint8_t* cursor = data_start;
600   uint32_t dex_file_index = 0;
601   for (const DexFile* dex_file : dex_files) {
602     DexFileDeps deps(/*num_class_defs=*/0u);  // Do not initialize vectors.
603     // Fetch the offset of this dex file's verifier data.
604     cursor = data_start + reinterpret_cast<const uint32_t*>(data_start)[dex_file_index++];
605     size_t num_class_defs = dex_file->NumClassDefs();
606     deps.verified_classes_.resize(num_class_defs);
607     if (UNLIKELY(!DecodeDexFileDeps</*kOnlyVerifiedClasses=*/true>(
608             deps, &cursor, data_start, data_end, num_class_defs))) {
609       LOG(ERROR) << "Failed to parse dex file dependencies for " << dex_file->GetLocation();
610       return false;
611     }
612     verified_classes_per_dex->push_back(std::move(deps.verified_classes_));
613   }
614   // TODO: We should check that `data_start == data_end`. Why are we passing excessive data?
615   return true;
616 }
617 
Equals(const VerifierDeps & rhs) const618 bool VerifierDeps::Equals(const VerifierDeps& rhs) const {
619   if (dex_deps_.size() != rhs.dex_deps_.size()) {
620     return false;
621   }
622 
623   auto lhs_it = dex_deps_.begin();
624   auto rhs_it = rhs.dex_deps_.begin();
625 
626   for (; (lhs_it != dex_deps_.end()) && (rhs_it != rhs.dex_deps_.end()); lhs_it++, rhs_it++) {
627     const DexFile* lhs_dex_file = lhs_it->first;
628     const DexFile* rhs_dex_file = rhs_it->first;
629     if (lhs_dex_file != rhs_dex_file) {
630       return false;
631     }
632 
633     DexFileDeps* lhs_deps = lhs_it->second.get();
634     DexFileDeps* rhs_deps = rhs_it->second.get();
635     if (!lhs_deps->Equals(*rhs_deps)) {
636       return false;
637     }
638   }
639 
640   DCHECK((lhs_it == dex_deps_.end()) && (rhs_it == rhs.dex_deps_.end()));
641   return true;
642 }
643 
Equals(const VerifierDeps::DexFileDeps & rhs) const644 bool VerifierDeps::DexFileDeps::Equals(const VerifierDeps::DexFileDeps& rhs) const {
645   return (strings_ == rhs.strings_) && (assignable_types_ == rhs.assignable_types_) &&
646          (verified_classes_ == rhs.verified_classes_);
647 }
648 
Dump(VariableIndentationOutputStream * vios) const649 void VerifierDeps::Dump(VariableIndentationOutputStream* vios) const {
650   // Sort dex files by their location to ensure deterministic ordering.
651   using DepsEntry = std::pair<const DexFile*, const DexFileDeps*>;
652   std::vector<DepsEntry> dex_deps;
653   dex_deps.reserve(dex_deps_.size());
654   for (const auto& dep : dex_deps_) {
655     dex_deps.emplace_back(dep.first, dep.second.get());
656   }
657   std::sort(dex_deps.begin(), dex_deps.end(), [](const DepsEntry& lhs, const DepsEntry& rhs) {
658     return lhs.first->GetLocation() < rhs.first->GetLocation();
659   });
660   for (const auto& dep : dex_deps) {
661     const DexFile& dex_file = *dep.first;
662     vios->Stream() << "Dependencies of " << dex_file.GetLocation() << ":\n";
663 
664     ScopedIndentation indent(vios);
665 
666     for (const std::string& str : dep.second->strings_) {
667       vios->Stream() << "Extra string: " << str << "\n";
668     }
669 
670     for (size_t idx = 0; idx < dep.second->assignable_types_.size(); idx++) {
671       vios->Stream() << "Dependencies of " << dex_file.GetClassDescriptor(dex_file.GetClassDef(idx))
672                      << ":\n";
673       for (const TypeAssignability& entry : dep.second->assignable_types_[idx]) {
674         vios->Stream() << GetStringFromIndex(dex_file, entry.GetSource())
675                        << " must be assignable to "
676                        << GetStringFromIndex(dex_file, entry.GetDestination()) << "\n";
677       }
678     }
679 
680     for (size_t idx = 0; idx < dep.second->verified_classes_.size(); idx++) {
681       if (!dep.second->verified_classes_[idx]) {
682         vios->Stream() << dex_file.GetClassDescriptor(dex_file.GetClassDef(idx))
683                        << " will be verified at runtime\n";
684       }
685     }
686   }
687 }
688 
ValidateDependenciesAndUpdateStatus(Thread * self,Handle<mirror::ClassLoader> class_loader,const std::vector<const DexFile * > & dex_files)689 bool VerifierDeps::ValidateDependenciesAndUpdateStatus(
690     Thread* self,
691     Handle<mirror::ClassLoader> class_loader,
692     const std::vector<const DexFile*>& dex_files) {
693   bool all_validated = true;
694   for (const auto* dex_file : dex_files) {
695     DexFileDeps* my_deps = GetDexFileDeps(*dex_file);
696     if (!VerifyDexFileAndUpdateStatus(class_loader, *dex_file, *my_deps, self)) {
697       all_validated = false;
698     }
699   }
700   return all_validated;
701 }
702 
703 // TODO: share that helper with other parts of the compiler that have
704 // the same lookup pattern.
FindClassAndClearException(ClassLinker * class_linker,Thread * self,const char * descriptor,size_t descriptor_length,Handle<mirror::ClassLoader> class_loader)705 static ObjPtr<mirror::Class> FindClassAndClearException(ClassLinker* class_linker,
706                                                         Thread* self,
707                                                         const char* descriptor,
708                                                         size_t descriptor_length,
709                                                         Handle<mirror::ClassLoader> class_loader)
710     REQUIRES_SHARED(Locks::mutator_lock_) {
711   ObjPtr<mirror::Class> result =
712       class_linker->FindClass(self, descriptor, descriptor_length, class_loader);
713   if (result == nullptr) {
714     DCHECK(self->IsExceptionPending());
715     self->ClearException();
716   }
717   return result;
718 }
719 
VerifyDexFileAndUpdateStatus(Handle<mirror::ClassLoader> class_loader,const DexFile & dex_file,DexFileDeps & deps,Thread * self)720 bool VerifierDeps::VerifyDexFileAndUpdateStatus(
721     Handle<mirror::ClassLoader> class_loader,
722     const DexFile& dex_file,
723     DexFileDeps& deps,
724     Thread* self) {
725   StackHandleScope<2> hs(self);
726   const std::vector<std::set<TypeAssignability>>& assignables = deps.assignable_types_;
727   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
728   MutableHandle<mirror::Class> source(hs.NewHandle<mirror::Class>(nullptr));
729   MutableHandle<mirror::Class> destination(hs.NewHandle<mirror::Class>(nullptr));
730 
731   uint32_t class_def_index = 0u;
732   bool all_validated = true;
733   uint32_t number_of_warnings = 0;
734   static constexpr uint32_t kMaxWarnings = 5;
735   for (const auto& vec : assignables) {
736     for (const auto& entry : vec) {
737       size_t destination_desc_length;
738       const char* destination_desc =
739           GetStringFromIndex(dex_file, entry.GetDestination(), &destination_desc_length);
740       destination.Assign(FindClassAndClearException(
741           class_linker, self, destination_desc, destination_desc_length, class_loader));
742       size_t source_desc_length;
743       const char* source_desc =
744           GetStringFromIndex(dex_file, entry.GetSource(), &source_desc_length);
745       source.Assign(FindClassAndClearException(
746           class_linker, self, source_desc, source_desc_length, class_loader));
747 
748       if (destination == nullptr || source == nullptr) {
749         // We currently don't use assignability information for unresolved
750         // types, as the status of the class using unresolved types will be soft
751         // fail in the vdex.
752         continue;
753       }
754 
755       DCHECK(destination->IsResolved() && source->IsResolved());
756       if (!destination->IsAssignableFrom(source.Get())) {
757         deps.verified_classes_[class_def_index] = false;
758         all_validated = false;
759         if (number_of_warnings++ < kMaxWarnings) {
760           LOG(WARNING) << "Class "
761                        << dex_file.PrettyType(dex_file.GetClassDef(class_def_index).class_idx_)
762                        << " could not be fast verified because one of its methods wrongly expected "
763                        << destination_desc << " to be assignable from " << source_desc;
764         }
765         break;
766       }
767     }
768     class_def_index++;
769   }
770   return all_validated;
771 }
772 
773 }  // namespace verifier
774 }  // namespace art
775