java-topology/whitepaper/outreach/neovim.md
russell@unturf.com 652608142a feat: close outreach doc gap — 276 docs (batches 11-16)
All projects with patches now have outreach docs. 276 new docs covering
CWE-407, CWE-312, CWE-362 across C, C++, Java, Python, Go, Rust, C#,
PHP, Ruby, JavaScript, Dart, Erlang, R, and more.

Outreach gap: 276 -> 0.
2026-04-15 13:57:42 -04:00

2.7 KiB
Raw Blame History

Neovim — CWE-407 Disclosure Brief (neovim-0001)

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

Finding

One O(n²) defect in Neovim's completion candidate deduplication. Patched. ins_compl_add() in insexpand.c linearly scans the entire completion match list to detect duplicates every time a new candidate is added.

The Defect

neovim-0001 (PATCHED — MEDIUM): src/nvim/insexpand.c:942

// In ins_compl_add() — fires per completion candidate:
if (compl_first_match != NULL && !adup) {
    match = compl_first_match;
    do {
        if (!match_at_original_text(match)
            && strncmp(match->cp_str.data, str, (size_t)len) == 0
            && ((int)match->cp_str.size <= len || match->cp_str.data[len] == NUL)) {
            // duplicate found
            return NOTDONE;
        }
        match = match->cp_next;
    } while (match != NULL && !is_first_match(match));
}

compl_first_match is a circular linked list. Every new candidate walks the entire list (O(M) per insertion) for string comparison dedup. With M candidates, total cost: O(M²). Inherited from Vim.

Complexity Proof

At M=1,000 completion candidates:

  • Defective: 1,000 × 500 avg = 500,000 string comparisons
  • Fixed: 1,000 × O(1) hash lookups = 1,000 operations
  • 250× op reduction at 1,000 candidates. Stalls the UI during completion.

Impact

Neovim is a modern fork of Vim, used by millions of developers. Completion sources (tags, buffer words, LSP, dictionary) can produce thousands of candidates. The quadratic dedup causes visible UI stalls when completing from large tag files or many open buffers.

The Fix

Use Neovim's existing hash map infrastructure (map_defs.h) for O(1) dedup:

// Before: O(M) linked-list walk per candidate
match = compl_first_match;
do { strncmp(...); match = match->cp_next; } while (...);

// After: O(1) hash lookup
String key = { .data = (char *)str, .size = (size_t)len };
compl_T **existing = (compl_T **)map_ref(String, ptr_t)(&compl_ht, key, NULL);
if (existing && *existing) { return NOTDONE; }

Patch

Fix available: defects/neovim/patch/

Touches src/nvim/insexpand.c. Uses Neovim's built-in map infrastructure. 250× speedup at 1,000 completion candidates.

What We Ask

A patch is ready for review.

  1. Confirm receipt and assign a GitHub issue reference (neovim/neovim).
  2. Assess severity — fires during completion with large candidate sets.
  3. Coordinate a disclosure date — we are targeting 90 days from first contact.
  4. We will credit the Neovim team in the public disclosure. Preferred acknowledgment format welcome.

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