• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "repr/abi_diff_helpers.h"
16 
17 #include "utils/header_abi_util.h"
18 
19 #include <llvm/Support/raw_ostream.h>
20 
21 
22 namespace header_checker {
23 namespace repr {
24 
25 
Unwind(const std::deque<std::string> * type_queue)26 std::string Unwind(const std::deque<std::string> *type_queue) {
27   if (!type_queue) {
28     return "";
29   }
30   std::string stack_str;
31   std::deque<std::string> type_queue_copy = *type_queue;
32   while (!type_queue_copy.empty()) {
33     stack_str += type_queue_copy.front() + "-> ";
34     type_queue_copy.pop_front();
35   }
36   return stack_str;
37 }
38 
TypeQueueCheckAndPushBack(std::deque<std::string> * type_queue,const std::string & str)39 static void TypeQueueCheckAndPushBack(std::deque<std::string> *type_queue,
40                                       const std::string &str) {
41   if (type_queue) {
42     type_queue->push_back(str);
43   }
44 }
45 
TypeQueueCheckAndPop(std::deque<std::string> * type_queue)46 static void TypeQueueCheckAndPop(std::deque<std::string> *type_queue) {
47   if (type_queue && !type_queue->empty()) {
48     type_queue->pop_back();
49   }
50 }
51 
IsAccessDownGraded(AccessSpecifierIR old_access,AccessSpecifierIR new_access)52 static bool IsAccessDownGraded(AccessSpecifierIR old_access,
53                                AccessSpecifierIR new_access) {
54   bool access_downgraded = false;
55   switch (old_access) {
56     case AccessSpecifierIR::ProtectedAccess:
57       if (new_access == AccessSpecifierIR::PrivateAccess) {
58         access_downgraded = true;
59       }
60       break;
61     case AccessSpecifierIR::PublicAccess:
62       if (new_access != AccessSpecifierIR::PublicAccess) {
63         access_downgraded = true;
64       }
65       break;
66     default:
67       break;
68   }
69   return access_downgraded;
70 }
71 
ConvertTypeIdToString(const AbiElementMap<const TypeIR * > & type_graph,const std::string & type_id)72 static std::string ConvertTypeIdToString(
73     const AbiElementMap<const TypeIR *> &type_graph,
74     const std::string &type_id) {
75   auto it = type_graph.find(type_id);
76   if (it != type_graph.end()) {
77     return it->second->GetName();
78   }
79   return "type-unexported";
80 }
81 
82 template <typename Container>
ReplaceReferencesOtherTypeIdWithName(const AbiElementMap<const TypeIR * > & type_graph,Container & to_fix_elements)83 static void ReplaceReferencesOtherTypeIdWithName(
84     const AbiElementMap<const TypeIR *> &type_graph,
85     Container &to_fix_elements) {
86   for (auto &element : to_fix_elements) {
87     element.SetReferencedType(
88         ConvertTypeIdToString(type_graph, element.GetReferencedType()));
89   }
90 }
91 
ReplaceEnumTypeIRTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,EnumTypeIR * enum_type_ir)92 static void ReplaceEnumTypeIRTypeIdsWithTypeNames(
93     const AbiElementMap<const TypeIR *> &type_graph, EnumTypeIR *enum_type_ir) {
94   // Replace underlying type.
95   enum_type_ir->SetUnderlyingType(
96       ConvertTypeIdToString(type_graph, enum_type_ir->GetUnderlyingType()));
97 }
98 
ReplaceRecordTypeIRTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,RecordTypeIR * record_type_ir)99 static void ReplaceRecordTypeIRTypeIdsWithTypeNames(
100     const AbiElementMap<const TypeIR *> &type_graph,
101     RecordTypeIR *record_type_ir) {
102   // Replace Fields
103   ReplaceReferencesOtherTypeIdWithName(type_graph,
104                                        record_type_ir->GetFields());
105   // Replace template parameters
106   ReplaceReferencesOtherTypeIdWithName(type_graph,
107                                        record_type_ir->GetTemplateElements());
108   // Replace bases
109   ReplaceReferencesOtherTypeIdWithName(type_graph,
110                                        record_type_ir->GetBases());
111 }
112 
ReplaceGlobalVarTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,GlobalVarIR * global_var_ir)113 static void ReplaceGlobalVarTypeIdsWithTypeNames(
114     const AbiElementMap<const TypeIR *> &type_graph,
115     GlobalVarIR *global_var_ir) {
116   // Replace referenced type id.
117   global_var_ir->SetReferencedType(
118       ConvertTypeIdToString(type_graph, global_var_ir->GetReferencedType()));
119 }
120 
ReplaceFunctionTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,FunctionIR * function_ir)121 static void ReplaceFunctionTypeIdsWithTypeNames(
122     const AbiElementMap<const TypeIR *> &type_graph, FunctionIR *function_ir) {
123   // Replace return type
124   function_ir->SetReturnType(
125       ConvertTypeIdToString(type_graph, function_ir->GetReturnType()));
126   // Replace function parameters
127   ReplaceReferencesOtherTypeIdWithName(type_graph,
128                                        function_ir->GetParameters());
129   // Replace function template parameters
130   ReplaceReferencesOtherTypeIdWithName(type_graph,
131                                        function_ir->GetTemplateElements());
132 }
133 
ReplaceTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,LinkableMessageIR * lm)134 void ReplaceTypeIdsWithTypeNames(
135     const AbiElementMap<const TypeIR *> &type_graph,
136     LinkableMessageIR *lm) {
137   switch (lm->GetKind()) {
138     case FunctionKind:
139       ReplaceFunctionTypeIdsWithTypeNames(
140           type_graph, static_cast<FunctionIR *>(lm));
141       break;
142     case GlobalVarKind:
143       ReplaceGlobalVarTypeIdsWithTypeNames(
144           type_graph, static_cast<GlobalVarIR *>(lm));
145       break;
146     case RecordTypeKind:
147       ReplaceRecordTypeIRTypeIdsWithTypeNames(
148           type_graph, static_cast<RecordTypeIR *>(lm));
149       break;
150     case EnumTypeKind:
151       ReplaceEnumTypeIRTypeIdsWithTypeNames(
152           type_graph, static_cast<EnumTypeIR *>(lm));
153       break;
154     default:
155       // This method should not be called on any other LinkableMessage
156       assert(0);
157   }
158 }
159 
CompareEnumFields(const std::vector<EnumFieldIR> & old_fields,const std::vector<EnumFieldIR> & new_fields,EnumTypeDiffIR * enum_type_diff_ir)160 void AbiDiffHelper::CompareEnumFields(
161     const std::vector<EnumFieldIR> &old_fields,
162     const std::vector<EnumFieldIR> &new_fields,
163     EnumTypeDiffIR *enum_type_diff_ir) {
164   AbiElementMap<const EnumFieldIR *> old_fields_map;
165   AbiElementMap<const EnumFieldIR *> new_fields_map;
166   utils::AddToMap(&old_fields_map, old_fields,
167                   [](const EnumFieldIR *f) {return f->GetName();},
168                   [](const EnumFieldIR *f) {return f;});
169 
170   utils::AddToMap(&new_fields_map, new_fields,
171                   [](const EnumFieldIR *f) {return f->GetName();},
172                   [](const EnumFieldIR *f) {return f;});
173 
174   std::vector<const EnumFieldIR *> removed_fields =
175       utils::FindRemovedElements(old_fields_map, new_fields_map);
176 
177   std::vector<const EnumFieldIR *> added_fields =
178       utils::FindRemovedElements(new_fields_map, old_fields_map);
179 
180   enum_type_diff_ir->SetFieldsAdded(std::move(added_fields));
181 
182   enum_type_diff_ir->SetFieldsRemoved(std::move(removed_fields));
183 
184   std::vector<std::pair<const EnumFieldIR *,
185                         const EnumFieldIR *>> cf =
186       utils::FindCommonElements(old_fields_map, new_fields_map);
187   std::vector<EnumFieldDiffIR> enum_field_diffs;
188   for (auto &&common_fields : cf) {
189     if (common_fields.first->GetValue() != common_fields.second->GetValue()) {
190       EnumFieldDiffIR enum_field_diff_ir(common_fields.first,
191                                                    common_fields.second);
192       enum_field_diffs.emplace_back(std::move(enum_field_diff_ir));
193     }
194   }
195   enum_type_diff_ir->SetFieldsDiff(std::move(enum_field_diffs));
196 }
197 
CompareEnumTypes(const EnumTypeIR * old_type,const EnumTypeIR * new_type,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)198 DiffStatus AbiDiffHelper::CompareEnumTypes(
199     const EnumTypeIR *old_type, const EnumTypeIR *new_type,
200     std::deque<std::string> *type_queue,
201     DiffMessageIR::DiffKind diff_kind) {
202   if (old_type->GetUniqueId() != new_type->GetUniqueId()) {
203     return DiffStatus::direct_diff;
204   }
205   auto enum_type_diff_ir = std::make_unique<EnumTypeDiffIR>();
206   enum_type_diff_ir->SetName(old_type->GetName());
207   const std::string &old_underlying_type =
208       ConvertTypeIdToString(old_types_, old_type->GetUnderlyingType());
209   const std::string &new_underlying_type =
210       ConvertTypeIdToString(new_types_, new_type->GetUnderlyingType());
211   if (old_underlying_type != new_underlying_type) {
212     enum_type_diff_ir->SetUnderlyingTypeDiff(
213         std::make_unique<std::pair<std::string, std::string>>(
214             old_underlying_type, new_underlying_type));
215   }
216   CompareEnumFields(old_type->GetFields(), new_type->GetFields(),
217                     enum_type_diff_ir.get());
218   if ((enum_type_diff_ir->IsExtended() ||
219        enum_type_diff_ir->IsIncompatible()) &&
220       (ir_diff_dumper_ && !ir_diff_dumper_->AddDiffMessageIR(
221           enum_type_diff_ir.get(), Unwind(type_queue), diff_kind))) {
222     llvm::errs() << "AddDiffMessage on EnumTypeDiffIR failed\n";
223     ::exit(1);
224   }
225   return DiffStatus::no_diff;
226 }
227 
RemoveThunkInfoFromMangledName(const std::string & name)228 static std::string RemoveThunkInfoFromMangledName(const std::string &name) {
229   if (name.find("_ZTv") != 0 && name.find("_ZTh") != 0 &&
230       name.find("_ZTc") != 0) {
231     return name;
232   }
233   size_t base_name_pos = name.find("N");
234   if (base_name_pos == std::string::npos) {
235     return name;
236   }
237   return "_Z" + name.substr(base_name_pos);
238 }
239 
CompareVTableComponents(const VTableComponentIR & old_component,const VTableComponentIR & new_component)240 bool AbiDiffHelper::CompareVTableComponents(
241     const VTableComponentIR &old_component,
242     const VTableComponentIR &new_component) {
243   // Vtable components in prebuilts/abi-dumps/vndk/28 don't have thunk info.
244   if (old_component.GetName() != new_component.GetName()) {
245     if (RemoveThunkInfoFromMangledName(old_component.GetName()) ==
246         RemoveThunkInfoFromMangledName(new_component.GetName())) {
247       llvm::errs() << "WARNING: Ignore difference between "
248                    << old_component.GetName() << " and "
249                    << new_component.GetName() << "\n";
250     } else {
251       return false;
252     }
253   }
254   return old_component.GetValue() == new_component.GetValue() &&
255          old_component.GetKind() == new_component.GetKind();
256 }
257 
CompareVTables(const RecordTypeIR * old_record,const RecordTypeIR * new_record)258 bool AbiDiffHelper::CompareVTables(
259     const RecordTypeIR *old_record,
260     const RecordTypeIR *new_record) {
261 
262   const std::vector<VTableComponentIR> &old_components =
263       old_record->GetVTableLayout().GetVTableComponents();
264   const std::vector<VTableComponentIR> &new_components =
265       new_record->GetVTableLayout().GetVTableComponents();
266   if (old_components.size() > new_components.size()) {
267     // Something in the vtable got deleted.
268     return false;
269   }
270   uint32_t i = 0;
271   while (i < old_components.size()) {
272     auto &old_element = old_components.at(i);
273     auto &new_element = new_components.at(i);
274     if (!CompareVTableComponents(old_element, new_element)) {
275       return false;
276     }
277     i++;
278   }
279   return true;
280 }
281 
CompareSizeAndAlignment(const TypeIR * old_type,const TypeIR * new_type)282 bool AbiDiffHelper::CompareSizeAndAlignment(
283     const TypeIR *old_type,
284     const TypeIR *new_type) {
285   return old_type->GetSize() == new_type->GetSize() &&
286       old_type->GetAlignment() == new_type->GetAlignment();
287 }
288 
289 DiffStatusPair<std::unique_ptr<RecordFieldDiffIR>>
CompareCommonRecordFields(const RecordFieldIR * old_field,const RecordFieldIR * new_field,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)290 AbiDiffHelper::CompareCommonRecordFields(
291     const RecordFieldIR *old_field,
292     const RecordFieldIR *new_field,
293     std::deque<std::string> *type_queue,
294     DiffMessageIR::DiffKind diff_kind) {
295 
296   DiffStatus field_diff_status =
297       CompareAndDumpTypeDiff(old_field->GetReferencedType(),
298                              new_field->GetReferencedType(),
299                              type_queue, diff_kind);
300 
301   if (old_field->GetOffset() != new_field->GetOffset() ||
302       // TODO: Should this be an inquality check instead ? Some compilers can
303       // make signatures dependant on absolute values of access specifiers.
304       IsAccessDownGraded(old_field->GetAccess(), new_field->GetAccess()) ||
305       (field_diff_status == DiffStatus::direct_diff)) {
306     return std::make_pair(
307         DiffStatus::direct_diff,
308         std::make_unique<RecordFieldDiffIR>(old_field, new_field)
309         );
310   }
311   return std::make_pair(field_diff_status, nullptr);
312 }
313 
314 
315 GenericFieldDiffInfo<RecordFieldIR, RecordFieldDiffIR>
CompareRecordFields(const std::vector<RecordFieldIR> & old_fields,const std::vector<RecordFieldIR> & new_fields,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)316 AbiDiffHelper::CompareRecordFields(
317     const std::vector<RecordFieldIR> &old_fields,
318     const std::vector<RecordFieldIR> &new_fields,
319     std::deque<std::string> *type_queue,
320     DiffMessageIR::DiffKind diff_kind) {
321   GenericFieldDiffInfo<RecordFieldIR, RecordFieldDiffIR>
322       diffed_removed_added_fields;
323   AbiElementMap<const RecordFieldIR *> old_fields_map;
324   AbiElementMap<const RecordFieldIR *> new_fields_map;
325   std::map<uint64_t, const RecordFieldIR *> old_fields_offset_map;
326   std::map<uint64_t, const RecordFieldIR *> new_fields_offset_map;
327 
328   utils::AddToMap(
329       &old_fields_map, old_fields,
330       [](const RecordFieldIR *f) {return f->GetName();},
331       [](const RecordFieldIR *f) {return f;});
332   utils::AddToMap(
333       &new_fields_map, new_fields,
334       [](const RecordFieldIR *f) {return f->GetName();},
335       [](const RecordFieldIR *f) {return f;});
336   utils::AddToMap(
337       &old_fields_offset_map, old_fields,
338       [](const RecordFieldIR *f) {return f->GetOffset();},
339       [](const RecordFieldIR *f) {return f;});
340   utils::AddToMap(
341       &new_fields_offset_map, new_fields,
342       [](const RecordFieldIR *f) {return f->GetOffset();},
343       [](const RecordFieldIR *f) {return f;});
344   // If a field is removed from the map field_name -> offset see if another
345   // field is present at the same offset and compare the size and type etc,
346   // remove it from the removed fields if they're compatible.
347   DiffStatus final_diff_status = DiffStatus::no_diff;
348   std::vector<const RecordFieldIR *> removed_fields =
349       utils::FindRemovedElements(old_fields_map, new_fields_map);
350 
351   std::vector<const RecordFieldIR *> added_fields =
352       utils::FindRemovedElements(new_fields_map, old_fields_map);
353 
354   auto predicate =
355       [&](const RecordFieldIR *removed_field,
356           std::map<uint64_t, const RecordFieldIR *> &field_off_map) {
357         uint64_t old_field_offset = removed_field->GetOffset();
358         auto corresponding_field_at_same_offset =
359             field_off_map.find(old_field_offset);
360         // Correctly reported as removed, so do not remove.
361         if (corresponding_field_at_same_offset == field_off_map.end()) {
362           return false;
363         }
364 
365         auto comparison_result = CompareCommonRecordFields(
366             removed_field, corresponding_field_at_same_offset->second,
367             type_queue, diff_kind);
368         // No actual diff, so remove it.
369         return (comparison_result.second == nullptr);
370       };
371 
372   removed_fields.erase(
373       std::remove_if(
374           removed_fields.begin(), removed_fields.end(),
375           std::bind(predicate, std::placeholders::_1, new_fields_offset_map)),
376       removed_fields.end());
377   added_fields.erase(
378       std::remove_if(
379           added_fields.begin(), added_fields.end(),
380           std::bind(predicate, std::placeholders::_1, old_fields_offset_map)),
381       added_fields.end());
382 
383   diffed_removed_added_fields.removed_fields_ = std::move(removed_fields);
384   diffed_removed_added_fields.added_fields_ = std::move(added_fields);
385 
386   std::vector<std::pair<
387       const RecordFieldIR *, const RecordFieldIR *>> cf =
388       utils::FindCommonElements(old_fields_map, new_fields_map);
389   bool common_field_diff_exists = false;
390   for (auto &&common_fields : cf) {
391     auto diffed_field_ptr = CompareCommonRecordFields(
392         common_fields.first, common_fields.second, type_queue, diff_kind);
393     if (!common_field_diff_exists &&
394         (diffed_field_ptr.first &
395         (DiffStatus::direct_diff | DiffStatus::indirect_diff))) {
396         common_field_diff_exists = true;
397     }
398     if (diffed_field_ptr.second != nullptr) {
399       diffed_removed_added_fields.diffed_fields_.emplace_back(
400           std::move(*(diffed_field_ptr.second.release())));
401     }
402   }
403   if (diffed_removed_added_fields.diffed_fields_.size() != 0 ||
404       diffed_removed_added_fields.removed_fields_.size() != 0) {
405     final_diff_status = DiffStatus::direct_diff;
406   } else if (common_field_diff_exists) {
407     final_diff_status = DiffStatus::indirect_diff;
408   }
409   diffed_removed_added_fields.diff_status_ = final_diff_status;
410   return diffed_removed_added_fields;
411 }
412 
CompareBaseSpecifiers(const std::vector<CXXBaseSpecifierIR> & old_base_specifiers,const std::vector<CXXBaseSpecifierIR> & new_base_specifiers,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)413 bool AbiDiffHelper::CompareBaseSpecifiers(
414     const std::vector<CXXBaseSpecifierIR> &old_base_specifiers,
415     const std::vector<CXXBaseSpecifierIR> &new_base_specifiers,
416     std::deque<std::string> *type_queue,
417     DiffMessageIR::DiffKind diff_kind) {
418   if (old_base_specifiers.size() != new_base_specifiers.size()) {
419     return false;
420   }
421   int i = 0;
422   while (i < old_base_specifiers.size()) {
423     if (CompareAndDumpTypeDiff(old_base_specifiers.at(i).GetReferencedType(),
424                                new_base_specifiers.at(i).GetReferencedType(),
425                                type_queue, diff_kind) ==
426         DiffStatus::direct_diff ||
427         (old_base_specifiers.at(i).GetAccess() !=
428          new_base_specifiers.at(i).GetAccess())) {
429       return false;
430     }
431     i++;
432   }
433   return true;
434 }
435 
CompareTemplateInfo(const std::vector<TemplateElementIR> & old_template_elements,const std::vector<TemplateElementIR> & new_template_elements,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)436 DiffStatus AbiDiffHelper::CompareTemplateInfo(
437     const std::vector<TemplateElementIR> &old_template_elements,
438     const std::vector<TemplateElementIR> &new_template_elements,
439     std::deque<std::string> *type_queue,
440     DiffMessageIR::DiffKind diff_kind) {
441   uint32_t old_template_size = old_template_elements.size();
442   uint32_t i = 0;
443   if (old_template_size != new_template_elements.size()) {
444     return DiffStatus::direct_diff;
445   }
446   DiffStatus final_diff_status = DiffStatus::no_diff;
447   while (i < old_template_size) {
448     const TemplateElementIR &old_template_element =
449         old_template_elements[i];
450     const TemplateElementIR &new_template_element =
451         new_template_elements[i];
452     auto template_element_diff =
453         CompareAndDumpTypeDiff(old_template_element.GetReferencedType(),
454                                new_template_element.GetReferencedType(),
455                                type_queue, diff_kind);
456     if (template_element_diff &
457         (DiffStatus::direct_diff | DiffStatus::indirect_diff)) {
458       final_diff_status = template_element_diff;
459     }
460     i++;
461   }
462   return final_diff_status;
463 }
464 
465 template <typename DiffContainer, typename T>
ConvertToDiffContainerVector(std::vector<std::pair<T,T>> & nc_vector)466 static std::vector<DiffContainer> ConvertToDiffContainerVector(
467     std::vector<std::pair<T, T>> &nc_vector) {
468   std::vector<DiffContainer> cptr_vec;
469   for (auto &e : nc_vector) {
470     cptr_vec.emplace_back(&e.first, &e.second);
471   }
472   return cptr_vec;
473 }
474 
475 template <typename T>
ConvertToConstPtrVector(std::vector<T> & nc_vector)476 static std::vector<const T*> ConvertToConstPtrVector(
477     std::vector<T> &nc_vector) {
478   std::vector<const T*> cptr_vec;
479   for (auto &e : nc_vector) {
480     cptr_vec.emplace_back(&e);
481   }
482   return cptr_vec;
483 }
484 
FixupRemovedFieldTypeIds(const std::vector<const RecordFieldIR * > & removed_fields,const AbiElementMap<const TypeIR * > & old_types)485 static std::vector<RecordFieldIR> FixupRemovedFieldTypeIds(
486     const std::vector<const RecordFieldIR *> &removed_fields,
487     const AbiElementMap<const TypeIR *> &old_types) {
488   std::vector<RecordFieldIR> removed_fields_dup;
489   for (auto &removed_field : removed_fields) {
490     removed_fields_dup.emplace_back(*removed_field);
491     RecordFieldIR &it = removed_fields_dup[removed_fields_dup.size() -1];
492     it.SetReferencedType(
493         ConvertTypeIdToString(old_types, it.GetReferencedType()));
494   }
495   return removed_fields_dup;
496 }
497 
498 std::vector<std::pair<RecordFieldIR, RecordFieldIR>>
FixupDiffedFieldTypeIds(const std::vector<RecordFieldDiffIR> & field_diffs)499 AbiDiffHelper::FixupDiffedFieldTypeIds(
500     const std::vector<RecordFieldDiffIR> &field_diffs) {
501   std::vector<std::pair<RecordFieldIR, RecordFieldIR>>
502       diffed_fields_dup;
503   for (auto &field_diff : field_diffs) {
504     diffed_fields_dup.emplace_back(*(field_diff.old_field_),
505                                    *(field_diff.new_field_));
506     auto &it = diffed_fields_dup[diffed_fields_dup.size() - 1];
507     RecordFieldIR &old_field = it.first;
508     RecordFieldIR &new_field = it.second;
509     old_field.SetReferencedType(
510         ConvertTypeIdToString(old_types_, old_field.GetReferencedType()));
511     new_field.SetReferencedType(
512         ConvertTypeIdToString(new_types_, new_field.GetReferencedType()));
513   }
514   return diffed_fields_dup;
515 }
516 
CompareFunctionTypes(const FunctionTypeIR * old_type,const FunctionTypeIR * new_type,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)517 DiffStatus AbiDiffHelper::CompareFunctionTypes(
518     const FunctionTypeIR *old_type,
519     const FunctionTypeIR *new_type,
520     std::deque<std::string> *type_queue,
521     DiffMessageIR::DiffKind diff_kind) {
522   DiffStatus param_diffs = CompareFunctionParameters(old_type->GetParameters(),
523                                                      new_type->GetParameters(),
524                                                      type_queue, diff_kind);
525   DiffStatus return_type_diff =
526       CompareAndDumpTypeDiff(old_type->GetReturnType(),
527                              new_type->GetReturnType(),
528                              type_queue, diff_kind);
529 
530   if (param_diffs == DiffStatus::direct_diff ||
531       return_type_diff == DiffStatus::direct_diff) {
532     return DiffStatus::direct_diff;
533   }
534 
535   if (param_diffs == DiffStatus::indirect_diff ||
536       return_type_diff == DiffStatus::indirect_diff) {
537     return DiffStatus::indirect_diff;
538   }
539 
540   return DiffStatus::no_diff;
541 }
542 
CompareRecordTypes(const RecordTypeIR * old_type,const RecordTypeIR * new_type,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)543 DiffStatus AbiDiffHelper::CompareRecordTypes(
544     const RecordTypeIR *old_type,
545     const RecordTypeIR *new_type,
546     std::deque<std::string> *type_queue,
547     DiffMessageIR::DiffKind diff_kind) {
548   auto record_type_diff_ir = std::make_unique<RecordTypeDiffIR>();
549   // Compare names.
550   if (!old_type->IsAnonymous() && !new_type->IsAnonymous() &&
551       old_type->GetUniqueId() != new_type->GetUniqueId()) {
552     // Do not dump anything since the record types themselves are fundamentally
553     // different.
554     return DiffStatus::direct_diff;
555   }
556   DiffStatus final_diff_status = DiffStatus::no_diff;
557   record_type_diff_ir->SetName(old_type->GetName());
558   if (IsAccessDownGraded(old_type->GetAccess(), new_type->GetAccess())) {
559     final_diff_status = DiffStatus::indirect_diff;
560     record_type_diff_ir->SetAccessDiff(
561         std::make_unique<AccessSpecifierDiffIR>(
562             old_type->GetAccess(), new_type->GetAccess()));
563   }
564 
565   if (!CompareSizeAndAlignment(old_type, new_type)) {
566     final_diff_status = DiffStatus::indirect_diff;
567     record_type_diff_ir->SetTypeDiff(
568         std::make_unique<TypeDiffIR>(
569             std::make_pair(old_type->GetSize(), new_type->GetSize()),
570             std::make_pair(old_type->GetAlignment(),
571                            new_type->GetAlignment())));
572   }
573   if (!CompareVTables(old_type, new_type)) {
574     final_diff_status = DiffStatus::indirect_diff;
575     record_type_diff_ir->SetVTableLayoutDiff(
576         std::make_unique<VTableLayoutDiffIR>(
577             old_type->GetVTableLayout(), new_type->GetVTableLayout()));
578   }
579   auto &old_fields_dup = old_type->GetFields();
580   auto &new_fields_dup = new_type->GetFields();
581   auto field_status_and_diffs = CompareRecordFields(
582       old_fields_dup, new_fields_dup, type_queue, diff_kind);
583   // TODO: Combine this with base class diffs as well.
584   final_diff_status = final_diff_status | field_status_and_diffs.diff_status_;
585 
586   std::vector<CXXBaseSpecifierIR> old_bases = old_type->GetBases();
587   std::vector<CXXBaseSpecifierIR> new_bases = new_type->GetBases();
588 
589   if (!CompareBaseSpecifiers(old_bases, new_bases, type_queue, diff_kind) &&
590       ir_diff_dumper_) {
591     ReplaceReferencesOtherTypeIdWithName(old_types_, old_bases);
592     ReplaceReferencesOtherTypeIdWithName(new_types_, new_bases);
593     record_type_diff_ir->SetBaseSpecifierDiffs (
594         std::make_unique<CXXBaseSpecifierDiffIR>(old_bases,
595                                                            new_bases));
596   }
597   if (ir_diff_dumper_) {
598     // Make copies of the fields removed and diffed, since we have to change
599     // type ids -> type strings.
600     std::vector<std::pair<RecordFieldIR, RecordFieldIR>> field_diff_dups =
601         FixupDiffedFieldTypeIds(field_status_and_diffs.diffed_fields_);
602     std::vector<RecordFieldDiffIR> field_diffs_fixed =
603         ConvertToDiffContainerVector<RecordFieldDiffIR,
604                                      RecordFieldIR>(field_diff_dups);
605 
606     std::vector<RecordFieldIR> field_removed_dups =
607         FixupRemovedFieldTypeIds(field_status_and_diffs.removed_fields_,
608                                  old_types_);
609     std::vector<const RecordFieldIR *> fields_removed_fixed =
610         ConvertToConstPtrVector(field_removed_dups);
611 
612     std::vector<RecordFieldIR> field_added_dups =
613         FixupRemovedFieldTypeIds(field_status_and_diffs.added_fields_,
614                                  new_types_);
615     std::vector<const RecordFieldIR *> fields_added_fixed =
616         ConvertToConstPtrVector(field_added_dups);
617 
618     record_type_diff_ir->SetFieldDiffs(std::move(field_diffs_fixed));
619     record_type_diff_ir->SetFieldsRemoved(std::move(fields_removed_fixed));
620     record_type_diff_ir->SetFieldsAdded(std::move(fields_added_fixed));
621 
622     if (record_type_diff_ir->DiffExists() &&
623         !ir_diff_dumper_->AddDiffMessageIR(record_type_diff_ir.get(),
624                                            Unwind(type_queue), diff_kind)) {
625       llvm::errs() << "AddDiffMessage on record type failed\n";
626       ::exit(1);
627     }
628   }
629 
630   final_diff_status = final_diff_status |
631       CompareTemplateInfo(old_type->GetTemplateElements(),
632                           new_type->GetTemplateElements(),
633                           type_queue, diff_kind);
634 
635   // Records cannot be 'extended' compatibly, without a certain amount of risk.
636   return ((final_diff_status &
637            (DiffStatus::direct_diff | DiffStatus::indirect_diff)) ?
638           DiffStatus::indirect_diff : DiffStatus::no_diff);
639 }
640 
CompareLvalueReferenceTypes(const LvalueReferenceTypeIR * old_type,const LvalueReferenceTypeIR * new_type,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)641 DiffStatus AbiDiffHelper::CompareLvalueReferenceTypes(
642     const LvalueReferenceTypeIR *old_type,
643     const LvalueReferenceTypeIR *new_type,
644     std::deque<std::string> *type_queue,
645     DiffMessageIR::DiffKind diff_kind) {
646   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
647                                 new_type->GetReferencedType(),
648                                 type_queue, diff_kind);
649 }
650 
CompareRvalueReferenceTypes(const RvalueReferenceTypeIR * old_type,const RvalueReferenceTypeIR * new_type,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)651 DiffStatus AbiDiffHelper::CompareRvalueReferenceTypes(
652     const RvalueReferenceTypeIR *old_type,
653     const RvalueReferenceTypeIR *new_type,
654     std::deque<std::string> *type_queue,
655     DiffMessageIR::DiffKind diff_kind) {
656   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
657                                 new_type->GetReferencedType(),
658                                 type_queue, diff_kind);
659 }
660 
CompareQualifiedTypes(const QualifiedTypeIR * old_type,const QualifiedTypeIR * new_type,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)661 DiffStatus AbiDiffHelper::CompareQualifiedTypes(
662     const QualifiedTypeIR *old_type,
663     const QualifiedTypeIR *new_type,
664     std::deque<std::string> *type_queue,
665     DiffMessageIR::DiffKind diff_kind) {
666   // If all the qualifiers are not the same, return direct_diff, else
667   // recursively compare the unqualified types.
668   if (old_type->IsConst() != new_type->IsConst() ||
669       old_type->IsVolatile() != new_type->IsVolatile() ||
670       old_type->IsRestricted() != new_type->IsRestricted()) {
671     return DiffStatus::direct_diff;
672   }
673   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
674                                 new_type->GetReferencedType(),
675                                 type_queue, diff_kind);
676 }
677 
ComparePointerTypes(const PointerTypeIR * old_type,const PointerTypeIR * new_type,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)678 DiffStatus AbiDiffHelper::ComparePointerTypes(
679     const PointerTypeIR *old_type,
680     const PointerTypeIR *new_type,
681     std::deque<std::string> *type_queue,
682     DiffMessageIR::DiffKind diff_kind) {
683   // The following need to be the same for two pointer types to be considered
684   // equivalent:
685   // 1) Number of pointer indirections are the same.
686   // 2) The ultimate pointee is the same.
687   assert(CompareSizeAndAlignment(old_type, new_type));
688   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
689                                 new_type->GetReferencedType(),
690                                 type_queue, diff_kind);
691 }
692 
CompareBuiltinTypes(const BuiltinTypeIR * old_type,const BuiltinTypeIR * new_type)693 DiffStatus AbiDiffHelper::CompareBuiltinTypes(
694     const BuiltinTypeIR *old_type,
695     const BuiltinTypeIR *new_type) {
696   // If the size, alignment and is_unsigned are the same, return no_diff
697   // else return direct_diff.
698   if (!CompareSizeAndAlignment(old_type, new_type) ||
699       old_type->IsUnsigned() != new_type->IsUnsigned() ||
700       old_type->IsIntegralType() != new_type->IsIntegralType()) {
701     return DiffStatus::direct_diff;
702   }
703   return DiffStatus::no_diff;
704 }
705 
CompareFunctionParameters(const std::vector<ParamIR> & old_parameters,const std::vector<ParamIR> & new_parameters,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)706 DiffStatus AbiDiffHelper::CompareFunctionParameters(
707     const std::vector<ParamIR> &old_parameters,
708     const std::vector<ParamIR> &new_parameters,
709     std::deque<std::string> *type_queue,
710     DiffMessageIR::DiffKind diff_kind) {
711   size_t old_parameters_size = old_parameters.size();
712   if (old_parameters_size != new_parameters.size()) {
713     return DiffStatus::direct_diff;
714   }
715   uint64_t i = 0;
716   while (i < old_parameters_size) {
717     const ParamIR &old_parameter = old_parameters.at(i);
718     const ParamIR &new_parameter = new_parameters.at(i);
719     if ((CompareAndDumpTypeDiff(old_parameter.GetReferencedType(),
720                                new_parameter.GetReferencedType(),
721                                type_queue, diff_kind) ==
722         DiffStatus::direct_diff) ||
723         (old_parameter.GetIsDefault() != new_parameter.GetIsDefault())) {
724       return DiffStatus::direct_diff;
725     }
726     i++;
727   }
728   return DiffStatus::no_diff;
729 }
730 
CompareAndDumpTypeDiff(const TypeIR * old_type,const TypeIR * new_type,LinkableMessageKind kind,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)731 DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff(
732     const TypeIR *old_type, const TypeIR *new_type,
733     LinkableMessageKind kind, std::deque<std::string> *type_queue,
734     DiffMessageIR::DiffKind diff_kind) {
735   if (kind == LinkableMessageKind::BuiltinTypeKind) {
736     return CompareBuiltinTypes(
737         static_cast<const BuiltinTypeIR *>(old_type),
738         static_cast<const BuiltinTypeIR *>(new_type));
739   }
740 
741   if (kind == LinkableMessageKind::QualifiedTypeKind) {
742     return CompareQualifiedTypes(
743         static_cast<const QualifiedTypeIR *>(old_type),
744         static_cast<const QualifiedTypeIR *>(new_type),
745         type_queue, diff_kind);
746   }
747 
748   if (kind == LinkableMessageKind::EnumTypeKind) {
749     return CompareEnumTypes(
750         static_cast<const EnumTypeIR *>(old_type),
751         static_cast<const EnumTypeIR *>(new_type),
752         type_queue, diff_kind);
753   }
754 
755   if (kind == LinkableMessageKind::LvalueReferenceTypeKind) {
756     return CompareLvalueReferenceTypes(
757         static_cast<const LvalueReferenceTypeIR *>(old_type),
758         static_cast<const LvalueReferenceTypeIR *>(new_type),
759         type_queue, diff_kind);
760   }
761 
762   if (kind == LinkableMessageKind::RvalueReferenceTypeKind) {
763     return CompareRvalueReferenceTypes(
764         static_cast<const RvalueReferenceTypeIR *>(old_type),
765         static_cast<const RvalueReferenceTypeIR *>(new_type),
766         type_queue, diff_kind);
767   }
768 
769   if (kind == LinkableMessageKind::PointerTypeKind) {
770     return ComparePointerTypes(
771         static_cast<const PointerTypeIR *>(old_type),
772         static_cast<const PointerTypeIR *>(new_type),
773         type_queue, diff_kind);
774   }
775 
776   if (kind == LinkableMessageKind::RecordTypeKind) {
777     return CompareRecordTypes(
778         static_cast<const RecordTypeIR *>(old_type),
779         static_cast<const RecordTypeIR *>(new_type),
780         type_queue, diff_kind);
781   }
782 
783   if (kind == LinkableMessageKind::FunctionTypeKind) {
784     return CompareFunctionTypes(
785         static_cast<const FunctionTypeIR *>(old_type),
786         static_cast<const FunctionTypeIR *>(new_type),
787         type_queue, diff_kind);
788   }
789   return DiffStatus::no_diff;
790 }
791 
CompareDistinctKindMessages(const TypeIR * old_type,const TypeIR * new_type)792 static DiffStatus CompareDistinctKindMessages(
793     const TypeIR *old_type, const TypeIR *new_type) {
794   // For these types to be considered ABI compatible, the very least requirement
795   // is that their sizes and alignments should be equal.
796   // TODO: Fill in
797   return DiffStatus::direct_diff;
798 }
799 
CompareAndDumpTypeDiff(const std::string & old_type_id,const std::string & new_type_id,std::deque<std::string> * type_queue,DiffMessageIR::DiffKind diff_kind)800 DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff(
801     const std::string &old_type_id, const std::string &new_type_id,
802     std::deque<std::string> *type_queue,
803     DiffMessageIR::DiffKind diff_kind) {
804   // Check the map for type ids which have already been compared
805   // These types have already been diffed, return without further comparison.
806   if (!type_cache_->insert(old_type_id + new_type_id).second) {
807     return DiffStatus::no_diff;
808   }
809 
810   TypeQueueCheckAndPushBack(
811       type_queue, ConvertTypeIdToString(old_types_,old_type_id));
812 
813   AbiElementMap<const TypeIR *>::const_iterator old_it =
814       old_types_.find(old_type_id);
815   AbiElementMap<const TypeIR *>::const_iterator new_it =
816       new_types_.find(new_type_id);
817 
818   if (old_it == old_types_.end() || new_it == new_types_.end()) {
819     TypeQueueCheckAndPop(type_queue);
820     // One of the types were hidden, we cannot compare further.
821     if (diff_policy_options_.consider_opaque_types_different_) {
822       return DiffStatus::opaque_diff;
823     }
824     return DiffStatus::no_diff;
825   }
826 
827   LinkableMessageKind old_kind = old_it->second->GetKind();
828   LinkableMessageKind new_kind = new_it->second->GetKind();
829   DiffStatus diff_status = DiffStatus::no_diff;
830   if (old_kind != new_kind) {
831     diff_status = CompareDistinctKindMessages(old_it->second, new_it->second);
832   } else {
833     diff_status = CompareAndDumpTypeDiff(old_it->second , new_it->second ,
834                                          old_kind, type_queue, diff_kind);
835   }
836 
837   TypeQueueCheckAndPop(type_queue);
838 
839   if (diff_policy_options_.consider_opaque_types_different_ &&
840       diff_status == DiffStatus::opaque_diff) {
841     // If `-considered-opaque-types-different` is specified and the comparison
842     // of `referenced_type` results in `opaque_diff`, then check the type name
843     // at this level.
844     return (old_it->second->GetName() == new_it->second->GetName() ?
845             DiffStatus::no_diff : DiffStatus::direct_diff);
846   }
847 
848   return diff_status;
849 }
850 
851 
852 }  // namespace repr
853 }  // namespace header_checker
854