java-topology/whitepaper/outreach/wesnoth-0003.md
russell@unturf.com 6784cdf1cf feat: add 39 outreach docs (batches 6-8)
Batch 6 (9): dolibarr, jitsi-videobridge, zed, tryton, suricata,
  strawberry, zulip, zesarux, zephyr
Batch 7 (15): xonotic (4), xash3d (3), xenia, xtuple, zabbix (2),
  zathura, zebra, yabause, zephyr-0001
Batch 8 (15): woodpecker (2), wine (4), widelands (3), wesnoth (3),
  wekan (3)

Mix of CWE-407 and CWE-312.
2026-04-14 17:06:28 -04:00

3.1 KiB
Raw Blame History

Battle for Wesnoth — CWE-407 Disclosure Brief (wesnoth-0003)

2026-04-13 · Patch available — awaiting upstream merge

Finding

One O(n²) defect in Wesnoth's unit type system. combine_special_notes() and its helper append_special_note() use utils::contains() (linear scan) on a std::vector<t_string> to deduplicate special notes when building unit type descriptions. Each note insertion scans the full list, producing O(N²) where N = total notes from all sources.

The Defect

wesnoth-0003 (PATCHED — LOW): src/units/types.cpp:458

// append_special_note — called per note from abilities, attacks, movement:
static void append_special_note(std::vector<t_string>& notes, const t_string& new_note) {
    if (new_note.empty()) return;
    if (utils::contains(notes, new_note)) return;  // O(N) linear scan
    notes.push_back(new_note);
}

// combine_special_notes — aggregates from 4+ sources:
for (const auto& note : direct) { append_special_note(notes, note); }
for (const auto [key, cfg] : abilities.all_children_view()) { ... append_special_note(...) }
for (const auto& attack : attacks) { ... append_special_note(...) }
for (const auto& move_note : mt.special_notes()) { append_special_note(notes, move_note); }

Units with many abilities, attack types, and movement specials accumulate notes from multiple sources. Each note insertion scans all previously added notes.

Complexity Proof

At N=50 special notes (complex unit with many abilities and attacks):

  • Defective: 1 + 2 + ... + 50 = 1,275 string comparisons
  • Fixed: 50 set lookups
  • ~25× op reduction. Fires during unit type initialization and display.

Impact

Wesnoth loads unit type data on game start and when displaying unit information panels. Modded games with complex unit types (many abilities, weapon specials, movement properties) accumulate dozens of special notes. While the absolute cost is moderate for vanilla units, heavily modded scenarios with custom unit types amplify the quadratic path.

The Fix

Use std::set<std::string> for O(log N) dedup lookups instead of O(N) vector scan:

// Before
if (utils::contains(notes, new_note)) return;

// After
// CWE-407 fix: set for O(log N) dedup instead of O(N) vector scan.
std::set<std::string> seen;
std::string key(note.c_str());
if (!key.empty() && seen.insert(key).second) {
    notes.push_back(note);
}

Patch

Fix available: defects/wesnoth-0003/patch/wesnoth-0003.patch

Single-file patch in src/units/types.cpp. Inlines dedup logic with std::set<std::string>, eliminates append_special_note dependency on utils::contains. ~25× speedup at N=50.

What We Ask

A patch is ready for review.

  1. Confirm receipt and assign a GitHub issue reference (wesnoth/wesnoth).
  2. Assess severity — fires during unit type initialization and info display.
  3. Coordinate a disclosure date — we target 90 days from first contact.
  4. We will credit the Wesnoth team in the public disclosure. Preferred acknowledgment format welcome.

Contact: see cover email. This brief is confidential until coordinated disclosure.