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