# UNDF: UNDF-2026-000000808 # UNDF: (leave blank) # vscode-0002: abstractExtensionManagementService.getAllDepsAndPacks O(D²) # # File: src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts # Function: getAllDepsAndPacks (line ~448) # # Defect: Recursive dependency traversal accumulates IDs into allDepsOrPacks # array, checking allDepsOrPacks.includes(id) on every iteration — # O(D²) where D = total transitive dependencies+packs. # Fix: Use a Set for the seen-check; keep the array for the result list. # Severity: MEDIUM (D = extension dependency tree depth × breadth, typically 10-50) # Speedup: 25x at D=50 # --- a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts +++ b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts @@ -448,7 +448,8 @@ - const getAllDepsAndPacks = (extension: ILocalExtension, profileLocation: URI, allDepsOrPacks: string[]) => { + const getAllDepsAndPacks = (extension: ILocalExtension, profileLocation: URI, allDepsOrPacks: string[], seenDepsOrPacks?: Set) => { + if (!seenDepsOrPacks) { seenDepsOrPacks = new Set(allDepsOrPacks); } const depsOrPacks = []; if (extension.manifest.extensionDependencies?.length) { depsOrPacks.push(...extension.manifest.extensionDependencies); @@ -456,12 +457,13 @@ for (const id of depsOrPacks) { - if (allDepsOrPacks.includes(id.toLowerCase())) { + const lowerId = id.toLowerCase(); + if (seenDepsOrPacks.has(lowerId)) { continue; } - allDepsOrPacks.push(id.toLowerCase()); - const installed = installExtensionResultsMap.get(`${id.toLowerCase()}-${profileLocation.toString()}`); + seenDepsOrPacks.add(lowerId); + allDepsOrPacks.push(lowerId); + const installed = installExtensionResultsMap.get(`${lowerId}-${profileLocation.toString()}`); if (installed?.local) { - allDepsOrPacks = getAllDepsAndPacks(installed.local, profileLocation, allDepsOrPacks); + allDepsOrPacks = getAllDepsAndPacks(installed.local, profileLocation, allDepsOrPacks, seenDepsOrPacks); } } return allDepsOrPacks;