summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Merey <amerey@redhat.com>2024-01-21 19:44:34 -0500
committerAaron Merey <amerey@redhat.com>2024-01-22 12:52:47 -0500
commit1652e02a8a63c7c830b15701a6a34b53ae345d91 (patch)
treeb075d820d2737bb4bf9e0db0c1b539bd66323c29
parentc1058da5a450e33e72b72abb53bc3ffd7f6b361b (diff)
PR31097
-rw-r--r--src/unstrip.c43
1 files changed, 40 insertions, 3 deletions
diff --git a/src/unstrip.c b/src/unstrip.c
index d5bd1821..0c01baad 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -903,8 +903,12 @@ collect_symbols (Elf *outelf, bool rel, Elf_Scn *symscn, Elf_Scn *strscn,
if (s1->value > s2->value) \
return 1
-/* Compare symbols with a consistent ordering,
- but one only meaningful for equality. */
+/* Symbol comparison used to sort symbols in preparation for deduplication.
+
+ This function must ensure a consistent ordering of duplicates even when
+ used with an unstable sort function such as qsort. If duplicate symbols
+ aren't sorted in a consistent order, the symbol index map can become
+ corrupt. */
static int
compare_symbols (const void *a, const void *b)
{
@@ -915,6 +919,38 @@ compare_symbols (const void *a, const void *b)
CMP (size);
CMP (shndx);
+ int res = s1->compare - s2->compare;
+ if (res != 0)
+ return res;
+
+ res = strcmp (s1->name, s2->name);
+ if (res != 0)
+ return res;
+
+ /* Duplicates still have distinct positions in the symbol index map.
+ Compare map positions to ensure that duplicate symbols are ordered
+ consistently even if the sort function is unstable. */
+ CMP (map);
+ error_exit (0, "found two identical index map positions.");
+}
+
+/* Symbol comparison used to deduplicate symbols found in both the stripped
+ and unstripped input files.
+
+ Similar to compare_symbols, but does not differentiate symbols based
+ on their position in the symbol index map. Duplicates can't be found
+ by comparing index map postions because duplicates still have distinct
+ positions in the map. */
+static int
+compare_symbols_duplicate (const void *a, const void *b)
+{
+ const struct symbol *s1 = a;
+ const struct symbol *s2 = b;
+
+ CMP (value);
+ CMP (size);
+ CMP (shndx);
+
return (s1->compare - s2->compare) ?: strcmp (s1->name, s2->name);
}
@@ -1855,7 +1891,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
}
struct symbol *n = s;
- while (n + 1 < &symbols[total_syms] && !compare_symbols (s, n + 1))
+ while (n + 1 < &symbols[total_syms]
+ && !compare_symbols_duplicate (s, n + 1))
++n;
while (s < n)