java-topology/defects/thunderbird-0007/patch/thunderbird-0007_about3Pane_initServer_existingURIs_ON2.patch

50 lines
2.4 KiB
Diff

# UNDF: UNDF-2026-000001168
--- a/mail/base/content/about3Pane.js
+++ b/mail/base/content/about3Pane.js
@@ -1241,20 +1241,21 @@ MOAD-0001 CWE-407: about3Pane.js SmartServerPane.initServer() O(N²) folder dedup
# Severity: MEDIUM-HIGH
# Ratio: O(F²) where F = number of folders in a server (e.g. 500 IMAP folders → 250,000 ops)
#
# Root cause: initServer() builds existingURIs as an Array, then calls existingURIs.includes()
# inside a do-while loop over remainingFolderURIs. After each addFolder() call the array is
# fully rebuilt from DOM (Array.from(existingRows, li => li.uri)). Every includes() call is
# O(F) and there are F iterations → O(F²) total.
#
# Fix: use a Set<string> for existingURIs. Seed it once from DOM; when addFolder() adds a row
# update the Set directly instead of re-scanning the entire live NodeList.
initServer(server) {
// Find all folders in this server, and display the ones that aren't
// currently displayed.
const descendants = new Map(
server.rootFolder.descendants.map(d => [d.URI, d])
);
if (!descendants.size) {
return;
}
const remainingFolderURIs = Array.from(descendants.keys());
// Get a list of folders that already exist in the folder tree.
const existingRows = this.containerList.getElementsByTagName("li");
- let existingURIs = Array.from(existingRows, li => li.uri);
+ // PATCH thunderbird-0007: use a Set so membership checks are O(1).
+ const existingURIs = new Set(Array.from(existingRows, li => li.uri));
do {
const folderURI = remainingFolderURIs.shift();
- if (existingURIs.includes(folderURI)) {
+ if (existingURIs.has(folderURI)) {
continue;
}
const folder = descendants.get(folderURI);
if (folderPane._isGmailFolder(folder)) {
continue;
}
this.addFolder(folderPane._getNonGmailParent(folder), folder);
- // Update the list of existing folders. `existingRows` is a live
- // list, so we don't need to call `getElementsByTagName` again.
- existingURIs = Array.from(existingRows, li => li.uri);
+ // Update the Set so subsequent iterations see the newly added row.
+ // `existingRows` is a live NodeList — we just add the new URI.
+ existingURIs.add(folderURI);
} while (remainingFolderURIs.length);
},