ld: Avoid overflows in string merging
authorMichael Matz <matz@suse.de>
Tue, 7 Nov 2023 15:54:44 +0000 (16:54 +0100)
committerMichael Matz <matz@suse.de>
Thu, 9 Nov 2023 16:42:04 +0000 (17:42 +0100)
as the bug report shows we had an overflow in the test if
hash table resizing is needed.  Reorder the expression to avoid
that.  There's still a bug somewhere in gracefully handling
failure in resizing (e.g. out of memory), but this pushes the
boundary for that occurring somewhen into the future and
immediately helps the reporter.

    bfd/

    PR ld/31009
    * merge.c (NEEDS_RESIZE): New macro avoiding overflow.
    (sec_merge_maybe_resize): Use it.
    (sec_merge_hash_insert): Ditto.

bfd/merge.c

index 722e665948627cbee4b5215d9011137713604f00..61ffab4d706c0e063097877e2578172a309e228d 100644 (file)
@@ -94,6 +94,10 @@ struct sec_merge_hash
   struct sec_merge_hash_entry **values;
 };
 
+/* True when given NEWCOUNT and NBUCKETS indicate that the hash table needs
+   resizing.  */
+#define NEEDS_RESIZE(newcount, nbuckets) ((newcount) > (nbuckets) / 3 * 2)
+
 struct sec_merge_sec_info;
 
 /* Information per merged blob.  This is the unit of merging and is
@@ -167,7 +171,7 @@ static bool
 sec_merge_maybe_resize (struct sec_merge_hash *table, unsigned added)
 {
   struct bfd_hash_table *bfdtab = &table->table;
-  if (bfdtab->count + added > table->nbuckets * 2 / 3)
+  if (NEEDS_RESIZE (bfdtab->count + added, table->nbuckets))
     {
       unsigned i;
       unsigned long newnb = table->nbuckets * 2;
@@ -175,7 +179,7 @@ sec_merge_maybe_resize (struct sec_merge_hash *table, unsigned added)
       uint64_t *newl;
       unsigned long alloc;
 
-      while (bfdtab->count + added > newnb * 2 / 3)
+      while (NEEDS_RESIZE (bfdtab->count + added, newnb))
        {
          newnb *= 2;
          if (!newnb)
@@ -239,8 +243,8 @@ sec_merge_hash_insert (struct sec_merge_hash *table,
   hashp->alignment = 0;
   hashp->u.suffix = NULL;
   hashp->next = NULL;
-  // We must not need resizing, otherwise _index is wrong
-  BFD_ASSERT (bfdtab->count + 1 <= table->nbuckets * 2 / 3);
+  // We must not need resizing, otherwise the estimation was wrong
+  BFD_ASSERT (!NEEDS_RESIZE (bfdtab->count + 1, table->nbuckets));
   bfdtab->count++;
   table->key_lens[_index] = (hash << 32) | (uint32_t)len;
   table->values[_index] = hashp;