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->GetLinkerSetKey() != new_type->GetLinkerSetKey()) {
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->GetLinkerSetKey() != new_type->GetLinkerSetKey()) {
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