1 /*
2  * Copyright (C) 2017 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  * Implementation file of dex ir verifier.
17  *
18  * Compares two dex files at the IR level, allowing differences in layout, but not in data.
19  */
20 
21 #include "dex_verify.h"
22 
23 #include <inttypes.h>
24 
25 #include <set>
26 
27 #include "android-base/stringprintf.h"
28 
29 namespace art {
30 
31 using android::base::StringPrintf;
32 
VerifyOutputDexFile(dex_ir::Header * orig_header,dex_ir::Header * output_header,std::string * error_msg)33 bool VerifyOutputDexFile(dex_ir::Header* orig_header,
34                          dex_ir::Header* output_header,
35                          std::string* error_msg) {
36   // Compare all id sections. They have a defined order that can't be changed by dexlayout.
37   if (!VerifyIds(orig_header->StringIds(), output_header->StringIds(), "string ids", error_msg) ||
38       !VerifyIds(orig_header->TypeIds(), output_header->TypeIds(), "type ids", error_msg) ||
39       !VerifyIds(orig_header->ProtoIds(), output_header->ProtoIds(), "proto ids", error_msg) ||
40       !VerifyIds(orig_header->FieldIds(), output_header->FieldIds(), "field ids", error_msg) ||
41       !VerifyIds(orig_header->MethodIds(), output_header->MethodIds(), "method ids", error_msg)) {
42     return false;
43   }
44   // Compare class defs. The order may have been changed by dexlayout.
45   if (!VerifyClassDefs(orig_header->ClassDefs(), output_header->ClassDefs(), error_msg)) {
46     return false;
47   }
48   return true;
49 }
50 
VerifyIds(dex_ir::CollectionVector<T> & orig,dex_ir::CollectionVector<T> & output,const char * section_name,std::string * error_msg)51 template<class T> bool VerifyIds(dex_ir::CollectionVector<T>& orig,
52                                  dex_ir::CollectionVector<T>& output,
53                                  const char* section_name,
54                                  std::string* error_msg) {
55   auto orig_iter = orig.begin();
56   auto output_iter = output.begin();
57   for (; orig_iter != orig.end() && output_iter != output.end(); ++orig_iter, ++output_iter) {
58     if (!VerifyId(orig_iter->get(), output_iter->get(), error_msg)) {
59       return false;
60     }
61   }
62   if (orig_iter != orig.end() || output_iter != output.end()) {
63     const char* longer;
64     if (orig_iter == orig.end()) {
65       longer = "output";
66     } else {
67       longer = "original";
68     }
69     *error_msg = StringPrintf("Mismatch for %s section: %s is longer.", section_name, longer);
70     return false;
71   }
72   return true;
73 }
74 
VerifyId(dex_ir::StringId * orig,dex_ir::StringId * output,std::string * error_msg)75 bool VerifyId(dex_ir::StringId* orig, dex_ir::StringId* output, std::string* error_msg) {
76   if (strcmp(orig->Data(), output->Data()) != 0) {
77     *error_msg = StringPrintf("Mismatched string data for string id %u at offset %x: %s vs %s.",
78                               orig->GetIndex(),
79                               orig->GetOffset(),
80                               orig->Data(),
81                               output->Data());
82     return false;
83   }
84   return true;
85 }
86 
VerifyId(dex_ir::TypeId * orig,dex_ir::TypeId * output,std::string * error_msg)87 bool VerifyId(dex_ir::TypeId* orig, dex_ir::TypeId* output, std::string* error_msg) {
88   if (orig->GetStringId()->GetIndex() != output->GetStringId()->GetIndex()) {
89     *error_msg = StringPrintf("Mismatched string index for type id %u at offset %x: %u vs %u.",
90                               orig->GetIndex(),
91                               orig->GetOffset(),
92                               orig->GetStringId()->GetIndex(),
93                               output->GetStringId()->GetIndex());
94     return false;
95   }
96   return true;
97 }
98 
VerifyId(dex_ir::ProtoId * orig,dex_ir::ProtoId * output,std::string * error_msg)99 bool VerifyId(dex_ir::ProtoId* orig, dex_ir::ProtoId* output, std::string* error_msg) {
100   if (orig->Shorty()->GetIndex() != output->Shorty()->GetIndex()) {
101     *error_msg = StringPrintf("Mismatched string index for proto id %u at offset %x: %u vs %u.",
102                               orig->GetIndex(),
103                               orig->GetOffset(),
104                               orig->Shorty()->GetIndex(),
105                               output->Shorty()->GetIndex());
106     return false;
107   }
108   if (orig->ReturnType()->GetIndex() != output->ReturnType()->GetIndex()) {
109     *error_msg = StringPrintf("Mismatched type index for proto id %u at offset %x: %u vs %u.",
110                               orig->GetIndex(),
111                               orig->GetOffset(),
112                               orig->ReturnType()->GetIndex(),
113                               output->ReturnType()->GetIndex());
114     return false;
115   }
116   if (!VerifyTypeList(orig->Parameters(), output->Parameters())) {
117     *error_msg = StringPrintf("Mismatched type list for proto id %u at offset %x.",
118                               orig->GetIndex(),
119                               orig->GetOffset());
120   }
121   return true;
122 }
123 
VerifyId(dex_ir::FieldId * orig,dex_ir::FieldId * output,std::string * error_msg)124 bool VerifyId(dex_ir::FieldId* orig, dex_ir::FieldId* output, std::string* error_msg) {
125   if (orig->Class()->GetIndex() != output->Class()->GetIndex()) {
126     *error_msg =
127         StringPrintf("Mismatched class type index for field id %u at offset %x: %u vs %u.",
128                      orig->GetIndex(),
129                      orig->GetOffset(),
130                      orig->Class()->GetIndex(),
131                      output->Class()->GetIndex());
132     return false;
133   }
134   if (orig->Type()->GetIndex() != output->Type()->GetIndex()) {
135     *error_msg = StringPrintf("Mismatched type index for field id %u at offset %x: %u vs %u.",
136                               orig->GetIndex(),
137                               orig->GetOffset(),
138                               orig->Class()->GetIndex(),
139                               output->Class()->GetIndex());
140     return false;
141   }
142   if (orig->Name()->GetIndex() != output->Name()->GetIndex()) {
143     *error_msg = StringPrintf("Mismatched string index for field id %u at offset %x: %u vs %u.",
144                               orig->GetIndex(),
145                               orig->GetOffset(),
146                               orig->Name()->GetIndex(),
147                               output->Name()->GetIndex());
148     return false;
149   }
150   return true;
151 }
152 
VerifyId(dex_ir::MethodId * orig,dex_ir::MethodId * output,std::string * error_msg)153 bool VerifyId(dex_ir::MethodId* orig, dex_ir::MethodId* output, std::string* error_msg) {
154   if (orig->Class()->GetIndex() != output->Class()->GetIndex()) {
155     *error_msg = StringPrintf("Mismatched type index for method id %u at offset %x: %u vs %u.",
156                               orig->GetIndex(),
157                               orig->GetOffset(),
158                               orig->Class()->GetIndex(),
159                               output->Class()->GetIndex());
160     return false;
161   }
162   if (orig->Proto()->GetIndex() != output->Proto()->GetIndex()) {
163     *error_msg = StringPrintf("Mismatched proto index for method id %u at offset %x: %u vs %u.",
164                               orig->GetIndex(),
165                               orig->GetOffset(),
166                               orig->Class()->GetIndex(),
167                               output->Class()->GetIndex());
168     return false;
169   }
170   if (orig->Name()->GetIndex() != output->Name()->GetIndex()) {
171     *error_msg =
172         StringPrintf("Mismatched string index for method id %u at offset %x: %u vs %u.",
173                      orig->GetIndex(),
174                      orig->GetOffset(),
175                      orig->Name()->GetIndex(),
176                      output->Name()->GetIndex());
177     return false;
178   }
179   return true;
180 }
181 
182 struct ClassDefCompare {
operator ()art::ClassDefCompare183   bool operator()(dex_ir::ClassDef* lhs, dex_ir::ClassDef* rhs) const {
184     return lhs->ClassType()->GetIndex() < rhs->ClassType()->GetIndex();
185   }
186 };
187 
188 // The class defs may have a new order due to dexlayout. Use the class's class_idx to uniquely
189 // identify them and sort them for comparison.
VerifyClassDefs(dex_ir::CollectionVector<dex_ir::ClassDef> & orig,dex_ir::CollectionVector<dex_ir::ClassDef> & output,std::string * error_msg)190 bool VerifyClassDefs(dex_ir::CollectionVector<dex_ir::ClassDef>& orig,
191                      dex_ir::CollectionVector<dex_ir::ClassDef>& output,
192                      std::string* error_msg) {
193   // Store the class defs into sets sorted by the class's type index.
194   std::set<dex_ir::ClassDef*, ClassDefCompare> orig_set;
195   std::set<dex_ir::ClassDef*, ClassDefCompare> output_set;
196   auto orig_iter = orig.begin();
197   auto output_iter = output.begin();
198   for (; orig_iter != orig.end() && output_iter != output.end(); ++orig_iter, ++output_iter) {
199     orig_set.insert(orig_iter->get());
200     output_set.insert(output_iter->get());
201   }
202   if (orig_iter != orig.end() || output_iter != output.end()) {
203     const char* longer;
204     if (orig_iter == orig.end()) {
205       longer = "output";
206     } else {
207       longer = "original";
208     }
209     *error_msg = StringPrintf("Mismatch for class defs section: %s is longer.", longer);
210     return false;
211   }
212   auto orig_set_iter = orig_set.begin();
213   auto output_set_iter = output_set.begin();
214   while (orig_set_iter != orig_set.end() && output_set_iter != output_set.end()) {
215     if (!VerifyClassDef(*orig_set_iter, *output_set_iter, error_msg)) {
216       return false;
217     }
218     orig_set_iter++;
219     output_set_iter++;
220   }
221   return true;
222 }
223 
VerifyClassDef(dex_ir::ClassDef * orig,dex_ir::ClassDef * output,std::string * error_msg)224 bool VerifyClassDef(dex_ir::ClassDef* orig, dex_ir::ClassDef* output, std::string* error_msg) {
225   if (orig->ClassType()->GetIndex() != output->ClassType()->GetIndex()) {
226     *error_msg =
227         StringPrintf("Mismatched class type index for class def %u at offset %x: %u vs %u.",
228                      orig->GetIndex(),
229                      orig->GetOffset(),
230                      orig->ClassType()->GetIndex(),
231                      output->ClassType()->GetIndex());
232     return false;
233   }
234   if (orig->GetAccessFlags() != output->GetAccessFlags()) {
235     *error_msg =
236         StringPrintf("Mismatched access flags for class def %u at offset %x: %x vs %x.",
237                      orig->GetIndex(),
238                      orig->GetOffset(),
239                      orig->GetAccessFlags(),
240                      output->GetAccessFlags());
241     return false;
242   }
243   uint32_t orig_super = orig->Superclass() == nullptr ? 0 : orig->Superclass()->GetIndex();
244   uint32_t output_super = output->Superclass() == nullptr ? 0 : output->Superclass()->GetIndex();
245   if (orig_super != output_super) {
246     *error_msg =
247         StringPrintf("Mismatched super class for class def %u at offset %x: %u vs %u.",
248                      orig->GetIndex(),
249                      orig->GetOffset(),
250                      orig_super,
251                      output_super);
252     return false;
253   }
254   if (!VerifyTypeList(orig->Interfaces(), output->Interfaces())) {
255     *error_msg = StringPrintf("Mismatched type list for class def %u at offset %x.",
256                               orig->GetIndex(),
257                               orig->GetOffset());
258     return false;
259   }
260   const char* orig_source = orig->SourceFile() == nullptr ? "" : orig->SourceFile()->Data();
261   const char* output_source = output->SourceFile() == nullptr ? "" : output->SourceFile()->Data();
262   if (strcmp(orig_source, output_source) != 0) {
263     *error_msg = StringPrintf("Mismatched source file for class def %u at offset %x: %s vs %s.",
264                               orig->GetIndex(),
265                               orig->GetOffset(),
266                               orig_source,
267                               output_source);
268     return false;
269   }
270   if (!VerifyAnnotationsDirectory(orig->Annotations(), output->Annotations(), error_msg)) {
271     return false;
272   }
273   if (!VerifyClassData(orig->GetClassData(), output->GetClassData(), error_msg)) {
274     return false;
275   }
276   return VerifyEncodedArray(orig->StaticValues(), output->StaticValues(), error_msg);
277 }
278 
VerifyTypeList(const dex_ir::TypeList * orig,const dex_ir::TypeList * output)279 bool VerifyTypeList(const dex_ir::TypeList* orig, const dex_ir::TypeList* output) {
280   if (orig == nullptr || output == nullptr) {
281     return orig == output;
282   }
283   const dex_ir::TypeIdVector* orig_list = orig->GetTypeList();
284   const dex_ir::TypeIdVector* output_list = output->GetTypeList();
285   if (orig_list->size() != output_list->size()) {
286     return false;
287   }
288   for (size_t i = 0; i < orig_list->size(); ++i) {
289     if ((*orig_list)[i]->GetIndex() != (*output_list)[i]->GetIndex()) {
290       return false;
291     }
292   }
293   return true;
294 }
295 
VerifyAnnotationsDirectory(dex_ir::AnnotationsDirectoryItem * orig,dex_ir::AnnotationsDirectoryItem * output,std::string * error_msg)296 bool VerifyAnnotationsDirectory(dex_ir::AnnotationsDirectoryItem* orig,
297                                 dex_ir::AnnotationsDirectoryItem* output,
298                                 std::string* error_msg) {
299   if (orig == nullptr || output == nullptr) {
300     if (orig != output) {
301       *error_msg = "Found unexpected empty annotations directory.";
302       return false;
303     }
304     return true;
305   }
306   if (!VerifyAnnotationSet(orig->GetClassAnnotation(), output->GetClassAnnotation(), error_msg)) {
307     return false;
308   }
309   if (!VerifyFieldAnnotations(orig->GetFieldAnnotations(),
310                               output->GetFieldAnnotations(),
311                               orig->GetOffset(),
312                               error_msg)) {
313     return false;
314   }
315   if (!VerifyMethodAnnotations(orig->GetMethodAnnotations(),
316                                output->GetMethodAnnotations(),
317                                orig->GetOffset(),
318                                error_msg)) {
319     return false;
320   }
321   return VerifyParameterAnnotations(orig->GetParameterAnnotations(),
322                                     output->GetParameterAnnotations(),
323                                     orig->GetOffset(),
324                                     error_msg);
325 }
326 
VerifyFieldAnnotations(dex_ir::FieldAnnotationVector * orig,dex_ir::FieldAnnotationVector * output,uint32_t orig_offset,std::string * error_msg)327 bool VerifyFieldAnnotations(dex_ir::FieldAnnotationVector* orig,
328                             dex_ir::FieldAnnotationVector* output,
329                             uint32_t orig_offset,
330                             std::string* error_msg) {
331   if (orig == nullptr || output == nullptr) {
332     if (orig != output) {
333       *error_msg = StringPrintf(
334           "Found unexpected empty field annotations for annotations directory at offset %x.",
335           orig_offset);
336       return false;
337     }
338     return true;
339   }
340   if (orig->size() != output->size()) {
341     *error_msg = StringPrintf(
342         "Mismatched field annotations size for annotations directory at offset %x: %zu vs %zu.",
343         orig_offset,
344         orig->size(),
345         output->size());
346     return false;
347   }
348   for (size_t i = 0; i < orig->size(); ++i) {
349     dex_ir::FieldAnnotation* orig_field = (*orig)[i].get();
350     dex_ir::FieldAnnotation* output_field = (*output)[i].get();
351     if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) {
352       *error_msg = StringPrintf(
353           "Mismatched field annotation index for annotations directory at offset %x: %u vs %u.",
354           orig_offset,
355           orig_field->GetFieldId()->GetIndex(),
356           output_field->GetFieldId()->GetIndex());
357       return false;
358     }
359     if (!VerifyAnnotationSet(orig_field->GetAnnotationSetItem(),
360                              output_field->GetAnnotationSetItem(),
361                              error_msg)) {
362       return false;
363     }
364   }
365   return true;
366 }
367 
VerifyMethodAnnotations(dex_ir::MethodAnnotationVector * orig,dex_ir::MethodAnnotationVector * output,uint32_t orig_offset,std::string * error_msg)368 bool VerifyMethodAnnotations(dex_ir::MethodAnnotationVector* orig,
369                              dex_ir::MethodAnnotationVector* output,
370                              uint32_t orig_offset,
371                              std::string* error_msg) {
372   if (orig == nullptr || output == nullptr) {
373     if (orig != output) {
374       *error_msg = StringPrintf(
375           "Found unexpected empty method annotations for annotations directory at offset %x.",
376           orig_offset);
377       return false;
378     }
379     return true;
380   }
381   if (orig->size() != output->size()) {
382     *error_msg = StringPrintf(
383         "Mismatched method annotations size for annotations directory at offset %x: %zu vs %zu.",
384         orig_offset,
385         orig->size(),
386         output->size());
387     return false;
388   }
389   for (size_t i = 0; i < orig->size(); ++i) {
390     dex_ir::MethodAnnotation* orig_method = (*orig)[i].get();
391     dex_ir::MethodAnnotation* output_method = (*output)[i].get();
392     if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) {
393       *error_msg = StringPrintf(
394           "Mismatched method annotation index for annotations directory at offset %x: %u vs %u.",
395           orig_offset,
396           orig_method->GetMethodId()->GetIndex(),
397           output_method->GetMethodId()->GetIndex());
398       return false;
399     }
400     if (!VerifyAnnotationSet(orig_method->GetAnnotationSetItem(),
401                              output_method->GetAnnotationSetItem(),
402                              error_msg)) {
403       return false;
404     }
405   }
406   return true;
407 }
408 
VerifyParameterAnnotations(dex_ir::ParameterAnnotationVector * orig,dex_ir::ParameterAnnotationVector * output,uint32_t orig_offset,std::string * error_msg)409 bool VerifyParameterAnnotations(dex_ir::ParameterAnnotationVector* orig,
410                                 dex_ir::ParameterAnnotationVector* output,
411                                 uint32_t orig_offset,
412                                 std::string* error_msg) {
413   if (orig == nullptr || output == nullptr) {
414     if (orig != output) {
415       *error_msg = StringPrintf(
416           "Found unexpected empty parameter annotations for annotations directory at offset %x.",
417           orig_offset);
418       return false;
419     }
420     return true;
421   }
422   if (orig->size() != output->size()) {
423     *error_msg = StringPrintf(
424         "Mismatched parameter annotations size for annotations directory at offset %x: %zu vs %zu.",
425         orig_offset,
426         orig->size(),
427         output->size());
428     return false;
429   }
430   for (size_t i = 0; i < orig->size(); ++i) {
431     dex_ir::ParameterAnnotation* orig_param = (*orig)[i].get();
432     dex_ir::ParameterAnnotation* output_param = (*output)[i].get();
433     if (orig_param->GetMethodId()->GetIndex() != output_param->GetMethodId()->GetIndex()) {
434       *error_msg = StringPrintf(
435           "Mismatched parameter annotation index for annotations directory at offset %x: %u vs %u.",
436           orig_offset,
437           orig_param->GetMethodId()->GetIndex(),
438           output_param->GetMethodId()->GetIndex());
439       return false;
440     }
441     if (!VerifyAnnotationSetRefList(orig_param->GetAnnotations(),
442                                     output_param->GetAnnotations(),
443                                     error_msg)) {
444       return false;
445     }
446   }
447   return true;
448 }
449 
VerifyAnnotationSetRefList(dex_ir::AnnotationSetRefList * orig,dex_ir::AnnotationSetRefList * output,std::string * error_msg)450 bool VerifyAnnotationSetRefList(dex_ir::AnnotationSetRefList* orig,
451                                 dex_ir::AnnotationSetRefList* output,
452                                 std::string* error_msg) {
453   std::vector<dex_ir::AnnotationSetItem*>* orig_items = orig->GetItems();
454   std::vector<dex_ir::AnnotationSetItem*>* output_items = output->GetItems();
455   if (orig_items->size() != output_items->size()) {
456     *error_msg = StringPrintf(
457         "Mismatched annotation set ref list size at offset %x: %zu vs %zu.",
458         orig->GetOffset(),
459         orig_items->size(),
460         output_items->size());
461     return false;
462   }
463   for (size_t i = 0; i < orig_items->size(); ++i) {
464     if (!VerifyAnnotationSet((*orig_items)[i], (*output_items)[i], error_msg)) {
465       return false;
466     }
467   }
468   return true;
469 }
470 
VerifyAnnotationSet(dex_ir::AnnotationSetItem * orig,dex_ir::AnnotationSetItem * output,std::string * error_msg)471 bool VerifyAnnotationSet(dex_ir::AnnotationSetItem* orig,
472                          dex_ir::AnnotationSetItem* output,
473                          std::string* error_msg) {
474   if (orig == nullptr || output == nullptr) {
475     if (orig != output) {
476       *error_msg = "Found unexpected empty annotation set.";
477       return false;
478     }
479     return true;
480   }
481   std::vector<dex_ir::AnnotationItem*>* orig_items = orig->GetItems();
482   std::vector<dex_ir::AnnotationItem*>* output_items = output->GetItems();
483   if (orig_items->size() != output_items->size()) {
484     *error_msg = StringPrintf("Mismatched size for annotation set at offset %x: %zu vs %zu.",
485                               orig->GetOffset(),
486                               orig_items->size(),
487                               output_items->size());
488     return false;
489   }
490   for (size_t i = 0; i < orig_items->size(); ++i) {
491     if (!VerifyAnnotation((*orig_items)[i], (*output_items)[i], error_msg)) {
492       return false;
493     }
494   }
495   return true;
496 }
497 
VerifyAnnotation(dex_ir::AnnotationItem * orig,dex_ir::AnnotationItem * output,std::string * error_msg)498 bool VerifyAnnotation(dex_ir::AnnotationItem* orig,
499                       dex_ir::AnnotationItem* output,
500                       std::string* error_msg) {
501   if (orig->GetVisibility() != output->GetVisibility()) {
502     *error_msg = StringPrintf("Mismatched visibility for annotation at offset %x: %u vs %u.",
503                               orig->GetOffset(),
504                               orig->GetVisibility(),
505                               output->GetVisibility());
506     return false;
507   }
508   return VerifyEncodedAnnotation(orig->GetAnnotation(),
509                                  output->GetAnnotation(),
510                                  orig->GetOffset(),
511                                  error_msg);
512 }
513 
VerifyEncodedAnnotation(dex_ir::EncodedAnnotation * orig,dex_ir::EncodedAnnotation * output,uint32_t orig_offset,std::string * error_msg)514 bool VerifyEncodedAnnotation(dex_ir::EncodedAnnotation* orig,
515                              dex_ir::EncodedAnnotation* output,
516                              uint32_t orig_offset,
517                              std::string* error_msg) {
518   if (orig->GetType()->GetIndex() != output->GetType()->GetIndex()) {
519     *error_msg = StringPrintf(
520         "Mismatched encoded annotation type for annotation at offset %x: %u vs %u.",
521         orig_offset,
522         orig->GetType()->GetIndex(),
523         output->GetType()->GetIndex());
524     return false;
525   }
526   dex_ir::AnnotationElementVector* orig_elements = orig->GetAnnotationElements();
527   dex_ir::AnnotationElementVector* output_elements = output->GetAnnotationElements();
528   if (orig_elements->size() != output_elements->size()) {
529     *error_msg = StringPrintf(
530         "Mismatched encoded annotation size for annotation at offset %x: %zu vs %zu.",
531         orig_offset,
532         orig_elements->size(),
533         output_elements->size());
534     return false;
535   }
536   for (size_t i = 0; i < orig_elements->size(); ++i) {
537     if (!VerifyAnnotationElement((*orig_elements)[i].get(),
538                                  (*output_elements)[i].get(),
539                                  orig_offset,
540                                  error_msg)) {
541       return false;
542     }
543   }
544   return true;
545 }
546 
VerifyAnnotationElement(dex_ir::AnnotationElement * orig,dex_ir::AnnotationElement * output,uint32_t orig_offset,std::string * error_msg)547 bool VerifyAnnotationElement(dex_ir::AnnotationElement* orig,
548                              dex_ir::AnnotationElement* output,
549                              uint32_t orig_offset,
550                              std::string* error_msg) {
551   if (orig->GetName()->GetIndex() != output->GetName()->GetIndex()) {
552     *error_msg = StringPrintf(
553         "Mismatched annotation element name for annotation at offset %x: %u vs %u.",
554         orig_offset,
555         orig->GetName()->GetIndex(),
556         output->GetName()->GetIndex());
557     return false;
558   }
559   return VerifyEncodedValue(orig->GetValue(), output->GetValue(), orig_offset, error_msg);
560 }
561 
VerifyEncodedValue(dex_ir::EncodedValue * orig,dex_ir::EncodedValue * output,uint32_t orig_offset,std::string * error_msg)562 bool VerifyEncodedValue(dex_ir::EncodedValue* orig,
563                         dex_ir::EncodedValue* output,
564                         uint32_t orig_offset,
565                         std::string* error_msg) {
566   if (orig->Type() != output->Type()) {
567     *error_msg = StringPrintf(
568         "Mismatched encoded value type for annotation or encoded array at offset %x: %d vs %d.",
569         orig_offset,
570         orig->Type(),
571         output->Type());
572     return false;
573   }
574   switch (orig->Type()) {
575     case DexFile::kDexAnnotationByte:
576       if (orig->GetByte() != output->GetByte()) {
577         *error_msg = StringPrintf("Mismatched encoded byte for annotation at offset %x: %d vs %d.",
578                                   orig_offset,
579                                   orig->GetByte(),
580                                   output->GetByte());
581         return false;
582       }
583       break;
584     case DexFile::kDexAnnotationShort:
585       if (orig->GetShort() != output->GetShort()) {
586         *error_msg = StringPrintf("Mismatched encoded short for annotation at offset %x: %d vs %d.",
587                                   orig_offset,
588                                   orig->GetShort(),
589                                   output->GetShort());
590         return false;
591       }
592       break;
593     case DexFile::kDexAnnotationChar:
594       if (orig->GetChar() != output->GetChar()) {
595         *error_msg = StringPrintf("Mismatched encoded char for annotation at offset %x: %c vs %c.",
596                                   orig_offset,
597                                   orig->GetChar(),
598                                   output->GetChar());
599         return false;
600       }
601       break;
602     case DexFile::kDexAnnotationInt:
603       if (orig->GetInt() != output->GetInt()) {
604         *error_msg = StringPrintf("Mismatched encoded int for annotation at offset %x: %d vs %d.",
605                                   orig_offset,
606                                   orig->GetInt(),
607                                   output->GetInt());
608         return false;
609       }
610       break;
611     case DexFile::kDexAnnotationLong:
612       if (orig->GetLong() != output->GetLong()) {
613         *error_msg = StringPrintf(
614             "Mismatched encoded long for annotation at offset %x: %" PRId64 " vs %" PRId64 ".",
615             orig_offset,
616             orig->GetLong(),
617             output->GetLong());
618         return false;
619       }
620       break;
621     case DexFile::kDexAnnotationFloat:
622       // The float value is encoded, so compare as if it's an int.
623       if (orig->GetInt() != output->GetInt()) {
624         *error_msg = StringPrintf(
625             "Mismatched encoded float for annotation at offset %x: %x (encoded) vs %x (encoded).",
626                                   orig_offset,
627                                   orig->GetInt(),
628                                   output->GetInt());
629         return false;
630       }
631       break;
632     case DexFile::kDexAnnotationDouble:
633       // The double value is encoded, so compare as if it's a long.
634       if (orig->GetLong() != output->GetLong()) {
635         *error_msg = StringPrintf(
636             "Mismatched encoded double for annotation at offset %x: %" PRIx64
637             " (encoded) vs %" PRIx64 " (encoded).",
638             orig_offset,
639             orig->GetLong(),
640             output->GetLong());
641         return false;
642       }
643       break;
644     case DexFile::kDexAnnotationString:
645       if (orig->GetStringId()->GetIndex() != output->GetStringId()->GetIndex()) {
646         *error_msg = StringPrintf(
647             "Mismatched encoded string for annotation at offset %x: %s vs %s.",
648             orig_offset,
649             orig->GetStringId()->Data(),
650             output->GetStringId()->Data());
651         return false;
652       }
653       break;
654     case DexFile::kDexAnnotationType:
655       if (orig->GetTypeId()->GetIndex() != output->GetTypeId()->GetIndex()) {
656         *error_msg = StringPrintf("Mismatched encoded type for annotation at offset %x: %u vs %u.",
657                                   orig_offset,
658                                   orig->GetTypeId()->GetIndex(),
659                                   output->GetTypeId()->GetIndex());
660         return false;
661       }
662       break;
663     case DexFile::kDexAnnotationField:
664     case DexFile::kDexAnnotationEnum:
665       if (orig->GetFieldId()->GetIndex() != output->GetFieldId()->GetIndex()) {
666         *error_msg = StringPrintf("Mismatched encoded field for annotation at offset %x: %u vs %u.",
667                                   orig_offset,
668                                   orig->GetFieldId()->GetIndex(),
669                                   output->GetFieldId()->GetIndex());
670         return false;
671       }
672       break;
673     case DexFile::kDexAnnotationMethod:
674       if (orig->GetMethodId()->GetIndex() != output->GetMethodId()->GetIndex()) {
675         *error_msg = StringPrintf(
676             "Mismatched encoded method for annotation at offset %x: %u vs %u.",
677             orig_offset,
678             orig->GetMethodId()->GetIndex(),
679             output->GetMethodId()->GetIndex());
680         return false;
681       }
682       break;
683     case DexFile::kDexAnnotationArray:
684       if (!VerifyEncodedArray(orig->GetEncodedArray(), output->GetEncodedArray(), error_msg)) {
685         return false;
686       }
687       break;
688     case DexFile::kDexAnnotationAnnotation:
689       if (!VerifyEncodedAnnotation(orig->GetEncodedAnnotation(),
690                                    output->GetEncodedAnnotation(),
691                                    orig_offset,
692                                    error_msg)) {
693         return false;
694       }
695       break;
696     case DexFile::kDexAnnotationNull:
697       break;
698     case DexFile::kDexAnnotationBoolean:
699       if (orig->GetBoolean() != output->GetBoolean()) {
700         *error_msg = StringPrintf(
701             "Mismatched encoded boolean for annotation at offset %x: %d vs %d.",
702             orig_offset,
703             orig->GetBoolean(),
704             output->GetBoolean());
705         return false;
706       }
707       break;
708     default:
709       break;
710   }
711   return true;
712 }
713 
VerifyEncodedArray(dex_ir::EncodedArrayItem * orig,dex_ir::EncodedArrayItem * output,std::string * error_msg)714 bool VerifyEncodedArray(dex_ir::EncodedArrayItem* orig,
715                         dex_ir::EncodedArrayItem* output,
716                         std::string* error_msg) {
717   if (orig == nullptr || output == nullptr) {
718     if (orig != output) {
719       *error_msg = "Found unexpected empty encoded array.";
720       return false;
721     }
722     return true;
723   }
724   dex_ir::EncodedValueVector* orig_vector = orig->GetEncodedValues();
725   dex_ir::EncodedValueVector* output_vector = output->GetEncodedValues();
726   if (orig_vector->size() != output_vector->size()) {
727     *error_msg = StringPrintf("Mismatched size for encoded array at offset %x: %zu vs %zu.",
728                               orig->GetOffset(),
729                               orig_vector->size(),
730                               output_vector->size());
731     return false;
732   }
733   for (size_t i = 0; i < orig_vector->size(); ++i) {
734     if (!VerifyEncodedValue((*orig_vector)[i].get(),
735                             (*output_vector)[i].get(),
736                             orig->GetOffset(),
737                             error_msg)) {
738       return false;
739     }
740   }
741   return true;
742 }
743 
VerifyClassData(dex_ir::ClassData * orig,dex_ir::ClassData * output,std::string * error_msg)744 bool VerifyClassData(dex_ir::ClassData* orig, dex_ir::ClassData* output, std::string* error_msg) {
745   if (orig == nullptr || output == nullptr) {
746     if (orig != output) {
747       *error_msg = "Found unexpected empty class data.";
748       return false;
749     }
750     return true;
751   }
752   if (!VerifyFields(orig->StaticFields(), output->StaticFields(), orig->GetOffset(), error_msg)) {
753     return false;
754   }
755   if (!VerifyFields(orig->InstanceFields(),
756                     output->InstanceFields(),
757                     orig->GetOffset(),
758                     error_msg)) {
759     return false;
760   }
761   if (!VerifyMethods(orig->DirectMethods(),
762                      output->DirectMethods(),
763                      orig->GetOffset(),
764                      error_msg)) {
765     return false;
766   }
767   return VerifyMethods(orig->VirtualMethods(),
768                        output->VirtualMethods(),
769                        orig->GetOffset(),
770                        error_msg);
771 }
772 
VerifyFields(dex_ir::FieldItemVector * orig,dex_ir::FieldItemVector * output,uint32_t orig_offset,std::string * error_msg)773 bool VerifyFields(dex_ir::FieldItemVector* orig,
774                   dex_ir::FieldItemVector* output,
775                   uint32_t orig_offset,
776                   std::string* error_msg) {
777   if (orig->size() != output->size()) {
778     *error_msg = StringPrintf("Mismatched fields size for class data at offset %x: %zu vs %zu.",
779                               orig_offset,
780                               orig->size(),
781                               output->size());
782     return false;
783   }
784   for (size_t i = 0; i < orig->size(); ++i) {
785     dex_ir::FieldItem* orig_field = &(*orig)[i];
786     dex_ir::FieldItem* output_field = &(*output)[i];
787     if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) {
788       *error_msg = StringPrintf("Mismatched field index for class data at offset %x: %u vs %u.",
789                                 orig_offset,
790                                 orig_field->GetFieldId()->GetIndex(),
791                                 output_field->GetFieldId()->GetIndex());
792       return false;
793     }
794     if (orig_field->GetAccessFlags() != output_field->GetAccessFlags()) {
795       *error_msg = StringPrintf(
796           "Mismatched field access flags for class data at offset %x: %u vs %u.",
797           orig_offset,
798           orig_field->GetAccessFlags(),
799           output_field->GetAccessFlags());
800       return false;
801     }
802   }
803   return true;
804 }
805 
VerifyMethods(dex_ir::MethodItemVector * orig,dex_ir::MethodItemVector * output,uint32_t orig_offset,std::string * error_msg)806 bool VerifyMethods(dex_ir::MethodItemVector* orig,
807                    dex_ir::MethodItemVector* output,
808                    uint32_t orig_offset,
809                    std::string* error_msg) {
810   if (orig->size() != output->size()) {
811     *error_msg = StringPrintf("Mismatched methods size for class data at offset %x: %zu vs %zu.",
812                               orig_offset,
813                               orig->size(),
814                               output->size());
815     return false;
816   }
817   for (size_t i = 0; i < orig->size(); ++i) {
818     dex_ir::MethodItem* orig_method = &(*orig)[i];
819     dex_ir::MethodItem* output_method = &(*output)[i];
820     if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) {
821       *error_msg = StringPrintf("Mismatched method index for class data at offset %x: %u vs %u.",
822                                 orig_offset,
823                                 orig_method->GetMethodId()->GetIndex(),
824                                 output_method->GetMethodId()->GetIndex());
825       return false;
826     }
827     if (orig_method->GetAccessFlags() != output_method->GetAccessFlags()) {
828       *error_msg = StringPrintf(
829           "Mismatched method access flags for class data at offset %x: %u vs %u.",
830           orig_offset,
831           orig_method->GetAccessFlags(),
832           output_method->GetAccessFlags());
833       return false;
834     }
835     if (!VerifyCode(orig_method->GetCodeItem(), output_method->GetCodeItem(), error_msg)) {
836       return false;
837     }
838   }
839   return true;
840 }
841 
VerifyCode(dex_ir::CodeItem * orig,dex_ir::CodeItem * output,std::string * error_msg)842 bool VerifyCode(dex_ir::CodeItem* orig, dex_ir::CodeItem* output, std::string* error_msg) {
843   if (orig == nullptr || output == nullptr) {
844     if (orig != output) {
845       *error_msg = "Found unexpected empty code item.";
846       return false;
847     }
848     return true;
849   }
850   if (orig->RegistersSize() != output->RegistersSize()) {
851     *error_msg = StringPrintf("Mismatched registers size for code item at offset %x: %u vs %u.",
852                               orig->GetOffset(),
853                               orig->RegistersSize(),
854                               output->RegistersSize());
855     return false;
856   }
857   if (orig->InsSize() != output->InsSize()) {
858     *error_msg = StringPrintf("Mismatched ins size for code item at offset %x: %u vs %u.",
859                               orig->GetOffset(),
860                               orig->InsSize(),
861                               output->InsSize());
862     return false;
863   }
864   if (orig->OutsSize() != output->OutsSize()) {
865     *error_msg = StringPrintf("Mismatched outs size for code item at offset %x: %u vs %u.",
866                               orig->GetOffset(),
867                               orig->OutsSize(),
868                               output->OutsSize());
869     return false;
870   }
871   if (orig->TriesSize() != output->TriesSize()) {
872     *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %u vs %u.",
873                               orig->GetOffset(),
874                               orig->TriesSize(),
875                               output->TriesSize());
876     return false;
877   }
878   if (!VerifyDebugInfo(orig->DebugInfo(), output->DebugInfo(), error_msg)) {
879     return false;
880   }
881   if (orig->InsnsSize() != output->InsnsSize()) {
882     *error_msg = StringPrintf("Mismatched insns size for code item at offset %x: %u vs %u.",
883                               orig->GetOffset(),
884                               orig->InsnsSize(),
885                               output->InsnsSize());
886     return false;
887   }
888   if (memcmp(orig->Insns(), output->Insns(), orig->InsnsSize()) != 0) {
889     *error_msg = StringPrintf("Mismatched insns for code item at offset %x.",
890                               orig->GetOffset());
891     return false;
892   }
893   if (!VerifyTries(orig->Tries(), output->Tries(), orig->GetOffset(), error_msg)) {
894     return false;
895   }
896   return VerifyHandlers(orig->Handlers(), output->Handlers(), orig->GetOffset(), error_msg);
897 }
898 
VerifyDebugInfo(dex_ir::DebugInfoItem * orig,dex_ir::DebugInfoItem * output,std::string * error_msg)899 bool VerifyDebugInfo(dex_ir::DebugInfoItem* orig,
900                      dex_ir::DebugInfoItem* output,
901                      std::string* error_msg) {
902   if (orig == nullptr || output == nullptr) {
903     if (orig != output) {
904       *error_msg = "Found unexpected empty debug info.";
905       return false;
906     }
907     return true;
908   }
909   // TODO: Test for debug equivalence rather than byte array equality.
910   uint32_t orig_size = orig->GetDebugInfoSize();
911   uint32_t output_size = output->GetDebugInfoSize();
912   if (orig_size != output_size) {
913     *error_msg = "DebugInfoSize disagreed.";
914     return false;
915   }
916   uint8_t* orig_data = orig->GetDebugInfo();
917   uint8_t* output_data = output->GetDebugInfo();
918   if ((orig_data == nullptr && output_data != nullptr) ||
919       (orig_data != nullptr && output_data == nullptr)) {
920     *error_msg = "DebugInfo null/non-null mismatch.";
921     return false;
922   }
923   if (orig_data != nullptr && memcmp(orig_data, output_data, orig_size) != 0) {
924     *error_msg = "DebugInfo bytes mismatch.";
925     return false;
926   }
927   return true;
928 }
929 
VerifyTries(dex_ir::TryItemVector * orig,dex_ir::TryItemVector * output,uint32_t orig_offset,std::string * error_msg)930 bool VerifyTries(dex_ir::TryItemVector* orig,
931                  dex_ir::TryItemVector* output,
932                  uint32_t orig_offset,
933                  std::string* error_msg) {
934   if (orig == nullptr || output == nullptr) {
935     if (orig != output) {
936       *error_msg = "Found unexpected empty try items.";
937       return false;
938     }
939     return true;
940   }
941   if (orig->size() != output->size()) {
942     *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %zu vs %zu.",
943                               orig_offset,
944                               orig->size(),
945                               output->size());
946     return false;
947   }
948   for (size_t i = 0; i < orig->size(); ++i) {
949     const dex_ir::TryItem* orig_try = (*orig)[i].get();
950     const dex_ir::TryItem* output_try = (*output)[i].get();
951     if (orig_try->StartAddr() != output_try->StartAddr()) {
952       *error_msg = StringPrintf(
953           "Mismatched try item start addr for code item at offset %x: %u vs %u.",
954           orig_offset,
955           orig_try->StartAddr(),
956           output_try->StartAddr());
957       return false;
958     }
959     if (orig_try->InsnCount() != output_try->InsnCount()) {
960       *error_msg = StringPrintf(
961           "Mismatched try item insn count for code item at offset %x: %u vs %u.",
962           orig_offset,
963           orig_try->InsnCount(),
964                                 output_try->InsnCount());
965       return false;
966     }
967     if (!VerifyHandler(orig_try->GetHandlers(),
968                        output_try->GetHandlers(),
969                        orig_offset,
970                        error_msg)) {
971       return false;
972     }
973   }
974   return true;
975 }
976 
VerifyHandlers(dex_ir::CatchHandlerVector * orig,dex_ir::CatchHandlerVector * output,uint32_t orig_offset,std::string * error_msg)977 bool VerifyHandlers(dex_ir::CatchHandlerVector* orig,
978                     dex_ir::CatchHandlerVector* output,
979                     uint32_t orig_offset,
980                     std::string* error_msg) {
981   if (orig == nullptr || output == nullptr) {
982     if (orig != output) {
983       *error_msg = "Found unexpected empty catch handlers.";
984       return false;
985     }
986     return true;
987   }
988   if (orig->size() != output->size()) {
989     *error_msg = StringPrintf(
990         "Mismatched catch handlers size for code item at offset %x: %zu vs %zu.",
991         orig_offset,
992         orig->size(),
993         output->size());
994     return false;
995   }
996   for (size_t i = 0; i < orig->size(); ++i) {
997     if (!VerifyHandler((*orig)[i].get(), (*output)[i].get(), orig_offset, error_msg)) {
998       return false;
999     }
1000   }
1001   return true;
1002 }
1003 
VerifyHandler(const dex_ir::CatchHandler * orig,const dex_ir::CatchHandler * output,uint32_t orig_offset,std::string * error_msg)1004 bool VerifyHandler(const dex_ir::CatchHandler* orig,
1005                    const dex_ir::CatchHandler* output,
1006                    uint32_t orig_offset,
1007                    std::string* error_msg) {
1008   dex_ir::TypeAddrPairVector* orig_handlers = orig->GetHandlers();
1009   dex_ir::TypeAddrPairVector* output_handlers = output->GetHandlers();
1010   if (orig_handlers->size() != output_handlers->size()) {
1011     *error_msg = StringPrintf(
1012         "Mismatched number of catch handlers for code item at offset %x: %zu vs %zu.",
1013         orig_offset,
1014         orig_handlers->size(),
1015         output_handlers->size());
1016     return false;
1017   }
1018   for (size_t i = 0; i < orig_handlers->size(); ++i) {
1019     const dex_ir::TypeAddrPair* orig_handler = (*orig_handlers)[i].get();
1020     const dex_ir::TypeAddrPair* output_handler = (*output_handlers)[i].get();
1021     if (orig_handler->GetTypeId() == nullptr || output_handler->GetTypeId() == nullptr) {
1022       if (orig_handler->GetTypeId() != output_handler->GetTypeId()) {
1023         *error_msg = StringPrintf(
1024             "Found unexpected catch all catch handler for code item at offset %x.",
1025             orig_offset);
1026         return false;
1027       }
1028     } else if (orig_handler->GetTypeId()->GetIndex() != output_handler->GetTypeId()->GetIndex()) {
1029       *error_msg = StringPrintf(
1030           "Mismatched catch handler type for code item at offset %x: %u vs %u.",
1031           orig_offset,
1032           orig_handler->GetTypeId()->GetIndex(),
1033           output_handler->GetTypeId()->GetIndex());
1034       return false;
1035     }
1036     if (orig_handler->GetAddress() != output_handler->GetAddress()) {
1037       *error_msg = StringPrintf(
1038           "Mismatched catch handler address for code item at offset %x: %u vs %u.",
1039           orig_offset,
1040           orig_handler->GetAddress(),
1041           output_handler->GetAddress());
1042       return false;
1043     }
1044   }
1045   return true;
1046 }
1047 
1048 }  // namespace art
1049