From 1652e02a8a63c7c830b15701a6a34b53ae345d91 Mon Sep 17 00:00:00 2001 From: Aaron Merey Date: Sun, 21 Jan 2024 19:44:34 -0500 Subject: [PATCH] PR31097 --- src/unstrip.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/unstrip.c b/src/unstrip.c index d5bd18215..0c01baade 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) -- 2.47.2