java-topology/whitepaper/outreach/zed.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

4 KiB

Zed Editor — CWE-407 Disclosure Brief

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

Finding

Two O(n^2) defects in Zed across the LSP code action pipeline and extension manifest builder. Both patched. Patches ready for upstream review. The LSP defect fires on every format-on-save and code action invocation; the manifest defect fires at extension build time.

The Defects

zed-0001 (PATCHED — MEDIUM): crates/project/src/lsp_store.rs:2010,3356

// Vec::contains() — O(E) per edit in dedup loop
let mut lsp_edits = Vec::new();
for edit in op.edits {
    match edit {
        Edit::Plain(edit) => {
            if !lsp_edits.contains(&edit) {  // O(E) linear scan
                lsp_edits.push(edit);
            }
        }
    }
}

Two identical call sites in apply_code_actions_as_format and apply_code_action use Vec::contains() to deduplicate LSP edits. Each new edit triggers a linear scan of all previously accumulated edits. Total cost: O(E^2) where E = number of edits returned by a language server. Large refactors (rename across file, organize imports) can produce hundreds of edits.

zed-0002 (PATCHED — LOW): crates/extension/src/extension_builder.rs:585

// Vec::contains() — O(N) per entry in three manifest loops
if !manifest.languages.contains(&relative_language_dir) {
    manifest.languages.push(relative_language_dir);
}

Three while loops accumulate entries into manifest.languages, manifest.themes, and manifest.icon_themes (all Vec), each checking Vec::contains before push. O(N^2) per category where N = number of language dirs / theme files / icon theme files.

Complexity Proof

zed-0001: At E=100 edits per code action:

  • Defective: 1 + 2 + ... + 100 = 5,050 comparisons (struct equality checks)
  • Fixed: 100 HashSet insertions
  • 50x op reduction at E=100.

zed-0002: At N=20 language directories:

  • Defective: 1 + 2 + ... + 20 = 210 comparisons
  • Fixed: 20 HashSet lookups
  • 20x op reduction at N=20. Lower practical impact (extension build time only).

Impact

Zed positions itself as a high-performance code editor. zed-0001 fires in the critical path of format-on-save and code action application, which developers trigger constantly during editing. Language servers like rust-analyzer, TypeScript, and gopls can return large edit batches during rename, organize imports, or bulk fix operations. At 200+ edits, the quadratic dedup adds measurable latency to what should feel instant.

zed-0002 only fires at extension build time and affects developers building Zed extensions. Lower severity but follows the same pattern.

The Fix

zed-0001: Add HashSet shadow set for O(1) dedup alongside the ordered Vec:

// Before
let mut lsp_edits = Vec::new();
if !lsp_edits.contains(&edit) { lsp_edits.push(edit); }

// After
let mut lsp_edits = Vec::new();
let mut seen_edits = HashSet::new();
if seen_edits.insert(edit.clone()) { lsp_edits.push(edit); }

zed-0002: Pre-build HashSet from existing manifest entries:

// Before
if !manifest.languages.contains(&relative_language_dir) {

// After
let existing_languages: HashSet<_> = manifest.languages.iter().cloned().collect();
if !existing_languages.contains(&relative_language_dir) {

Patch

Fixes available:

  • defects/zed/patch/zed-0001-lsp-edit-dedup-contains.patch
  • defects/zed/patch/zed-0002-extension-manifest-dedup.patch

Two-file patch across lsp_store.rs (two call sites) and extension_builder.rs (three loops). zed-0001: 50x speedup at E=100. zed-0002: 20x speedup at N=20.

What We Ask

Patches ready for review.

  1. Confirm receipt and assign a GitHub issue reference (zed-industries/zed).
  2. Assess severity — zed-0001 fires on every code action and format-on-save in the editor.
  3. Coordinate a disclosure date — we target 90 days from first contact.
  4. We will credit the Zed team in the public disclosure. Preferred acknowledgment format welcome.

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