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.
2.1 KiB
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)