2 KiB
UNDF: UNDF-2026-000000354
binutils-0001 — ldlang.c unique_section_p O(S×U) linked-list scan
Severity: MEDIUM
CWE: CWE-407 (Inefficient Algorithmic Complexity)
File: ld/ldlang.c
Functions: unique_section_p (line 389), lang_add_unique (line 10269)
Repo: https://sourceware.org/git/binutils-gdb.git
Defect
unique_section_list is a singly-linked list. Two O(N) linear scans exist:
1. unique_section_p — O(U) per call, called O(S) times → O(S×U) total
// ld/ldlang.c:402
for (unam = unique_section_list; unam; unam = unam->next)
if (name_match (unam->name, secnam) == 0)
return true;
Called from three section-placement paths during linking:
output_section_callback_sort(line 776) — called per matching sectionoutput_section_callback_nosort(line 3002, 3024) — called per matching section- orphan section placement (line 7784) — called per unplaced section
For a large binary with S=100K input sections and U=1K unique-section patterns (common in embedded/RTOS linker scripts with per-function sections), this is 100M name_match calls.
2. lang_add_unique — O(U) dedup scan on each insertion
// ld/ldlang.c:10273
for (ent = unique_section_list; ent; ent = ent->next)
if (strcmp (ent->name, name) == 0)
return;
Called O(U) times during linker script parsing. Each call scans the entire existing list → O(U²) total for adding U entries.
Fix
Replace unique_section_list linked list with a hash set.
// Replace:
static struct unique_sections *unique_section_list;
// With:
static htab_t unique_section_htab; /* htab_t keyed on section name */
unique_section_p: htab_find → O(1) averagelang_add_unique: htab_find_slot → O(1) average
Complexity
| Scenario | Before | After |
|---|---|---|
| S=100K sections, U=1K unique patterns | O(100M) | O(100K) |
| U=100 unique entries, insert all | O(5K) dedup | O(100) |
Speedup at S=10K, U=500: ~500x op-count reduction for unique_section_p.