package unit; import java.util.*; /** * CPythonTest — CWE-407 benchmark for cpython-0001 * * Models pkgutil.extend_path() O(N²) list-contains membership dedup * vs. O(N) parallel-set dedup. * * Real code (Lib/pkgutil.py:332-336): * for portion in portions: * if portion not in path: # O(n) list scan * path.append(portion) # n grows each iteration * * Fix: maintain parallel seen=set(path) for O(1) membership test. */ public class CPythonTest { static void bench(String label, Runnable slow, Runnable fast, long sOps, long fOps) { slow.run(); fast.run(); long t0 = System.nanoTime(); slow.run(); long sMs = (System.nanoTime() - t0) / 1_000_000; long t1 = System.nanoTime(); fast.run(); long fMs = (System.nanoTime() - t1) / 1_000_000; double speedup = fMs > 0 ? (double) sMs / fMs : 0; System.out.printf(" %-54s slow:%4dms (%,d ops) fast:%4dms (%,d ops) speedup:%.0fx%n", label, sMs, sOps, fMs, fOps, speedup); } /** Simulates extend_path list-contains dedup — returns total comparisons */ static long slowExtendPath(int N) { List path = new ArrayList<>(); long ops = 0; for (int i = 0; i < N; i++) { String portion = "portion-" + i; // simulate: if portion not in path boolean found = false; for (int j = 0; j < path.size(); j++) { ops++; if (path.get(j).equals(portion)) { found = true; break; } } if (!found) path.add(portion); } return ops; } /** Simulates fixed extend_path with parallel set — returns total ops */ static long fastExtendPath(int N) { List path = new ArrayList<>(); Set seen = new HashSet<>(N * 2); long ops = 0; for (int i = 0; i < N; i++) { String portion = "portion-" + i; ops++; // O(1) set probe if (seen.add(portion)) path.add(portion); } return ops; } public static void main(String[] args) { System.out.println("CPythonTest — cpython-0001: pkgutil.extend_path() list-contains → parallel set"); System.out.println(); System.out.println(" [pkgutil.extend_path() namespace package path dedup]"); int[][] cases = {{200, 10000}, {500, 5000}, {1000, 2000}}; for (int[] c : cases) { int N = c[0], R = c[1]; bench( String.format("N=%d portions, %,d extend_path() calls", N, R), () -> { for (int i = 0; i < R; i++) slowExtendPath(N); }, () -> { for (int i = 0; i < R; i++) fastExtendPath(N); }, (long) N * (N - 1) / 2 * R, (long) N * R ); } System.out.println(); System.out.println("Defect : Lib/pkgutil.py:332-336 — 'if portion not in path' list O(n) → O(n²) total"); System.out.println("Fix : seen = set(path); use 'if portion not in seen' → O(1) per check"); System.out.println("Ticket : cpython-0001-pkgutil-path-list-contains-quadratic.md"); System.out.println(); int pass = 0; long s0 = slowExtendPath(500), f0 = fastExtendPath(500); assert s0 > f0 * 50 : "cpython-0001 expected >50x; slow=" + s0 + " fast=" + f0; pass++; System.out.printf("%d/1 PASS — cpython-0001: CWE-407 in CPython pkgutil.extend_path()%n", pass); System.out.printf("Hotpath: every import of namespace package in scientific stacks / monorepos%n"); } }