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 <android-base/strings.h>
20 #include <llvm/Support/raw_ostream.h>
21
22 #include <unordered_set>
23
24
25 namespace header_checker {
26 namespace repr {
27
28
ConvertTypeIdToString(const AbiElementMap<const TypeIR * > & type_graph,const std::string & type_id)29 static std::string ConvertTypeIdToString(
30 const AbiElementMap<const TypeIR *> &type_graph,
31 const std::string &type_id) {
32 auto it = type_graph.find(type_id);
33 if (it != type_graph.end()) {
34 return it->second->GetName();
35 }
36 return "type-unexported";
37 }
38
39 template <typename Container>
ReplaceReferencesOtherTypeIdWithName(const AbiElementMap<const TypeIR * > & type_graph,Container & to_fix_elements)40 static void ReplaceReferencesOtherTypeIdWithName(
41 const AbiElementMap<const TypeIR *> &type_graph,
42 Container &to_fix_elements) {
43 for (auto &element : to_fix_elements) {
44 element.SetReferencedType(
45 ConvertTypeIdToString(type_graph, element.GetReferencedType()));
46 }
47 }
48
ReplaceEnumTypeIRTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,EnumTypeIR * enum_type_ir)49 static void ReplaceEnumTypeIRTypeIdsWithTypeNames(
50 const AbiElementMap<const TypeIR *> &type_graph, EnumTypeIR *enum_type_ir) {
51 // Replace underlying type.
52 enum_type_ir->SetUnderlyingType(
53 ConvertTypeIdToString(type_graph, enum_type_ir->GetUnderlyingType()));
54 }
55
ReplaceRecordTypeIRTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,RecordTypeIR * record_type_ir)56 static void ReplaceRecordTypeIRTypeIdsWithTypeNames(
57 const AbiElementMap<const TypeIR *> &type_graph,
58 RecordTypeIR *record_type_ir) {
59 // Replace Fields
60 ReplaceReferencesOtherTypeIdWithName(type_graph,
61 record_type_ir->GetFields());
62 // Replace template parameters
63 ReplaceReferencesOtherTypeIdWithName(type_graph,
64 record_type_ir->GetTemplateElements());
65 // Replace bases
66 ReplaceReferencesOtherTypeIdWithName(type_graph,
67 record_type_ir->GetBases());
68 }
69
ReplaceGlobalVarTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,GlobalVarIR * global_var_ir)70 static void ReplaceGlobalVarTypeIdsWithTypeNames(
71 const AbiElementMap<const TypeIR *> &type_graph,
72 GlobalVarIR *global_var_ir) {
73 // Replace referenced type id.
74 global_var_ir->SetReferencedType(
75 ConvertTypeIdToString(type_graph, global_var_ir->GetReferencedType()));
76 }
77
ReplaceFunctionTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,FunctionIR * function_ir)78 static void ReplaceFunctionTypeIdsWithTypeNames(
79 const AbiElementMap<const TypeIR *> &type_graph, FunctionIR *function_ir) {
80 // Replace return type
81 function_ir->SetReturnType(
82 ConvertTypeIdToString(type_graph, function_ir->GetReturnType()));
83 // Replace function parameters
84 ReplaceReferencesOtherTypeIdWithName(type_graph,
85 function_ir->GetParameters());
86 // Replace function template parameters
87 ReplaceReferencesOtherTypeIdWithName(type_graph,
88 function_ir->GetTemplateElements());
89 }
90
ReplaceTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,LinkableMessageIR * lm)91 void ReplaceTypeIdsWithTypeNames(
92 const AbiElementMap<const TypeIR *> &type_graph,
93 LinkableMessageIR *lm) {
94 switch (lm->GetKind()) {
95 case FunctionKind:
96 ReplaceFunctionTypeIdsWithTypeNames(
97 type_graph, static_cast<FunctionIR *>(lm));
98 break;
99 case GlobalVarKind:
100 ReplaceGlobalVarTypeIdsWithTypeNames(
101 type_graph, static_cast<GlobalVarIR *>(lm));
102 break;
103 case RecordTypeKind:
104 ReplaceRecordTypeIRTypeIdsWithTypeNames(
105 type_graph, static_cast<RecordTypeIR *>(lm));
106 break;
107 case EnumTypeKind:
108 ReplaceEnumTypeIRTypeIdsWithTypeNames(
109 type_graph, static_cast<EnumTypeIR *>(lm));
110 break;
111 default:
112 // This method should not be called on any other LinkableMessage
113 assert(0);
114 }
115 }
116
UnwindTypeStack()117 std::string AbiDiffHelper::UnwindTypeStack() {
118 return android::base::Join(type_stack_, "-> ");
119 }
120
CompareEnumFields(const std::vector<EnumFieldIR> & old_fields,const std::vector<EnumFieldIR> & new_fields,EnumTypeDiffIR * enum_type_diff_ir)121 void AbiDiffHelper::CompareEnumFields(
122 const std::vector<EnumFieldIR> &old_fields,
123 const std::vector<EnumFieldIR> &new_fields,
124 EnumTypeDiffIR *enum_type_diff_ir) {
125 AbiElementMap<const EnumFieldIR *> old_fields_map;
126 AbiElementMap<const EnumFieldIR *> new_fields_map;
127 utils::AddToMap(&old_fields_map, old_fields,
128 [](const EnumFieldIR *f) {return f->GetName();},
129 [](const EnumFieldIR *f) {return f;});
130
131 utils::AddToMap(&new_fields_map, new_fields,
132 [](const EnumFieldIR *f) {return f->GetName();},
133 [](const EnumFieldIR *f) {return f;});
134
135 std::vector<const EnumFieldIR *> removed_fields =
136 utils::FindRemovedElements(old_fields_map, new_fields_map);
137
138 std::vector<const EnumFieldIR *> added_fields =
139 utils::FindRemovedElements(new_fields_map, old_fields_map);
140
141 enum_type_diff_ir->SetFieldsAdded(std::move(added_fields));
142
143 enum_type_diff_ir->SetFieldsRemoved(std::move(removed_fields));
144
145 std::vector<std::pair<const EnumFieldIR *,
146 const EnumFieldIR *>> cf =
147 utils::FindCommonElements(old_fields_map, new_fields_map);
148 std::vector<EnumFieldDiffIR> enum_field_diffs;
149 for (auto &&common_fields : cf) {
150 if (common_fields.first->GetSignedValue() !=
151 common_fields.second->GetSignedValue()) {
152 EnumFieldDiffIR enum_field_diff_ir(common_fields.first,
153 common_fields.second);
154 enum_field_diffs.emplace_back(std::move(enum_field_diff_ir));
155 }
156 }
157 enum_type_diff_ir->SetFieldsDiff(std::move(enum_field_diffs));
158 }
159
CompareEnumTypes(const EnumTypeIR * old_type,const EnumTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)160 DiffStatus AbiDiffHelper::CompareEnumTypes(const EnumTypeIR *old_type,
161 const EnumTypeIR *new_type,
162 DiffMessageIR::DiffKind diff_kind) {
163 if (old_type->GetLinkerSetKey() != new_type->GetLinkerSetKey()) {
164 return DiffStatus::kDirectDiff;
165 }
166 auto enum_type_diff_ir = std::make_unique<EnumTypeDiffIR>();
167 enum_type_diff_ir->SetName(old_type->GetName());
168 enum_type_diff_ir->SetLinkerSetKey(old_type->GetLinkerSetKey());
169 const std::string &old_underlying_type =
170 ConvertTypeIdToString(old_types_, old_type->GetUnderlyingType());
171 const std::string &new_underlying_type =
172 ConvertTypeIdToString(new_types_, new_type->GetUnderlyingType());
173 if (old_underlying_type != new_underlying_type) {
174 enum_type_diff_ir->SetUnderlyingTypeDiff(
175 std::make_unique<std::pair<std::string, std::string>>(
176 old_underlying_type, new_underlying_type));
177 }
178 CompareEnumFields(old_type->GetFields(), new_type->GetFields(),
179 enum_type_diff_ir.get());
180 if ((enum_type_diff_ir->IsExtended() ||
181 enum_type_diff_ir->IsIncompatible()) &&
182 (ir_diff_dumper_ &&
183 !ir_diff_dumper_->AddDiffMessageIR(enum_type_diff_ir.get(),
184 UnwindTypeStack(), diff_kind))) {
185 llvm::errs() << "AddDiffMessage on EnumTypeDiffIR failed\n";
186 ::exit(1);
187 }
188 return DiffStatus::kNoDiff;
189 }
190
RemoveThunkInfoFromMangledName(const std::string & name)191 static std::string RemoveThunkInfoFromMangledName(const std::string &name) {
192 if (name.find("_ZTv") != 0 && name.find("_ZTh") != 0 &&
193 name.find("_ZTc") != 0) {
194 return name;
195 }
196 size_t base_name_pos = name.find("N");
197 if (base_name_pos == std::string::npos) {
198 return name;
199 }
200 return "_Z" + name.substr(base_name_pos);
201 }
202
CompareVTableComponents(const VTableComponentIR & old_component,const VTableComponentIR & new_component)203 static bool CompareVTableComponents(const VTableComponentIR &old_component,
204 const VTableComponentIR &new_component) {
205 // Vtable components in prebuilts/abi-dumps/vndk/28 don't have thunk info.
206 if (old_component.GetName() != new_component.GetName()) {
207 if (RemoveThunkInfoFromMangledName(old_component.GetName()) ==
208 RemoveThunkInfoFromMangledName(new_component.GetName())) {
209 llvm::errs() << "WARNING: Ignore difference between "
210 << old_component.GetName() << " and "
211 << new_component.GetName() << "\n";
212 } else {
213 return false;
214 }
215 }
216 return old_component.GetValue() == new_component.GetValue() &&
217 old_component.GetKind() == new_component.GetKind();
218 }
219
CompareVTables(const std::vector<VTableComponentIR> & old_components,const std::vector<VTableComponentIR> & new_components)220 static bool CompareVTables(
221 const std::vector<VTableComponentIR> &old_components,
222 const std::vector<VTableComponentIR> &new_components) {
223 if (old_components.size() != new_components.size()) {
224 return false;
225 }
226 for (size_t i = 0; i < old_components.size(); i++) {
227 if (!CompareVTableComponents(old_components[i], new_components[i])) {
228 return false;
229 }
230 }
231 return true;
232 }
233
IsVOffset(VTableComponentIR::Kind kind)234 static inline bool IsVOffset(VTableComponentIR::Kind kind) {
235 return kind == VTableComponentIR::VBaseOffset ||
236 kind == VTableComponentIR::VCallOffset;
237 }
238
IsFunctionPointer(VTableComponentIR::Kind kind)239 static inline bool IsFunctionPointer(VTableComponentIR::Kind kind) {
240 return kind == VTableComponentIR::FunctionPointer ||
241 kind == VTableComponentIR::CompleteDtorPointer ||
242 kind == VTableComponentIR::DeletingDtorPointer;
243 }
244
245 // A Vtable consists of one or more sub-vtables. Each sub-vtable is a sequence
246 // of components in the following order:
247 // Zero or more VCallOffset or VBaseOffset.
248 // One OffsetToTop.
249 // One RTTI.
250 // Zero or more FunctionPointer, CompleteDtorPointer, or DeletingDtorPointer.
251 //
252 // An object's vtable pointer points to the next component of the RTTI
253 // component. Hence, new components can be appended or prepended to sub-vtables
254 // without breaking compatibility.
IsVTableExtended(const std::vector<VTableComponentIR> & old_components,const std::vector<VTableComponentIR> & new_components)255 static bool IsVTableExtended(
256 const std::vector<VTableComponentIR> &old_components,
257 const std::vector<VTableComponentIR> &new_components) {
258 const auto old_end = old_components.end();
259 const auto new_end = new_components.end();
260 auto old_it = old_components.begin();
261 auto new_it = new_components.begin();
262 bool is_extended = false;
263 while (old_it != old_end) {
264 const auto old_begin = old_it;
265 const auto new_begin = new_it;
266 // Iterate VCallOffset and VBaseOffset.
267 while (old_it != old_end && IsVOffset(old_it->GetKind())) {
268 old_it++;
269 }
270 while (new_it != new_end && IsVOffset(new_it->GetKind())) {
271 new_it++;
272 }
273 // Compare VCallOffset and VBaseOffset.
274 auto old_back_it = old_it;
275 auto new_back_it = new_it;
276 while (old_back_it != old_begin) {
277 if (new_back_it == new_begin) {
278 return false;
279 }
280 old_back_it--;
281 new_back_it--;
282 if (old_back_it->GetKind() != new_back_it->GetKind()) {
283 return false;
284 }
285 }
286 // The new sub-vtable has additional VOffsets at the beginning.
287 if (new_back_it != new_begin) {
288 is_extended = true;
289 }
290 // Compare OffsetToTop.
291 if (old_it == old_end || new_it == new_end ||
292 old_it->GetKind() != VTableComponentIR::OffsetToTop ||
293 new_it->GetKind() != VTableComponentIR::OffsetToTop) {
294 return false;
295 }
296 old_it++;
297 new_it++;
298 // Compare RTTI.
299 if (old_it == old_end || new_it == new_end ||
300 old_it->GetKind() != VTableComponentIR::RTTI ||
301 new_it->GetKind() != VTableComponentIR::RTTI ||
302 old_it->GetName() != new_it->GetName()) {
303 return false;
304 }
305 old_it++;
306 new_it++;
307 // Compare function pointers.
308 while (old_it != old_end && IsFunctionPointer(old_it->GetKind())) {
309 if (new_it == new_end || old_it->GetKind() != new_it->GetKind() ||
310 old_it->GetName() != new_it->GetName()) {
311 return false;
312 }
313 old_it++;
314 new_it++;
315 }
316 // The new sub-vtable has additional function pointers at the end.
317 while (new_it != new_end && IsFunctionPointer(new_it->GetKind())) {
318 is_extended = true;
319 new_it++;
320 }
321 }
322 return new_it == new_end ? is_extended : false;
323 }
324
AreOpaqueTypesEqual(const std::string & old_type_id,const std::string & new_type_id) const325 bool AbiDiffHelper::AreOpaqueTypesEqual(const std::string &old_type_id,
326 const std::string &new_type_id) const {
327 // b/253095767: In T, some dump files contain opaque types whose IDs end with
328 // "#ODR:" and the source paths. This function removes the suffixes before
329 // comparing the type IDs.
330 if (!diff_policy_options_.consider_opaque_types_different_ ||
331 ExtractMultiDefinitionTypeId(old_type_id) ==
332 ExtractMultiDefinitionTypeId(new_type_id)) {
333 return true;
334 }
335 // __va_list is an opaque type defined by the compiler. ARM ABI requires
336 // __va_list to be in std namespace. Its mangled name is _ZTISt9__va_list, but
337 // some versions of clang produce _ZTI9__va_list. The names are equivalent.
338 static const std::unordered_set<std::string> va_list_names{
339 "_ZTI9__va_list", "_ZTISt9__va_list"};
340 return va_list_names.count(old_type_id) && va_list_names.count(new_type_id);
341 }
342
CompareSizeAndAlignment(const TypeIR * old_type,const TypeIR * new_type)343 static bool CompareSizeAndAlignment(const TypeIR *old_type,
344 const TypeIR *new_type) {
345 return old_type->GetSize() == new_type->GetSize() &&
346 old_type->GetAlignment() == new_type->GetAlignment();
347 }
348
CompareAccess(AccessSpecifierIR old_access,AccessSpecifierIR new_access)349 DiffStatus AbiDiffHelper::CompareAccess(AccessSpecifierIR old_access,
350 AccessSpecifierIR new_access) {
351 if (old_access == new_access) {
352 return DiffStatus::kNoDiff;
353 }
354 if (old_access > new_access) {
355 return DiffStatus::kDirectExt;
356 }
357 return DiffStatus::kDirectDiff;
358 }
359
360 // This function returns a map from field names to RecordFieldIR.
361 // It appends anonymous fields to anonymous_fields.
BuildRecordFieldNameMap(const std::vector<RecordFieldIR> & fields,std::vector<const RecordFieldIR * > & anonymous_fields)362 static AbiElementMap<const RecordFieldIR *> BuildRecordFieldNameMap(
363 const std::vector<RecordFieldIR> &fields,
364 std::vector<const RecordFieldIR *> &anonymous_fields) {
365 AbiElementMap<const RecordFieldIR *> field_map;
366 for (const RecordFieldIR &field : fields) {
367 const std::string &name = field.GetName();
368 if (name.empty()) {
369 anonymous_fields.emplace_back(&field);
370 } else {
371 field_map.emplace(name, &field);
372 }
373 }
374 return field_map;
375 }
376
CompareCommonRecordFields(const RecordFieldIR * old_field,const RecordFieldIR * new_field,DiffMessageIR::DiffKind diff_kind)377 DiffStatus AbiDiffHelper::CompareCommonRecordFields(
378 const RecordFieldIR *old_field, const RecordFieldIR *new_field,
379 DiffMessageIR::DiffKind diff_kind) {
380 DiffStatus field_diff_status =
381 CompareAndDumpTypeDiff(old_field->GetReferencedType(),
382 new_field->GetReferencedType(), diff_kind);
383 // CompareAndDumpTypeDiff should not return kDirectExt.
384 // In case it happens, report an incompatible diff for review.
385 if (field_diff_status.IsExtension() ||
386 old_field->GetOffset() != new_field->GetOffset() ||
387 old_field->IsBitField() != new_field->IsBitField() ||
388 old_field->GetBitWidth() != new_field->GetBitWidth()) {
389 field_diff_status.CombineWith(DiffStatus::kDirectDiff);
390 }
391 field_diff_status.CombineWith(
392 CompareAccess(old_field->GetAccess(), new_field->GetAccess()));
393 return field_diff_status;
394 }
395
396 // FilterOutRenamedRecordFields calls this function to compare record fields in
397 // two dumps.
398 // If this function returns 0, the fields may be compatible.
399 // If it returns -1 or 1, the fields must be incompatible.
CompareRenamedRecordFields(const RecordFieldIR * old_field,const RecordFieldIR * new_field)400 static int CompareRenamedRecordFields(const RecordFieldIR *old_field,
401 const RecordFieldIR *new_field) {
402 if (old_field->GetOffset() != new_field->GetOffset()) {
403 return old_field->GetOffset() < new_field->GetOffset() ? -1 : 1;
404 }
405 if (old_field->IsBitField() != new_field->IsBitField()) {
406 return old_field->IsBitField() < new_field->IsBitField() ? -1 : 1;
407 }
408 if (old_field->GetBitWidth() != new_field->GetBitWidth()) {
409 return old_field->GetBitWidth() < new_field->GetBitWidth() ? -1 : 1;
410 }
411 // Skip GetReferencedType because the same type in old and new dumps may have
412 // different IDs, especially in the cases of anonymous types and multiple
413 // definitions.
414 return 0;
415 }
416
417 // This function filters out the pairs of old and new fields that meet the
418 // following conditions:
419 // The old field's (offset, bit width, type) is unique in old_fields.
420 // The new field's (offset, bit width, type) is unique in new_fields.
421 // The two fields have compatible attributes except the name.
422 //
423 // This function returns either kNoDiff or kIndirectDiff. It is the status of
424 // the field pairs that are filtered out.
FilterOutRenamedRecordFields(DiffMessageIR::DiffKind diff_kind,std::vector<const RecordFieldIR * > & old_fields,std::vector<const RecordFieldIR * > & new_fields)425 DiffStatus AbiDiffHelper::FilterOutRenamedRecordFields(
426 DiffMessageIR::DiffKind diff_kind,
427 std::vector<const RecordFieldIR *> &old_fields,
428 std::vector<const RecordFieldIR *> &new_fields) {
429 DiffStatus diff_status = DiffStatus::kNoDiff;
430 const auto old_end = old_fields.end();
431 const auto new_end = new_fields.end();
432 // Sort fields by (offset, bit width, type).
433 auto is_less = [](const RecordFieldIR *first, const RecordFieldIR *second) {
434 int result = CompareRenamedRecordFields(first, second);
435 return result != 0
436 ? result < 0
437 : first->GetReferencedType() < second->GetReferencedType();
438 };
439 std::sort(old_fields.begin(), old_end, is_less);
440 std::sort(new_fields.begin(), new_end, is_less);
441
442 std::vector<const RecordFieldIR *> out_old_fields;
443 std::vector<const RecordFieldIR *> out_new_fields;
444 auto old_it = old_fields.begin();
445 auto new_it = new_fields.begin();
446 while (old_it != old_end && new_it != new_end) {
447 int old_new_cmp = CompareRenamedRecordFields(*old_it, *new_it);
448 auto next_old_it = std::next(old_it);
449 while (next_old_it != old_end && !is_less(*old_it, *next_old_it)) {
450 next_old_it++;
451 }
452 if (old_new_cmp < 0 || next_old_it - old_it > 1) {
453 out_old_fields.insert(out_old_fields.end(), old_it, next_old_it);
454 old_it = next_old_it;
455 continue;
456 }
457
458 auto next_new_it = std::next(new_it);
459 while (next_new_it != new_end && !is_less(*new_it, *next_new_it)) {
460 next_new_it++;
461 }
462 if (old_new_cmp > 0 || next_new_it - new_it > 1) {
463 out_new_fields.insert(out_new_fields.end(), new_it, next_new_it);
464 new_it = next_new_it;
465 continue;
466 }
467
468 DiffStatus field_diff_status =
469 CompareCommonRecordFields(*old_it, *new_it, diff_kind);
470 if (field_diff_status.IsDirectDiff()) {
471 out_old_fields.emplace_back(*old_it);
472 out_new_fields.emplace_back(*new_it);
473 } else {
474 diff_status.CombineWith(field_diff_status);
475 }
476 old_it = next_old_it;
477 new_it = next_new_it;
478 }
479 out_old_fields.insert(out_old_fields.end(), old_it, old_end);
480 out_new_fields.insert(out_new_fields.end(), new_it, new_end);
481
482 old_fields = std::move(out_old_fields);
483 new_fields = std::move(out_new_fields);
484 return diff_status;
485 }
486
CompareRecordFields(const std::vector<RecordFieldIR> & old_fields,const std::vector<RecordFieldIR> & new_fields,DiffMessageIR::DiffKind diff_kind)487 RecordFieldDiffResult AbiDiffHelper::CompareRecordFields(
488 const std::vector<RecordFieldIR> &old_fields,
489 const std::vector<RecordFieldIR> &new_fields,
490 DiffMessageIR::DiffKind diff_kind) {
491 RecordFieldDiffResult result;
492 DiffStatus &diff_status = result.status;
493 diff_status = DiffStatus::kNoDiff;
494 AbiElementMap<const RecordFieldIR *> old_fields_map =
495 BuildRecordFieldNameMap(old_fields, result.removed_fields);
496 AbiElementMap<const RecordFieldIR *> new_fields_map =
497 BuildRecordFieldNameMap(new_fields, result.added_fields);
498
499 // Compare the anonymous fields and the fields whose names are not present in
500 // both records.
501 utils::InsertAll(result.removed_fields,
502 utils::FindRemovedElements(old_fields_map, new_fields_map));
503 utils::InsertAll(result.added_fields,
504 utils::FindRemovedElements(new_fields_map, old_fields_map));
505 diff_status.CombineWith(FilterOutRenamedRecordFields(
506 diff_kind, result.removed_fields, result.added_fields));
507 if (result.removed_fields.size() != 0) {
508 diff_status.CombineWith(DiffStatus::kDirectDiff);
509 }
510 if (result.added_fields.size() != 0) {
511 diff_status.CombineWith(DiffStatus::kDirectExt);
512 }
513 // Compare the fields whose names are present in both records.
514 std::vector<std::pair<const RecordFieldIR *, const RecordFieldIR *>> cf =
515 utils::FindCommonElements(old_fields_map, new_fields_map);
516 for (auto &&common_fields : cf) {
517 DiffStatus field_diff_status = CompareCommonRecordFields(
518 common_fields.first, common_fields.second, diff_kind);
519 diff_status.CombineWith(field_diff_status);
520 if (field_diff_status.IsDirectDiff()) {
521 result.diffed_fields.emplace_back(common_fields.first,
522 common_fields.second);
523 }
524 }
525 return result;
526 }
527
CompareBaseSpecifiers(const std::vector<CXXBaseSpecifierIR> & old_base_specifiers,const std::vector<CXXBaseSpecifierIR> & new_base_specifiers,DiffMessageIR::DiffKind diff_kind)528 bool AbiDiffHelper::CompareBaseSpecifiers(
529 const std::vector<CXXBaseSpecifierIR> &old_base_specifiers,
530 const std::vector<CXXBaseSpecifierIR> &new_base_specifiers,
531 DiffMessageIR::DiffKind diff_kind) {
532 if (old_base_specifiers.size() != new_base_specifiers.size()) {
533 return false;
534 }
535 int i = 0;
536 while (i < old_base_specifiers.size()) {
537 if (CompareAndDumpTypeDiff(old_base_specifiers.at(i).GetReferencedType(),
538 new_base_specifiers.at(i).GetReferencedType(),
539 diff_kind)
540 .IsDirectDiff() ||
541 (old_base_specifiers.at(i).GetAccess() !=
542 new_base_specifiers.at(i).GetAccess())) {
543 return false;
544 }
545 i++;
546 }
547 return true;
548 }
549
CompareTemplateInfo(const std::vector<TemplateElementIR> & old_template_elements,const std::vector<TemplateElementIR> & new_template_elements,DiffMessageIR::DiffKind diff_kind)550 DiffStatus AbiDiffHelper::CompareTemplateInfo(
551 const std::vector<TemplateElementIR> &old_template_elements,
552 const std::vector<TemplateElementIR> &new_template_elements,
553 DiffMessageIR::DiffKind diff_kind) {
554 uint32_t old_template_size = old_template_elements.size();
555 uint32_t i = 0;
556 if (old_template_size != new_template_elements.size()) {
557 return DiffStatus::kDirectDiff;
558 }
559 DiffStatus final_diff_status = DiffStatus::kNoDiff;
560 while (i < old_template_size) {
561 const TemplateElementIR &old_template_element =
562 old_template_elements[i];
563 const TemplateElementIR &new_template_element =
564 new_template_elements[i];
565 auto template_element_diff = CompareAndDumpTypeDiff(
566 old_template_element.GetReferencedType(),
567 new_template_element.GetReferencedType(), diff_kind);
568 if (template_element_diff.HasDiff()) {
569 final_diff_status.CombineWith(template_element_diff);
570 }
571 i++;
572 }
573 return final_diff_status;
574 }
575
576 template <typename DiffContainer, typename T>
ConvertToDiffContainerVector(std::vector<std::pair<T,T>> & nc_vector)577 static std::vector<DiffContainer> ConvertToDiffContainerVector(
578 std::vector<std::pair<T, T>> &nc_vector) {
579 std::vector<DiffContainer> cptr_vec;
580 for (auto &e : nc_vector) {
581 cptr_vec.emplace_back(&e.first, &e.second);
582 }
583 return cptr_vec;
584 }
585
586 template <typename T>
ConvertToConstPtrVector(std::vector<T> & nc_vector)587 static std::vector<const T*> ConvertToConstPtrVector(
588 std::vector<T> &nc_vector) {
589 std::vector<const T*> cptr_vec;
590 for (auto &e : nc_vector) {
591 cptr_vec.emplace_back(&e);
592 }
593 return cptr_vec;
594 }
595
FixupRemovedFieldTypeIds(const std::vector<const RecordFieldIR * > & removed_fields,const AbiElementMap<const TypeIR * > & old_types)596 static std::vector<RecordFieldIR> FixupRemovedFieldTypeIds(
597 const std::vector<const RecordFieldIR *> &removed_fields,
598 const AbiElementMap<const TypeIR *> &old_types) {
599 std::vector<RecordFieldIR> removed_fields_dup;
600 for (auto &removed_field : removed_fields) {
601 removed_fields_dup.emplace_back(*removed_field);
602 RecordFieldIR &it = removed_fields_dup[removed_fields_dup.size() -1];
603 it.SetReferencedType(
604 ConvertTypeIdToString(old_types, it.GetReferencedType()));
605 }
606 return removed_fields_dup;
607 }
608
609 std::vector<std::pair<RecordFieldIR, RecordFieldIR>>
FixupDiffedFieldTypeIds(const std::vector<RecordFieldDiffIR> & field_diffs)610 AbiDiffHelper::FixupDiffedFieldTypeIds(
611 const std::vector<RecordFieldDiffIR> &field_diffs) {
612 std::vector<std::pair<RecordFieldIR, RecordFieldIR>>
613 diffed_fields_dup;
614 for (auto &field_diff : field_diffs) {
615 diffed_fields_dup.emplace_back(*(field_diff.old_field_),
616 *(field_diff.new_field_));
617 auto &it = diffed_fields_dup[diffed_fields_dup.size() - 1];
618 RecordFieldIR &old_field = it.first;
619 RecordFieldIR &new_field = it.second;
620 old_field.SetReferencedType(
621 ConvertTypeIdToString(old_types_, old_field.GetReferencedType()));
622 new_field.SetReferencedType(
623 ConvertTypeIdToString(new_types_, new_field.GetReferencedType()));
624 }
625 return diffed_fields_dup;
626 }
627
CompareFunctionTypes(const CFunctionLikeIR * old_type,const CFunctionLikeIR * new_type,DiffMessageIR::DiffKind diff_kind)628 DiffStatus AbiDiffHelper::CompareFunctionTypes(
629 const CFunctionLikeIR *old_type, const CFunctionLikeIR *new_type,
630 DiffMessageIR::DiffKind diff_kind) {
631 DiffStatus status = CompareFunctionParameters(
632 old_type->GetParameters(), new_type->GetParameters(), diff_kind);
633 status.CombineWith(CompareReturnTypes(old_type->GetReturnType(),
634 new_type->GetReturnType(), diff_kind));
635 return status;
636 }
637
CompareRecordTypes(const RecordTypeIR * old_type,const RecordTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)638 DiffStatus AbiDiffHelper::CompareRecordTypes(
639 const RecordTypeIR *old_type, const RecordTypeIR *new_type,
640 DiffMessageIR::DiffKind diff_kind) {
641 auto record_type_diff_ir = std::make_unique<RecordTypeDiffIR>();
642 // Compare names.
643 if (!old_type->IsAnonymous() && !new_type->IsAnonymous() &&
644 old_type->GetLinkerSetKey() != new_type->GetLinkerSetKey()) {
645 // Do not dump anything since the record types themselves are fundamentally
646 // different.
647 return DiffStatus::kDirectDiff;
648 }
649 DiffStatus final_diff_status = DiffStatus::kNoDiff;
650 record_type_diff_ir->SetName(old_type->GetName());
651 record_type_diff_ir->SetLinkerSetKey(old_type->GetLinkerSetKey());
652
653 DiffStatus access_diff_status =
654 CompareAccess(old_type->GetAccess(), new_type->GetAccess());
655 final_diff_status.CombineWith(access_diff_status);
656 if (access_diff_status.HasDiff()) {
657 record_type_diff_ir->SetAccessDiff(
658 std::make_unique<AccessSpecifierDiffIR>(
659 old_type->GetAccess(), new_type->GetAccess()));
660 }
661
662 if (!CompareSizeAndAlignment(old_type, new_type)) {
663 if (old_type->GetSize() < new_type->GetSize() &&
664 old_type->GetAlignment() == new_type->GetAlignment()) {
665 final_diff_status.CombineWith(DiffStatus::kDirectExt);
666 } else {
667 final_diff_status.CombineWith(DiffStatus::kDirectDiff);
668 }
669 record_type_diff_ir->SetTypeDiff(
670 std::make_unique<TypeDiffIR>(
671 std::make_pair(old_type->GetSize(), new_type->GetSize()),
672 std::make_pair(old_type->GetAlignment(),
673 new_type->GetAlignment())));
674 }
675
676 const std::vector<VTableComponentIR> &old_vtable =
677 old_type->GetVTableLayout().GetVTableComponents();
678 const std::vector<VTableComponentIR> &new_vtable =
679 new_type->GetVTableLayout().GetVTableComponents();
680 if (!CompareVTables(old_vtable, new_vtable)) {
681 if (IsVTableExtended(old_vtable, new_vtable)) {
682 final_diff_status.CombineWith(DiffStatus::kDirectExt);
683 } else {
684 final_diff_status.CombineWith(DiffStatus::kDirectDiff);
685 }
686 record_type_diff_ir->SetVTableLayoutDiff(
687 std::make_unique<VTableLayoutDiffIR>(
688 old_type->GetVTableLayout(), new_type->GetVTableLayout()));
689 }
690
691 auto &old_fields_dup = old_type->GetFields();
692 auto &new_fields_dup = new_type->GetFields();
693 RecordFieldDiffResult field_status_and_diffs =
694 CompareRecordFields(old_fields_dup, new_fields_dup, diff_kind);
695 final_diff_status.CombineWith(field_status_and_diffs.status);
696
697 std::vector<CXXBaseSpecifierIR> old_bases = old_type->GetBases();
698 std::vector<CXXBaseSpecifierIR> new_bases = new_type->GetBases();
699 if (!CompareBaseSpecifiers(old_bases, new_bases, diff_kind) &&
700 ir_diff_dumper_) {
701 final_diff_status.CombineWith(DiffStatus::kDirectDiff);
702 ReplaceReferencesOtherTypeIdWithName(old_types_, old_bases);
703 ReplaceReferencesOtherTypeIdWithName(new_types_, new_bases);
704 record_type_diff_ir->SetBaseSpecifierDiffs(
705 std::make_unique<CXXBaseSpecifierDiffIR>(old_bases, new_bases));
706 }
707 if (ir_diff_dumper_) {
708 // Make copies of the fields removed and diffed, since we have to change
709 // type ids -> type strings.
710 std::vector<std::pair<RecordFieldIR, RecordFieldIR>> field_diff_dups =
711 FixupDiffedFieldTypeIds(field_status_and_diffs.diffed_fields);
712 std::vector<RecordFieldDiffIR> field_diffs_fixed =
713 ConvertToDiffContainerVector<RecordFieldDiffIR,
714 RecordFieldIR>(field_diff_dups);
715
716 std::vector<RecordFieldIR> field_removed_dups = FixupRemovedFieldTypeIds(
717 field_status_and_diffs.removed_fields, old_types_);
718 std::vector<const RecordFieldIR *> fields_removed_fixed =
719 ConvertToConstPtrVector(field_removed_dups);
720
721 std::vector<RecordFieldIR> field_added_dups = FixupRemovedFieldTypeIds(
722 field_status_and_diffs.added_fields, new_types_);
723 std::vector<const RecordFieldIR *> fields_added_fixed =
724 ConvertToConstPtrVector(field_added_dups);
725
726 record_type_diff_ir->SetFieldDiffs(std::move(field_diffs_fixed));
727 record_type_diff_ir->SetFieldsRemoved(std::move(fields_removed_fixed));
728 record_type_diff_ir->SetFieldsAdded(std::move(fields_added_fixed));
729 record_type_diff_ir->SetExtended(final_diff_status.IsExtension());
730
731 if (final_diff_status.IsDirectDiff() &&
732 !ir_diff_dumper_->AddDiffMessageIR(record_type_diff_ir.get(),
733 UnwindTypeStack(), diff_kind)) {
734 llvm::errs() << "AddDiffMessage on record type failed\n";
735 ::exit(1);
736 }
737 }
738
739 final_diff_status.CombineWith(
740 CompareTemplateInfo(old_type->GetTemplateElements(),
741 new_type->GetTemplateElements(), diff_kind));
742
743 return (final_diff_status.HasDiff() ? DiffStatus::kIndirectDiff
744 : DiffStatus::kNoDiff);
745 }
746
CompareLvalueReferenceTypes(const LvalueReferenceTypeIR * old_type,const LvalueReferenceTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)747 DiffStatus AbiDiffHelper::CompareLvalueReferenceTypes(
748 const LvalueReferenceTypeIR *old_type,
749 const LvalueReferenceTypeIR *new_type, DiffMessageIR::DiffKind diff_kind) {
750 return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
751 new_type->GetReferencedType(), diff_kind);
752 }
753
CompareRvalueReferenceTypes(const RvalueReferenceTypeIR * old_type,const RvalueReferenceTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)754 DiffStatus AbiDiffHelper::CompareRvalueReferenceTypes(
755 const RvalueReferenceTypeIR *old_type,
756 const RvalueReferenceTypeIR *new_type, DiffMessageIR::DiffKind diff_kind) {
757 return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
758 new_type->GetReferencedType(), diff_kind);
759 }
760
CompareQualifiedTypes(const QualifiedTypeIR * old_type,const QualifiedTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)761 DiffStatus AbiDiffHelper::CompareQualifiedTypes(
762 const QualifiedTypeIR *old_type, const QualifiedTypeIR *new_type,
763 DiffMessageIR::DiffKind diff_kind) {
764 // If all the qualifiers are not the same, return direct_diff, else
765 // recursively compare the unqualified types.
766 if (old_type->IsConst() != new_type->IsConst() ||
767 old_type->IsVolatile() != new_type->IsVolatile() ||
768 old_type->IsRestricted() != new_type->IsRestricted()) {
769 return DiffStatus::kDirectDiff;
770 }
771 return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
772 new_type->GetReferencedType(), diff_kind);
773 }
774
CompareArrayTypes(const ArrayTypeIR * old_type,const ArrayTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)775 DiffStatus AbiDiffHelper::CompareArrayTypes(const ArrayTypeIR *old_type,
776 const ArrayTypeIR *new_type,
777 DiffMessageIR::DiffKind diff_kind) {
778 if (!CompareSizeAndAlignment(old_type, new_type) ||
779 old_type->IsOfUnknownBound() != new_type->IsOfUnknownBound()) {
780 return DiffStatus::kDirectDiff;
781 }
782 return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
783 new_type->GetReferencedType(), diff_kind);
784 }
785
ComparePointerTypes(const PointerTypeIR * old_type,const PointerTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)786 DiffStatus AbiDiffHelper::ComparePointerTypes(
787 const PointerTypeIR *old_type, const PointerTypeIR *new_type,
788 DiffMessageIR::DiffKind diff_kind) {
789 // The following need to be the same for two pointer types to be considered
790 // equivalent:
791 // 1) Number of pointer indirections are the same.
792 // 2) The ultimate pointee is the same.
793 assert(CompareSizeAndAlignment(old_type, new_type));
794 return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
795 new_type->GetReferencedType(), diff_kind);
796 }
797
CompareBuiltinTypes(const BuiltinTypeIR * old_type,const BuiltinTypeIR * new_type)798 DiffStatus AbiDiffHelper::CompareBuiltinTypes(
799 const BuiltinTypeIR *old_type,
800 const BuiltinTypeIR *new_type) {
801 // If the size, alignment and is_unsigned are the same, return no_diff
802 // else return direct_diff.
803 if (!CompareSizeAndAlignment(old_type, new_type) ||
804 old_type->IsUnsigned() != new_type->IsUnsigned() ||
805 old_type->IsIntegralType() != new_type->IsIntegralType()) {
806 return DiffStatus::kDirectDiff;
807 }
808 return DiffStatus::kNoDiff;
809 }
810
CompareFunctionParameters(const std::vector<ParamIR> & old_parameters,const std::vector<ParamIR> & new_parameters,DiffMessageIR::DiffKind diff_kind)811 DiffStatus AbiDiffHelper::CompareFunctionParameters(
812 const std::vector<ParamIR> &old_parameters,
813 const std::vector<ParamIR> &new_parameters,
814 DiffMessageIR::DiffKind diff_kind) {
815 size_t old_parameters_size = old_parameters.size();
816 if (old_parameters_size != new_parameters.size()) {
817 return DiffStatus::kDirectDiff;
818 }
819 DiffStatus result = DiffStatus::kNoDiff;
820 for (uint64_t i = 0; i < old_parameters_size; i++) {
821 const ParamIR &old_parameter = old_parameters.at(i);
822 const ParamIR &new_parameter = new_parameters.at(i);
823 result.CombineWith(CompareParameterTypes(old_parameter.GetReferencedType(),
824 new_parameter.GetReferencedType(),
825 diff_kind));
826 if (old_parameter.GetIsDefault() != new_parameter.GetIsDefault()) {
827 result.CombineWith(DiffStatus::kDirectDiff);
828 }
829 }
830 return result;
831 }
832
FindTypeById(const AbiElementMap<const TypeIR * > & type_graph,const std::string & type_id)833 static const TypeIR *FindTypeById(
834 const AbiElementMap<const TypeIR *> &type_graph,
835 const std::string &type_id) {
836 auto it = type_graph.find(type_id);
837 return it == type_graph.end() ? nullptr : it->second;
838 }
839
840 struct Qualifiers {
841 bool is_const = false;
842 bool is_restricted = false;
843 bool is_volatile = false;
844
operator ==header_checker::repr::Qualifiers845 bool operator==(const Qualifiers &other) const {
846 return (is_const == other.is_const &&
847 is_restricted == other.is_restricted &&
848 is_volatile == other.is_volatile);
849 }
850
operator !=header_checker::repr::Qualifiers851 bool operator!=(const Qualifiers &other) const { return !(*this == other); }
852 };
853
854 // This function returns the qualifiers and sets type_id to the unqalified or
855 // opaque type.
ResolveQualifiers(const AbiElementMap<const TypeIR * > & types,std::string & type_id)856 static Qualifiers ResolveQualifiers(const AbiElementMap<const TypeIR *> &types,
857 std::string &type_id) {
858 Qualifiers qual;
859 while (true) {
860 const TypeIR *type_ir = FindTypeById(types, type_id);
861 if (type_ir == nullptr ||
862 type_ir->GetKind() != LinkableMessageKind::QualifiedTypeKind) {
863 return qual;
864 }
865 const QualifiedTypeIR *qualified_type_ir =
866 static_cast<const QualifiedTypeIR *>(type_ir);
867 qual.is_const |= qualified_type_ir->IsConst();
868 qual.is_restricted |= qualified_type_ir->IsRestricted();
869 qual.is_volatile |= qualified_type_ir->IsVolatile();
870 type_id = qualified_type_ir->GetReferencedType();
871 }
872 }
873
874 // This function returns whether the old_type can be implicitly casted to
875 // new_type. It resolves qualified pointers and references until it reaches a
876 // type that does not reference other types. It does not compare the final
877 // referenced types.
878 //
879 // If this function returns true, old_type_id and new_type_id are set to the
880 // final referenced types. are_qualifiers_equal represents whether the
881 // qualifiers are exactly the same.
882 //
883 // If this function returns false, old_type_id, new_type_id, and
884 // are_qualifiers_equal do not have valid values.
885 //
886 // This function follows C++ standard to determine whether qualifiers can be
887 // casted. The rules are described in
888 // Section 7.5 Qualification conversions [conv.qual] in C++17 standard
889 // and
890 // https://en.cppreference.com/w/cpp/language/implicit_conversion#Qualification_conversions
891 // Additionally, __restrict__ follows the same rules as const and volatile.
ResolveImplicitlyConvertibleQualifiedReferences(const AbiElementMap<const TypeIR * > & old_types,const AbiElementMap<const TypeIR * > & new_types,std::string & old_type_id,std::string & new_type_id,bool & are_qualifiers_equal)892 static bool ResolveImplicitlyConvertibleQualifiedReferences(
893 const AbiElementMap<const TypeIR *> &old_types,
894 const AbiElementMap<const TypeIR *> &new_types, std::string &old_type_id,
895 std::string &new_type_id, bool &are_qualifiers_equal) {
896 are_qualifiers_equal = true;
897 bool is_first_level = true;
898 bool is_const_since_second_level = true;
899 while (true) {
900 // Check qualifiers.
901 const Qualifiers old_qual = ResolveQualifiers(old_types, old_type_id);
902 const Qualifiers new_qual = ResolveQualifiers(new_types, new_type_id);
903 are_qualifiers_equal &= (old_qual == new_qual);
904 if (is_first_level) {
905 is_first_level = false;
906 } else {
907 if ((old_qual.is_const && !new_qual.is_const) ||
908 (old_qual.is_restricted && !new_qual.is_restricted) ||
909 (old_qual.is_volatile && !new_qual.is_volatile)) {
910 return false;
911 }
912 if (!is_const_since_second_level && old_qual != new_qual) {
913 return false;
914 }
915 is_const_since_second_level &= new_qual.is_const;
916 }
917 // Stop if the unqualified types differ or don't reference other types.
918 const TypeIR *old_type = FindTypeById(old_types, old_type_id);
919 const TypeIR *new_type = FindTypeById(new_types, new_type_id);
920 if (old_type == nullptr || new_type == nullptr) {
921 return true;
922 }
923 const LinkableMessageKind kind = old_type->GetKind();
924 if (kind != new_type->GetKind()) {
925 return true;
926 }
927 if (kind != LinkableMessageKind::PointerTypeKind &&
928 kind != LinkableMessageKind::LvalueReferenceTypeKind &&
929 kind != LinkableMessageKind::RvalueReferenceTypeKind) {
930 return true;
931 }
932 // Get the referenced types.
933 old_type_id = old_type->GetReferencedType();
934 new_type_id = new_type->GetReferencedType();
935 }
936 }
937
CompareParameterTypes(const std::string & old_type_id,const std::string & new_type_id,DiffMessageIR::DiffKind diff_kind)938 DiffStatus AbiDiffHelper::CompareParameterTypes(
939 const std::string &old_type_id, const std::string &new_type_id,
940 DiffMessageIR::DiffKind diff_kind) {
941 // Compare size and alignment.
942 const TypeIR *old_type_ir = FindTypeById(old_types_, old_type_id);
943 const TypeIR *new_type_ir = FindTypeById(new_types_, new_type_id);
944 if (old_type_ir != nullptr && new_type_ir != nullptr &&
945 !CompareSizeAndAlignment(old_type_ir, new_type_ir)) {
946 return DiffStatus::kDirectDiff;
947 }
948 // Allow the new parameter to be more qualified than the old parameter.
949 std::string old_referenced_type_id = old_type_id;
950 std::string new_referenced_type_id = new_type_id;
951 bool are_qualifiers_equal;
952 if (!ResolveImplicitlyConvertibleQualifiedReferences(
953 old_types_, new_types_, old_referenced_type_id,
954 new_referenced_type_id, are_qualifiers_equal)) {
955 return DiffStatus::kDirectDiff;
956 }
957 // Compare the unqualified referenced types.
958 DiffStatus result = CompareAndDumpTypeDiff(old_referenced_type_id,
959 new_referenced_type_id, diff_kind);
960 if (!are_qualifiers_equal) {
961 result.CombineWith(DiffStatus::kDirectExt);
962 }
963 return result;
964 }
965
966 // This function is the same as CompareParameterTypes except for the arguments
967 // to ResolveImplicitlyConvertibleQualifiedReferences.
CompareReturnTypes(const std::string & old_type_id,const std::string & new_type_id,DiffMessageIR::DiffKind diff_kind)968 DiffStatus AbiDiffHelper::CompareReturnTypes(
969 const std::string &old_type_id, const std::string &new_type_id,
970 DiffMessageIR::DiffKind diff_kind) {
971 // Compare size and alignment.
972 const TypeIR *old_type_ir = FindTypeById(old_types_, old_type_id);
973 const TypeIR *new_type_ir = FindTypeById(new_types_, new_type_id);
974 if (old_type_ir != nullptr && new_type_ir != nullptr &&
975 !CompareSizeAndAlignment(old_type_ir, new_type_ir)) {
976 return DiffStatus::kDirectDiff;
977 }
978 // Allow the new return type to be less qualified than the old return type.
979 std::string old_referenced_type_id = old_type_id;
980 std::string new_referenced_type_id = new_type_id;
981 bool are_qualifiers_equal;
982 if (!ResolveImplicitlyConvertibleQualifiedReferences(
983 new_types_, old_types_, new_referenced_type_id,
984 old_referenced_type_id, are_qualifiers_equal)) {
985 return DiffStatus::kDirectDiff;
986 }
987 // Compare the unqualified referenced types.
988 DiffStatus result = CompareAndDumpTypeDiff(old_referenced_type_id,
989 new_referenced_type_id, diff_kind);
990 if (!are_qualifiers_equal) {
991 result.CombineWith(DiffStatus::kDirectExt);
992 }
993 return result;
994 }
995
CompareAndDumpTypeDiff(const TypeIR * old_type,const TypeIR * new_type,LinkableMessageKind kind,DiffMessageIR::DiffKind diff_kind)996 DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff(
997 const TypeIR *old_type, const TypeIR *new_type, LinkableMessageKind kind,
998 DiffMessageIR::DiffKind diff_kind) {
999 if (ignored_linker_set_keys_.find(new_type->GetLinkerSetKey()) !=
1000 ignored_linker_set_keys_.end()) {
1001 return DiffStatus::kNoDiff;
1002 }
1003
1004 switch (kind) {
1005 case LinkableMessageKind::BuiltinTypeKind:
1006 return CompareBuiltinTypes(static_cast<const BuiltinTypeIR *>(old_type),
1007 static_cast<const BuiltinTypeIR *>(new_type));
1008 case LinkableMessageKind::QualifiedTypeKind:
1009 return CompareQualifiedTypes(
1010 static_cast<const QualifiedTypeIR *>(old_type),
1011 static_cast<const QualifiedTypeIR *>(new_type), diff_kind);
1012 case LinkableMessageKind::ArrayTypeKind:
1013 return CompareArrayTypes(static_cast<const ArrayTypeIR *>(old_type),
1014 static_cast<const ArrayTypeIR *>(new_type),
1015 diff_kind);
1016 case LinkableMessageKind::EnumTypeKind:
1017 return CompareEnumTypes(static_cast<const EnumTypeIR *>(old_type),
1018 static_cast<const EnumTypeIR *>(new_type),
1019 diff_kind);
1020
1021 case LinkableMessageKind::LvalueReferenceTypeKind:
1022 return CompareLvalueReferenceTypes(
1023 static_cast<const LvalueReferenceTypeIR *>(old_type),
1024 static_cast<const LvalueReferenceTypeIR *>(new_type), diff_kind);
1025 case LinkableMessageKind::RvalueReferenceTypeKind:
1026 return CompareRvalueReferenceTypes(
1027 static_cast<const RvalueReferenceTypeIR *>(old_type),
1028 static_cast<const RvalueReferenceTypeIR *>(new_type), diff_kind);
1029 case LinkableMessageKind::PointerTypeKind:
1030 return ComparePointerTypes(static_cast<const PointerTypeIR *>(old_type),
1031 static_cast<const PointerTypeIR *>(new_type),
1032 diff_kind);
1033
1034 case LinkableMessageKind::RecordTypeKind:
1035 return CompareRecordTypes(static_cast<const RecordTypeIR *>(old_type),
1036 static_cast<const RecordTypeIR *>(new_type),
1037 diff_kind);
1038
1039 case LinkableMessageKind::FunctionTypeKind: {
1040 DiffStatus result = CompareFunctionTypes(
1041 static_cast<const FunctionTypeIR *>(old_type),
1042 static_cast<const FunctionTypeIR *>(new_type), diff_kind);
1043 // Do not allow extending function pointers, function references, etc.
1044 if (result.IsExtension()) {
1045 result.CombineWith(DiffStatus::kDirectDiff);
1046 }
1047 return result;
1048 }
1049 case LinkableMessageKind::FunctionKind:
1050 case LinkableMessageKind::GlobalVarKind:
1051 llvm::errs() << "Unexpected LinkableMessageKind: " << kind << "\n";
1052 ::exit(1);
1053 }
1054 }
1055
CompareDistinctKindMessages(const TypeIR * old_type,const TypeIR * new_type)1056 static DiffStatus CompareDistinctKindMessages(
1057 const TypeIR *old_type, const TypeIR *new_type) {
1058 // For these types to be considered ABI compatible, the very least requirement
1059 // is that their sizes and alignments should be equal.
1060 // TODO: Fill in
1061 return DiffStatus::kDirectDiff;
1062 }
1063
CompareAndDumpTypeDiff(const std::string & old_type_id,const std::string & new_type_id,DiffMessageIR::DiffKind diff_kind)1064 DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff(
1065 const std::string &old_type_id, const std::string &new_type_id,
1066 DiffMessageIR::DiffKind diff_kind) {
1067 // Check the map for type ids which have already been compared
1068 // These types have already been diffed, return without further comparison.
1069 if (!type_cache_->insert(old_type_id + new_type_id).second) {
1070 return DiffStatus::kNoDiff;
1071 }
1072
1073 TypeStackGuard guard(type_stack_,
1074 ConvertTypeIdToString(old_types_, old_type_id));
1075
1076 AbiElementMap<const TypeIR *>::const_iterator old_it =
1077 old_types_.find(old_type_id);
1078 AbiElementMap<const TypeIR *>::const_iterator new_it =
1079 new_types_.find(new_type_id);
1080
1081 if (old_it == old_types_.end() || new_it == new_types_.end()) {
1082 // One of the types were hidden, we cannot compare further.
1083 return AreOpaqueTypesEqual(old_type_id, new_type_id)
1084 ? DiffStatus::kNoDiff
1085 : DiffStatus::kDirectDiff;
1086 }
1087
1088 LinkableMessageKind old_kind = old_it->second->GetKind();
1089 LinkableMessageKind new_kind = new_it->second->GetKind();
1090 DiffStatus diff_status = DiffStatus::kNoDiff;
1091 if (old_kind != new_kind) {
1092 diff_status = CompareDistinctKindMessages(old_it->second, new_it->second);
1093 } else {
1094 diff_status = CompareAndDumpTypeDiff(old_it->second, new_it->second,
1095 old_kind, diff_kind);
1096 }
1097 return diff_status;
1098 }
1099
1100
1101 } // namespace repr
1102 } // namespace header_checker
1103