Skip to content

Commit ed3228d

Browse files
committed
PR32260: Improve error handling on string merging
if the input sections are near the max supported size (4G) we might fail to enlarge the hash table. The error handling for this case didn't quite work. When this happens we can gracefully fall back to just not deduplicate this section (and continue with further mergable sections). We were mixing that with the case of not being able to even allocate a small structure (in which case we can as well error out completely), this disentables both cases. bfd/ PR ld/32260 * merge.c (sec_merge_maybe_resize): Check overflow in ultimate target type. (record_section): Return three-state, use new state when unable to enlarge hash table. (_bfd_merge_sections): Remove current section from merging consideration when hashtable can't be enlarged.
1 parent 34f93a5 commit ed3228d

File tree

1 file changed

+25
-13
lines changed

1 file changed

+25
-13
lines changed

bfd/merge.c

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ struct sec_merge_sec_info
165165

166166
/* Given a merge hash table TABLE and a number of entries to be
167167
ADDED, possibly resize the table for this to fit without further
168-
resizing. */
168+
resizing. Returns false if that can't be done for whatever reason. */
169169

170170
static bool
171171
sec_merge_maybe_resize (struct sec_merge_hash *table, unsigned added)
@@ -174,17 +174,18 @@ sec_merge_maybe_resize (struct sec_merge_hash *table, unsigned added)
174174
if (NEEDS_RESIZE (bfdtab->count + added, table->nbuckets))
175175
{
176176
unsigned i;
177-
unsigned long newnb = table->nbuckets * 2;
177+
unsigned long newnb = table->nbuckets;
178178
struct sec_merge_hash_entry **newv;
179179
uint64_t *newl;
180180
unsigned long alloc;
181181

182-
while (NEEDS_RESIZE (bfdtab->count + added, newnb))
182+
do
183183
{
184184
newnb *= 2;
185-
if (!newnb)
185+
if (!(unsigned int)newnb)
186186
return false;
187187
}
188+
while (NEEDS_RESIZE (bfdtab->count + added, newnb));
188189

189190
alloc = newnb * sizeof (newl[0]);
190191
if (alloc / sizeof (newl[0]) != newnb)
@@ -698,9 +699,12 @@ _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec,
698699
}
699700

700701
/* Record one whole input section (described by SECINFO) into the hash table
701-
SINFO. */
702+
SINFO. Returns 0 on hard errors (no sense in continuing link),
703+
1 when section is completely recorded, and 2 when the section wasn't
704+
recorded but we can continue (e.g. by simply not deduplicating this
705+
section). */
702706

703-
static bool
707+
static int
704708
record_section (struct sec_merge_info *sinfo,
705709
struct sec_merge_sec_info *secinfo)
706710
{
@@ -737,8 +741,8 @@ record_section (struct sec_merge_info *sinfo,
737741
merged into this area will make use of that as well. */
738742
if (!sec_merge_maybe_resize (sinfo->htab, 1 + sec->size / 2))
739743
{
740-
bfd_set_error (bfd_error_no_memory);
741-
goto error_return;
744+
free (contents);
745+
return 2;
742746
}
743747

744748
/* Walk through the contents, calculate hashes and length of all
@@ -788,14 +792,14 @@ record_section (struct sec_merge_info *sinfo,
788792
/*printf ("ZZZ %s:%s %u entries\n", sec->owner->filename, sec->name,
789793
(unsigned)secinfo->noffsetmap);*/
790794

791-
return true;
795+
return 1;
792796

793797
error_return:
794798
free (contents);
795799
contents = NULL;
796800
for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
797801
*secinfo->psecinfo = NULL;
798-
return false;
802+
return 0;
799803
}
800804

801805
/* qsort comparison function. Won't ever return zero as all entries
@@ -991,9 +995,16 @@ _bfd_merge_sections (bfd *abfd,
991995
}
992996
else
993997
{
994-
if (!record_section (sinfo, secinfo))
998+
int e = record_section (sinfo, secinfo);
999+
if (e == 0)
9951000
return false;
996-
if (align)
1001+
if (e == 2)
1002+
{
1003+
*secinfo->psecinfo = NULL;
1004+
if (remove_hook)
1005+
(*remove_hook) (abfd, secinfo->sec);
1006+
}
1007+
else if (align)
9971008
{
9981009
unsigned int opb = bfd_octets_per_byte (abfd, secinfo->sec);
9991010

@@ -1043,7 +1054,8 @@ _bfd_merge_sections (bfd *abfd,
10431054
/* Finally remove all input sections which have not made it into
10441055
the hash table at all. */
10451056
for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
1046-
if (secinfo->first_str == NULL)
1057+
if (secinfo->first_str == NULL
1058+
&& secinfo->sec->sec_info_type == SEC_INFO_TYPE_MERGE)
10471059
secinfo->sec->flags |= SEC_EXCLUDE | SEC_KEEP;
10481060
}
10491061

0 commit comments

Comments
 (0)