java-topology/defects/lucene/patch/lucene-CLEAN.md
russell@unturf.com a629bd0bbf no-stone-unturned wave: 8 new defects, 15 CLEAN confirmations; count 621→629
New defects (all PASS):
- exim-0001: same_hosts() MX-segment O(H²) → AVL set O(H log H), 10.5x at H=20
- minecraft-0001: DependencySorter.isCyclic no visited set O(E^D) → O(E), 342,000x at D=24
- minecraft-0002: PistonStructureResolver toPush ArrayList O(N²) → HashSet O(N)
- minecraft-0003: RedstoneWireEvaluator Deque.contains O(N²) → HashSet O(N)
- minecraft-0004: MoveThroughVillageGoal visited List O(N²) → HashSet O(N)
- mpich-0001: group_lpid_to_rank O(N²) → HashMap O(N), 313x at N=1000
- ompi-0001: group_overlap process-name scan O(N×M) → HashMap O(N+M), 2048x
- pcl-0001: RegionGrowing::getSegmentFromPoint O(C×S) → point_labels[] O(1), 50000x

CLEAN confirmed: esbuild, express, koa, ktor, lucene, mpich-recvq, ompi-startup,
  prosody, roda, rust/rustc-wave2, signal-server, solana, wiredtiger, wireguard-tools,
  linux-kernel (pointer to linux/)
2026-03-29 16:11:50 -04:00

50 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Lucene CWE-407 Scan — CLEAN
**Date:** 2026-03-29
**Target:** Apache Lucene (`~/git/lucene/`)
**Language:** Java
**Version:** main branch (depth-1 clone)
## Scan Scope
| Area | Files Checked |
|------|--------------|
| `lucene/core/src/java/org/apache/lucene/index/` | IndexWriter, TieredMergePolicy, LogMergePolicy, TemporalMergePolicy, SegmentInfos, ReaderPool, DocumentsWriterPerThreadPool, BufferedUpdatesStream, UpgradeIndexMergePolicy, ConcurrentMergeScheduler, PerFieldMergeState |
| `lucene/core/src/java/org/apache/lucene/search/` | BooleanQuery |
| `lucene/core/src/java/org/apache/lucene/util/hnsw/` | UpdateGraphsUtils |
| `lucene/core/src/java/org/apache/lucene/codecs/perfield/` | PerFieldMergeState |
## Methodology
Searched for `List.contains()`, `ArrayList.contains()`, `Collection.contains()`, and `.indexOf()` calls nested inside loops over segment lists or merge candidates. Cross-referenced the declared type of each collection receiving a `.contains()` call.
## Findings
All `.contains()` calls in hot paths use hash-backed collections:
| Location | Collection | Type | Verdict |
|----------|-----------|------|---------|
| `TieredMergePolicy.java:316,765,938` | `merging` | `Set<SegmentCommitInfo>` (from `getMergingSegments()`) | O(1) |
| `LogMergePolicy.java:497` | `mergingSegments` | `Set<SegmentCommitInfo>` | O(1) |
| `TemporalMergePolicy.java` | `merging` | `Set<SegmentCommitInfo>` | O(1) |
| `IndexWriter.java:2268` | `pendingMerges` | `ArrayDeque<OneMerge>` — but call is not in inner loop, just poll loop once | O(D) one-shot |
| `IndexWriter.java:2268` | `runningMerges` | `HashSet<OneMerge>` | O(1) |
| `IndexWriter.java:3862` | `mergedSegmentNames` | `HashSet<String>` (constructed on line 3862) | O(1) |
| `IndexWriter.java:6445` | `alreadySeenSegments` | `Set<SegmentCommitInfo>` (parameter type) | O(1) |
| `IndexWriter.java:5482` | `mergeExceptions` | `ArrayList<OneMerge>` — called once in `addMergeException()`, not in a segment loop | O(E) isolated |
| `BooleanQuery.java:404,412` | `intersection` | `HashSet<Query>` | O(1) |
| `BooleanQuery.java:367368` | clause sets | `Collection<Query>` backed by map values (List per Occur) | rewrite-time, bounded clauses |
| `PerFieldMergeState.java:105,108` | `filteredNames` | `HashSet<String>` | O(1) |
| `UpdateGraphsUtils.java:45,74` | `j` | `IntHashSet` | O(1) |
## Notable Non-Defects
- **`IndexWriter.java:5482` `mergeExceptions.contains(merge)`**: `mergeExceptions` is an `ArrayList`, but `addMergeException()` is only called when a merge throws an exception (error path, infrequent). It is not called inside a per-segment loop. Not a hot path.
- **`IndexWriter.java:2268` `pendingMerges.contains(merge)`**: `pendingMerges` is an `ArrayDeque` (O(N) contains), and this is called inside a loop over `spec.merges` (up to N merges, each checked). This is `waitForMerges()` — only called when the caller explicitly waits for forced merges to complete. Not a per-document or per-query hot path. Excluded.
## Result
**CLEAN** — no CWE-407 defects confirmed in Lucene core.
The codebase consistently uses `Set<>` or `HashSet<>` for merge-state membership checks in the hot segment-iteration paths. The design is intentionally correct: `getMergingSegments()` returns a `Set<SegmentCommitInfo>` specifically so that callers can do O(1) membership checks in their segment-iteration loops.