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 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 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 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 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 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> 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 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 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 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 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 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 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 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 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 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 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 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>> 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> 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 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 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> 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> 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 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>> 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 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 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 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 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 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 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 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 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 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 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 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