61 lines
2.1 KiB
Diff
61 lines
2.1 KiB
Diff
# UNDF: UNDF-2026-000000846
|
||
# CWE-407: Algorithmic Complexity — Firefox nsDOMTokenList O(T²) classList add/remove
|
||
#
|
||
# File: dom/base/nsDOMTokenList.cpp
|
||
# Methods: AddInternal(), RemoveInternal()
|
||
#
|
||
# AddInternal() builds an `addedClasses` nsTArray and checks
|
||
# `addedClasses.Contains(aToken)` inside the loop over aTokens,
|
||
# making deduplication O(T²) where T = number of tokens being added.
|
||
#
|
||
# RemoveInternal() checks `aTokens.Contains(atom)` for each atom
|
||
# in the existing attribute, making removal O(A×T) where A = existing
|
||
# class count and T = tokens to remove.
|
||
#
|
||
# classList.add() and classList.remove() are called frequently in
|
||
# DOM-heavy applications (frameworks like React, Angular, etc.).
|
||
#
|
||
# Severity: MEDIUM — classList operations with many tokens are quadratic.
|
||
# At T=500 tokens, AddInternal does ~125,000 string comparisons instead
|
||
# of ~500 with a hash set.
|
||
#
|
||
# Fix: Use a hash set for dedup in AddInternal and for membership
|
||
# testing in RemoveInternal.
|
||
#
|
||
--- a/dom/base/nsDOMTokenList.cpp
|
||
+++ b/dom/base/nsDOMTokenList.cpp
|
||
@@ -159,7 +159,7 @@
|
||
- AutoTArray<nsString, 10> addedClasses;
|
||
+ nsTHashSet<nsString> addedClasses;
|
||
|
||
for (uint32_t i = 0, l = aTokens.Length(); i < l; ++i) {
|
||
const nsString& aToken = aTokens[i];
|
||
|
||
- if ((aAttr && aAttr->Contains(aToken)) || addedClasses.Contains(aToken)) {
|
||
+ if ((aAttr && aAttr->Contains(aToken)) || addedClasses.Contains(aToken)) {
|
||
continue;
|
||
}
|
||
|
||
@@ -171,7 +171,7 @@
|
||
resultStr.Append(aToken);
|
||
|
||
- addedClasses.AppendElement(aToken);
|
||
+ addedClasses.Insert(aToken);
|
||
}
|
||
|
||
@@ -196,10 +196,12 @@
|
||
void nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
|
||
const nsTArray<nsString>& aTokens) {
|
||
MOZ_ASSERT(aAttr, "Need an attribute");
|
||
|
||
RemoveDuplicates(aAttr);
|
||
|
||
+ nsTHashSet<nsString> tokenSet;
|
||
+ for (const auto& t : aTokens) { tokenSet.Insert(t); }
|
||
+
|
||
nsAutoString resultStr;
|
||
for (uint32_t i = 0; i < aAttr->GetAtomCount(); i++) {
|
||
- if (aTokens.Contains(nsDependentAtomString(aAttr->AtomAt(i)))) {
|
||
+ if (tokenSet.Contains(nsDependentAtomString(aAttr->AtomAt(i)))) {
|
||
continue;
|
||
}
|