java-topology/defects/wesnoth-0003/patch/wesnoth-0003.patch
russell@unturf.com 9fac7766ba wesnoth: 3 CWE-407 defects, MOAD 0002-0005 CLEAN
wesnoth-0001: A* pathfinding std::find on pq vector for decrease-key
  O(V*Q) per relaxation, fix: lazy deletion. HIGH, 1279x at N=5000.
wesnoth-0002: server ip_log_ deque linear scan on login/logoff
  O(N) per event with N up to 500. MEDIUM, 437x at L=2000.
wesnoth-0003: combine_special_notes O(N^2) vector dedup
  utils::contains on vector per note insertion. MEDIUM, 499x at N=1000.

MOAD-0002 (Intertangle): singletons deeply embedded, not actionable.
MOAD-0003 (Leaked Context): thread_local for debug/call-stack only.
MOAD-0004 (Logged Secret): passwords never logged verbatim.
MOAD-0005 (Thundering Herd): single-threaded game + coroutine server.

6/6 unit tests PASS.
2026-03-31 12:14:20 -04:00

67 lines
2.5 KiB
Diff

# UNDF: UNDF-2026-000000972
--- a/src/units/types.cpp
+++ b/src/units/types.cpp
@@ -458,10 +458,11 @@ std::vector<t_string> unit_type::special_notes() const {
static void append_special_note(std::vector<t_string>& notes, const t_string& new_note) {
if(new_note.empty()) return;
std::string_view note_plain = new_note.c_str();
utils::trim(note_plain);
if(note_plain.empty()) return;
- if(utils::contains(notes, new_note)) return;
notes.push_back(new_note);
}
-std::vector<t_string> combine_special_notes(const std::vector<t_string>& direct, const config& abilities, const const_attack_itors& attacks, const movetype& mt)
+std::vector<t_string> combine_special_notes(const std::vector<t_string>& direct, const config& abilities, const const_attack_itors& attacks, const movetype& mt)
{
- std::vector<t_string> notes;
+ std::vector<t_string> notes;
+ // Use a set to track seen notes for O(1) dedup instead of
+ // O(N) linear scan via utils::contains on vector per insertion.
+ std::set<std::string> seen;
for(const auto& note : direct) {
- append_special_note(notes, note);
+ std::string key(note.c_str());
+ if(!key.empty() && seen.insert(key).second) {
+ notes.push_back(note);
+ }
}
for(const auto [key, cfg] : abilities.all_children_view()) {
if(cfg.has_attribute("special_note")) {
- append_special_note(notes, cfg["special_note"].t_str());
+ const t_string& sn = cfg["special_note"].t_str();
+ std::string k(sn.c_str());
+ if(!k.empty() && seen.insert(k).second) {
+ notes.push_back(sn);
+ }
}
}
for(const auto& attack : attacks) {
for(const auto& p_ab : attack.specials()) {
if(p_ab->cfg().has_attribute("special_note")) {
- append_special_note(notes, p_ab->cfg()["special_note"].t_str());
+ const t_string& sn = p_ab->cfg()["special_note"].t_str();
+ std::string k(sn.c_str());
+ if(!k.empty() && seen.insert(k).second) {
+ notes.push_back(sn);
+ }
}
}
if(auto attack_type_note = string_table.find("special_note_damage_type_" + attack.type()); attack_type_note != string_table.end()) {
- append_special_note(notes, attack_type_note->second);
+ std::string k(attack_type_note->second.c_str());
+ if(!k.empty() && seen.insert(k).second) {
+ notes.push_back(attack_type_note->second);
+ }
}
}
for(const auto& move_note : mt.special_notes()) {
- append_special_note(notes, move_note);
+ std::string k(move_note.c_str());
+ if(!k.empty() && seen.insert(k).second) {
+ notes.push_back(move_note);
+ }
}
return notes;
}