diff options
author | Aaron Merey <amerey@redhat.com> | 2024-01-21 19:44:34 -0500 |
---|---|---|
committer | Aaron Merey <amerey@redhat.com> | 2024-01-22 12:52:47 -0500 |
commit | 1652e02a8a63c7c830b15701a6a34b53ae345d91 (patch) | |
tree | b075d820d2737bb4bf9e0db0c1b539bd66323c29 | |
parent | c1058da5a450e33e72b72abb53bc3ffd7f6b361b (diff) |
PR31097
-rw-r--r-- | src/unstrip.c | 43 |
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) |