@@ -423,7 +423,7 @@ class ObjcCategoryMerger {
423
423
private:
424
424
DenseSet<const Symbol *> collectNlCategories ();
425
425
void collectAndValidateCategoriesData ();
426
- void
426
+ bool
427
427
mergeCategoriesIntoSingleCategory (std::vector<InfoInputCategory> &categories);
428
428
429
429
void eraseISec (ConcatInputSection *isec);
@@ -434,8 +434,8 @@ class ObjcCategoryMerger {
434
434
catListToErasedOffsets);
435
435
void collectSectionWriteInfoFromIsec (const InputSection *isec,
436
436
InfoWriteSection &catWriteInfo);
437
- void collectCategoryWriterInfoFromCategory (const InfoInputCategory &catInfo);
438
- void parseCatInfoToExtInfo (const InfoInputCategory &catInfo,
437
+ bool collectCategoryWriterInfoFromCategory (const InfoInputCategory &catInfo);
438
+ bool parseCatInfoToExtInfo (const InfoInputCategory &catInfo,
439
439
ClassExtensionInfo &extInfo);
440
440
441
441
void parseProtocolListInfo (const ConcatInputSection *isec, uint32_t secOffset,
@@ -446,7 +446,7 @@ class ObjcCategoryMerger {
446
446
uint32_t secOffset,
447
447
SourceLanguage sourceLang);
448
448
449
- void parsePointerListInfo (const ConcatInputSection *isec, uint32_t secOffset,
449
+ bool parsePointerListInfo (const ConcatInputSection *isec, uint32_t secOffset,
450
450
PointerListInfo &ptrList);
451
451
452
452
void emitAndLinkPointerList (Defined *parentSym, uint32_t linkAtOffset,
@@ -474,7 +474,7 @@ class ObjcCategoryMerger {
474
474
uint32_t offset);
475
475
Defined *getClassRo (const Defined *classSym, bool getMetaRo);
476
476
SourceLanguage getClassSymSourceLang (const Defined *classSym);
477
- void mergeCategoriesIntoBaseClass (const Defined *baseClass,
477
+ bool mergeCategoriesIntoBaseClass (const Defined *baseClass,
478
478
std::vector<InfoInputCategory> &categories);
479
479
void eraseSymbolAtIsecOffset (ConcatInputSection *isec, uint32_t offset);
480
480
void tryEraseDefinedAtIsecOffset (const ConcatInputSection *isec,
@@ -543,9 +543,9 @@ ObjcCategoryMerger::tryGetSymbolAtIsecOffset(const ConcatInputSection *isec,
543
543
if (!reloc)
544
544
return nullptr ;
545
545
546
- Symbol *sym = reloc->referent .get <Symbol *>();
546
+ Symbol *sym = reloc->referent .dyn_cast <Symbol *>();
547
547
548
- if (reloc->addend ) {
548
+ if (reloc->addend && sym ) {
549
549
assert (isa<Defined>(sym) && " Expected defined for non-zero addend" );
550
550
Defined *definedSym = cast<Defined>(sym);
551
551
sym = tryFindDefinedOnIsec (definedSym->isec (),
@@ -618,7 +618,7 @@ void ObjcCategoryMerger::tryEraseDefinedAtIsecOffset(
618
618
}
619
619
}
620
620
621
- void ObjcCategoryMerger::collectCategoryWriterInfoFromCategory (
621
+ bool ObjcCategoryMerger::collectCategoryWriterInfoFromCategory (
622
622
const InfoInputCategory &catInfo) {
623
623
624
624
if (!infoCategoryWriter.catListInfo .valid )
@@ -631,7 +631,14 @@ void ObjcCategoryMerger::collectCategoryWriterInfoFromCategory(
631
631
if (!infoCategoryWriter.catNameInfo .valid ) {
632
632
lld::macho::Defined *catNameSym =
633
633
tryGetDefinedAtIsecOffset (catInfo.catBodyIsec , catLayout.nameOffset );
634
- assert (catNameSym && " Category does not have a valid name Symbol" );
634
+
635
+ if (!catNameSym) {
636
+ // This is an unhandeled case where the category name is not a symbol but
637
+ // instead points to an CStringInputSection (that doesn't have any symbol)
638
+ // TODO: Find a small repro and either fix or add a test case for this
639
+ // scenario
640
+ return false ;
641
+ }
635
642
636
643
collectSectionWriteInfoFromIsec (catNameSym->isec (),
637
644
infoCategoryWriter.catNameInfo );
@@ -651,6 +658,8 @@ void ObjcCategoryMerger::collectCategoryWriterInfoFromCategory(
651
658
}
652
659
}
653
660
}
661
+
662
+ return true ;
654
663
}
655
664
656
665
// Parse a protocol list that might be linked to ConcatInputSection at a given
@@ -723,7 +732,7 @@ ObjcCategoryMerger::parseProtocolListInfo(const ConcatInputSection *isec,
723
732
// Parse a pointer list that might be linked to ConcatInputSection at a given
724
733
// offset. This can be used for instance methods, class methods, instance props
725
734
// and class props since they have the same format.
726
- void ObjcCategoryMerger::parsePointerListInfo (const ConcatInputSection *isec,
735
+ bool ObjcCategoryMerger::parsePointerListInfo (const ConcatInputSection *isec,
727
736
uint32_t secOffset,
728
737
PointerListInfo &ptrList) {
729
738
assert (ptrList.pointersPerStruct == 2 || ptrList.pointersPerStruct == 3 );
@@ -732,8 +741,9 @@ void ObjcCategoryMerger::parsePointerListInfo(const ConcatInputSection *isec,
732
741
" Trying to read pointer list beyond section end" );
733
742
734
743
const Reloc *reloc = isec->getRelocAt (secOffset);
744
+ // Empty list is a valid case, return true.
735
745
if (!reloc)
736
- return ;
746
+ return true ;
737
747
738
748
auto *ptrListSym = dyn_cast_or_null<Defined>(reloc->referent .get <Symbol *>());
739
749
assert (ptrListSym && " Reloc does not have a valid Defined" );
@@ -759,17 +769,24 @@ void ObjcCategoryMerger::parsePointerListInfo(const ConcatInputSection *isec,
759
769
const Reloc *reloc = ptrListSym->isec ()->getRelocAt (off);
760
770
assert (reloc && " No reloc found at pointer list offset" );
761
771
762
- auto *listSym = dyn_cast_or_null<Defined>(reloc->referent .get <Symbol *>());
763
- assert (listSym && " Reloc does not have a valid Defined" );
772
+ auto *listSym =
773
+ dyn_cast_or_null<Defined>(reloc->referent .dyn_cast <Symbol *>());
774
+ // Sometimes, the reloc points to a StringPiece (InputSection + addend)
775
+ // instead of a symbol.
776
+ // TODO: Skip these cases for now, but we should fix this.
777
+ if (!listSym)
778
+ return false ;
764
779
765
780
ptrList.allPtrs .push_back (listSym);
766
781
}
782
+
783
+ return true ;
767
784
}
768
785
769
786
// Here we parse all the information of an input category (catInfo) and
770
787
// append the parsed info into the structure which will contain all the
771
788
// information about how a class is extended (extInfo)
772
- void ObjcCategoryMerger::parseCatInfoToExtInfo (const InfoInputCategory &catInfo,
789
+ bool ObjcCategoryMerger::parseCatInfoToExtInfo (const InfoInputCategory &catInfo,
773
790
ClassExtensionInfo &extInfo) {
774
791
const Reloc *catNameReloc =
775
792
catInfo.catBodyIsec ->getRelocAt (catLayout.nameOffset );
@@ -808,20 +825,27 @@ void ObjcCategoryMerger::parseCatInfoToExtInfo(const InfoInputCategory &catInfo,
808
825
" class" );
809
826
}
810
827
811
- parsePointerListInfo (catInfo.catBodyIsec , catLayout.instanceMethodsOffset ,
812
- extInfo.instanceMethods );
828
+ if (!parsePointerListInfo (catInfo.catBodyIsec ,
829
+ catLayout.instanceMethodsOffset ,
830
+ extInfo.instanceMethods ))
831
+ return false ;
813
832
814
- parsePointerListInfo (catInfo.catBodyIsec , catLayout.classMethodsOffset ,
815
- extInfo.classMethods );
833
+ if (!parsePointerListInfo (catInfo.catBodyIsec , catLayout.classMethodsOffset ,
834
+ extInfo.classMethods ))
835
+ return false ;
816
836
817
837
parseProtocolListInfo (catInfo.catBodyIsec , catLayout.protocolsOffset ,
818
838
extInfo.protocols , catInfo.sourceLanguage );
819
839
820
- parsePointerListInfo (catInfo.catBodyIsec , catLayout.instancePropsOffset ,
821
- extInfo.instanceProps );
840
+ if (!parsePointerListInfo (catInfo.catBodyIsec , catLayout.instancePropsOffset ,
841
+ extInfo.instanceProps ))
842
+ return false ;
822
843
823
- parsePointerListInfo (catInfo.catBodyIsec , catLayout.classPropsOffset ,
824
- extInfo.classProps );
844
+ if (!parsePointerListInfo (catInfo.catBodyIsec , catLayout.classPropsOffset ,
845
+ extInfo.classProps ))
846
+ return false ;
847
+
848
+ return true ;
825
849
}
826
850
827
851
// Generate a protocol list (including header) and link it into the parent at
@@ -1090,14 +1114,15 @@ Defined *ObjcCategoryMerger::emitCategory(const ClassExtensionInfo &extInfo) {
1090
1114
1091
1115
// This method merges all the categories (sharing a base class) into a single
1092
1116
// category.
1093
- void ObjcCategoryMerger::mergeCategoriesIntoSingleCategory (
1117
+ bool ObjcCategoryMerger::mergeCategoriesIntoSingleCategory (
1094
1118
std::vector<InfoInputCategory> &categories) {
1095
1119
assert (categories.size () > 1 && " Expected at least 2 categories" );
1096
1120
1097
1121
ClassExtensionInfo extInfo (catLayout);
1098
1122
1099
1123
for (auto &catInfo : categories)
1100
- parseCatInfoToExtInfo (catInfo, extInfo);
1124
+ if (!parseCatInfoToExtInfo (catInfo, extInfo))
1125
+ return false ;
1101
1126
1102
1127
Defined *newCatDef = emitCategory (extInfo);
1103
1128
assert (newCatDef && " Failed to create a new category" );
@@ -1107,6 +1132,8 @@ void ObjcCategoryMerger::mergeCategoriesIntoSingleCategory(
1107
1132
1108
1133
for (auto &catInfo : categories)
1109
1134
catInfo.wasMerged = true ;
1135
+
1136
+ return true ;
1110
1137
}
1111
1138
1112
1139
void ObjcCategoryMerger::createSymbolReference (Defined *refFrom,
@@ -1179,9 +1206,10 @@ void ObjcCategoryMerger::collectAndValidateCategoriesData() {
1179
1206
tryGetSymbolAtIsecOffset (catBodyIsec, catLayout.klassOffset );
1180
1207
assert (classSym && " Category does not have a valid base class" );
1181
1208
1182
- categoryMap[classSym].push_back (catInputInfo);
1209
+ if (!collectCategoryWriterInfoFromCategory (catInputInfo))
1210
+ continue ;
1183
1211
1184
- collectCategoryWriterInfoFromCategory (catInputInfo);
1212
+ categoryMap[classSym]. push_back (catInputInfo);
1185
1213
}
1186
1214
}
1187
1215
}
@@ -1309,13 +1337,17 @@ void ObjcCategoryMerger::doMerge() {
1309
1337
collectAndValidateCategoriesData ();
1310
1338
1311
1339
for (auto &[baseClass, catInfos] : categoryMap) {
1340
+ bool merged = false ;
1312
1341
if (auto *baseClassDef = dyn_cast<Defined>(baseClass)) {
1313
1342
// Merge all categories into the base class
1314
- mergeCategoriesIntoBaseClass (baseClassDef, catInfos);
1343
+ merged = mergeCategoriesIntoBaseClass (baseClassDef, catInfos);
1315
1344
} else if (catInfos.size () > 1 ) {
1316
1345
// Merge all categories into a new, single category
1317
- mergeCategoriesIntoSingleCategory (catInfos);
1346
+ merged = mergeCategoriesIntoSingleCategory (catInfos);
1318
1347
}
1348
+ if (!merged)
1349
+ warn (" ObjC category merging skipped for class symbol' " +
1350
+ baseClass->getName ().str () + " '\n " );
1319
1351
}
1320
1352
1321
1353
// Erase all categories that were merged
@@ -1374,7 +1406,8 @@ ObjcCategoryMerger::getClassSymSourceLang(const Defined *classSym) {
1374
1406
1375
1407
llvm_unreachable (" Unexpected class symbol name during category merging" );
1376
1408
}
1377
- void ObjcCategoryMerger::mergeCategoriesIntoBaseClass (
1409
+
1410
+ bool ObjcCategoryMerger::mergeCategoriesIntoBaseClass (
1378
1411
const Defined *baseClass, std::vector<InfoInputCategory> &categories) {
1379
1412
assert (categories.size () >= 1 && " Expected at least one category to merge" );
1380
1413
@@ -1383,9 +1416,9 @@ void ObjcCategoryMerger::mergeCategoriesIntoBaseClass(
1383
1416
extInfo.baseClass = baseClass;
1384
1417
extInfo.baseClassSourceLanguage = getClassSymSourceLang (baseClass);
1385
1418
1386
- for (auto &catInfo : categories) {
1387
- parseCatInfoToExtInfo (catInfo, extInfo);
1388
- }
1419
+ for (auto &catInfo : categories)
1420
+ if (! parseCatInfoToExtInfo (catInfo, extInfo))
1421
+ return false ;
1389
1422
1390
1423
// Get metadata for the base class
1391
1424
Defined *metaRo = getClassRo (baseClass, /* getMetaRo=*/ true );
@@ -1452,6 +1485,8 @@ void ObjcCategoryMerger::mergeCategoriesIntoBaseClass(
1452
1485
// Mark all the categories as merged - this will be used to erase them later
1453
1486
for (auto &catInfo : categories)
1454
1487
catInfo.wasMerged = true ;
1488
+
1489
+ return true ;
1455
1490
}
1456
1491
1457
1492
// Erase the symbol at a given offset in an InputSection
0 commit comments