java-topology/defects/jitsi-meet-0004/SCAN-NOTES.md
russell@unturf.com 5575f6cd9c jitsi-meet+solvespace: 5-MOAD scan; 3 new CWE-407 defects
jitsi-meet-0003: av-moderation pendingAudio/Video/Desktop Array.find()
dedup O(P^2) in large moderated meetings — 249.5x op-count at P=500,
138.5x measured at P=2000. Fix: Map<id, participant> for O(1) dedup.

jitsi-meet-0004: visitors middleware delta Array.findIndex() per update
O(U*V) in large broadcast events — 15x at V=5000 U=1000. Fix: Map-based
apply-delta O(1) per join/leave.

solvespace-0002: VRML export colours_present std::vector + find_if
O(T*C) per triangle — 250x op-count at T=50k C=500. Fix: unordered_map
keyed by ToPackedInt() RGBA uint32.

MOAD-0002/0003/0004/0005: CLEAN for both targets.
All 13 unit tests PASS.
2026-03-31 22:42:46 -04:00

2.1 KiB
Raw Permalink Blame History

jitsi-meet-0004 — MOAD-0001 CWE-407

Location

react/features/visitors/middleware.ts, delta-updates callback, line 399-411

Pattern

O(U × V): Jitsi Meet supports large-scale broadcast meetings with thousands of "visitors" (view-only participants). Our visitors list is updated via a delta stream. On each batch of U updates, the middleware iterates every update and calls visitors.findIndex() to locate or confirm absence of a visitor in our current visitors array:

// middleware.ts line 399-411
updates.forEach(u => {
    if (u.s === 'j') {
        const index = visitors.findIndex(v => v.id === u.r);  // O(V) per update
        if (index === -1) {
            visitors.push({ id: u.r, name: u.n });
        } else {
            visitors[index] = { id: u.r, name: u.n };
        }
    } else if (u.s === 'l') {
        visitors = visitors.filter(v => v.id !== u.r);        // O(V) per leave
    }
});

Each join update is O(V) to find our slot. Each leave update is O(V) to filter. A burst of U updates with a visitor list of size V costs O(U × V).

Severity

HIGH. Jitsi Meet's visitors feature targets large-scale broadcasts. A 10,000-visitor broadcast receiving bursts of join/leave deltas during entry phase:

  • 1,000 delta updates × 10,000 visitor list = 10,000,000 comparisons.
  • With a Map: 1,000 × O(1) = 1,000 operations.
  • 10,000x overhead during our visitor entry surge.

Fix

Replace visitors array with Map<string, {id: string; name: string}> keyed by visitor ID. Join: map.set(u.r, {id: u.r, name: u.n}) — O(1). Leave: map.delete(u.r) — O(1). Convert to array only at dispatch(updateVisitorsList(...)). Also update initial load callback to use Map construction from Array.map().

All 5 MOADs

  • MOAD-0001: CONFIRMED (this defect)
  • MOAD-0002: CLEAN (Redux single-source-of-truth; visitors list is properly isolated)
  • MOAD-0003: CLEAN (no AsyncLocalStorage; visitor context is carried in Redux, not thread-local)
  • MOAD-0004: CLEAN (visitor IDs are JIDs/session IDs, no credentials logged)
  • MOAD-0005: CLEAN (JavaScript is single-threaded; no async cache races possible)