java-topology/defects/nomad/unit/NomadTest.java
russell@unturf.com 783e406633 pygame/libgdx: CWE-407 findings
pygame: CLEAN — runtime uses dict/set throughout (O(1) membership)
libgdx-0002: ModelBuilder.rebuildReferences Array.contains O(P*M) — patch
libgdx-0005: Stage.touchDragged touchFocuses.contains O(F^2) — patch
libgdx-0006: AfterAction.delegate currentActions.indexOf O(W*A) per frame — patch
unit: extend LibGDXTest to 7 tests, all PASS (50x-1971x speedup measured)
2026-03-30 09:13:34 -04:00

76 lines
3.1 KiB
Java
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.

import java.util.*;
/**
* CWE-407 unit tests for Nomad new defects.
*
* nomad-0005: scheduler/reconciler/reconcile_cluster.go ~line 1337
* handleReconnectingAllocs() builds a []string replacements slice by following
* the NextAllocation linked list, then iterates all allocs with:
* slices.Contains(replacements, replacementAlloc.ID)
* This is O(|all| × |replacements|) = O(A × R).
* In a deployment with many reconnecting allocations and a large alloc set,
* this becomes effectively O(A²).
* Fix: map[string]struct{} built from the linked-list walk → O(1) membership.
*
* Note: nomad-0001 through nomad-0004 (bitmap port alloc, stream namespace
* filter, vault secrets dedup, checkstore difference) were found in a prior
* scan and carry UNDF-2026-000000476 through UNDF-2026-000000479.
* nomad-0005 is the reconnect reconciler defect first identified here.
*/
public class NomadTest {
// --- nomad-0005 simulation ---
static boolean containsReplacements_slice(List<String> replacements, String allocID) {
return replacements.contains(allocID); // O(R) — defect
}
static boolean containsReplacements_map(Set<String> replacementsSet, String allocID) {
return replacementsSet.contains(allocID); // O(1) — fix
}
static void testNomad0005() throws Exception {
int A = 2000; // total allocations in a large deployment
int R = 500; // length of replacement chain per reconnecting alloc
List<String> replacementsSlice = new ArrayList<>(R);
Set<String> replacementsSet = new HashSet<>(R);
for (int i = 0; i < R; i++) {
String id = "alloc-replace-" + i;
replacementsSlice.add(id);
replacementsSet.add(id);
}
// alloc IDs that the outer loop iterates over all allocations
List<String> allAllocIDs = new ArrayList<>(A);
for (int i = 0; i < A; i++) allAllocIDs.add("alloc-" + i);
// worst-case candidate: last entry in replacements (tail of chain)
String targetID = "alloc-replace-" + (R - 1);
long t0 = System.nanoTime();
int hitSlice = 0;
for (String id : allAllocIDs) {
if (containsReplacements_slice(replacementsSlice, targetID)) hitSlice++;
}
long sliceNs = System.nanoTime() - t0;
long t1 = System.nanoTime();
int hitMap = 0;
for (String id : allAllocIDs) {
if (containsReplacements_map(replacementsSet, targetID)) hitMap++;
}
long mapNs = System.nanoTime() - t1;
if (hitSlice != hitMap) throw new AssertionError("result mismatch: " + hitSlice + " vs " + hitMap);
double ratio = (double) sliceNs / Math.max(mapNs, 1);
System.out.printf("nomad-0005 PASS A=%d R=%d slice=%dns map=%dns ratio=%.1fx%n",
A, R, sliceNs, mapNs, ratio);
if (ratio < 5.0) throw new AssertionError("expected speedup >= 5x, got " + ratio);
}
public static void main(String[] args) throws Exception {
testNomad0005();
System.out.println("ALL PASS");
}
}