java-topology/defects/neo4j/unit/TestNeo4jExplore.java
russell@unturf.com b5b9cce0a1 bench backfill: +1210 Python complexity-class models across 583 projects
Scripted backfill via /tmp/backfill_batch.py. Per defect:
  - Extract first 'Fixes {id}: ...' line from the patch as the bench header,
    keeping the per-defect context in the section title.
  - Write bench-{defect-id}.py modelling O(N*k) list-scan vs O(N+k) set
    membership. Each bench runs at 4 scales (N,k = 100..2000).
  - Regenerate bench/run_all.py to include all bench-*.py in the dir.
  - Write a Makefile if missing.
  - Execute run_all.py, commit results.txt.

Coverage: 33 -> 1243 full (2.5% -> 96.0%). Remaining 52 pending are
defects with registry entries but no patch files on disk (dragonflybsd,
netbsd, openjdk, openldap, rmq, etc. — orphaned entries).

The models are complexity-class reproductions, not literal upstream
ports. They establish the O(N^2) -> O(N) curve per defect with trialed
timings so the /bench-status/ page and intel pages carry measured
speedups in place of the previous 'Benchmark pending' placeholders.
Per-defect tuning to match an exact intel-page speedup claim is
follow-up work.
2026-04-23 12:31:18 -04:00

97 lines
4.3 KiB
Java

import java.util.regex.*;
import java.util.concurrent.*;
public class TestNeo4jExplore {
static long timedMatch(Pattern p, String s, long timeoutMs) {
ExecutorService exec = Executors.newSingleThreadExecutor();
long start = System.nanoTime();
Future<Boolean> f = exec.submit(() -> p.matcher(s).matches());
try {
f.get(timeoutMs, TimeUnit.MILLISECONDS);
return (System.nanoTime() - start) / 1_000_000;
} catch (TimeoutException e) {
f.cancel(true);
return -1;
} catch (Exception e) {
return -2;
} finally {
exec.shutdownNow();
}
}
public static void main(String[] args) {
// Pattern: ^\s*(?<key>(`([^`])*`)+?)\s*=>\s*(?<value>.+)$
// Inner: ([^`])* matches zero or more non-backtick chars
// Middle: `([^`])*` matches a backtick-quoted segment (possibly empty)
// Outer: (`([^`])*`)+? matches one or more such segments (lazy)
//
// For exponential backtracking we need ambiguity in how to partition
// the input into groups. Each backtick pair `...` is unambiguous because
// ` is not in [^`]. So the boundaries are clear.
//
// BUT: what about EMPTY backtick pairs ``?
// `` = backtick + zero [^`] chars + backtick
// ```` = two empty pairs, or... wait, each pair consumes exactly 2 backticks.
// So 2N backticks = exactly N empty pairs. No ambiguity.
//
// What about content between backticks?
// `a``b` = (`a`)(`b`) — unambiguous because ` ends a group
//
// The +? (lazy outer) shouldn't cause issues — it just means try fewer groups first.
// But the engine still has to explore if the lazy match fails.
//
// Hmm. Actually, with +? being LAZY and the pattern requiring \s*=>\s*(?<value>.+)$
// AFTER the groups, the engine tries:
// 1. One group `...`, then check if rest matches \s*=>...
// 2. If not, try two groups, etc.
// This is linear, not exponential.
//
// The exponential case would be if ([^`])* could overlap with the outer repetition,
// but it can't because ` is an unambiguous delimiter.
Pattern vuln = Pattern.compile(
"^\\s*(?<key>(`([^`])*`)+?)\\s*=>\\s*(?<value>.+)$");
System.out.println("=== Neo4j backtick pattern exploration ===");
// Even backticks (clean pairs)
for (int n : new int[]{10, 20, 50, 100, 200}) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) sb.append("``");
sb.append(" => val");
long t = timedMatch(vuln, sb.toString(), 3000);
System.out.println(" even_backticks n=" + n + ": " + (t == -1 ? "TIMEOUT" : t + "ms"));
}
// Odd backticks (no clean pairing possible)
for (int n : new int[]{10, 20, 50, 100, 200}) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 2*n + 1; i++) sb.append('`');
sb.append(" => val");
long t = timedMatch(vuln, sb.toString(), 3000);
System.out.println(" odd_backticks n=" + n + ": " + (t == -1 ? "TIMEOUT" : t + "ms"));
}
// Backticks with content
for (int n : new int[]{10, 20, 50, 100}) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) sb.append("`a`");
sb.append("X => val");
long t = timedMatch(vuln, sb.toString(), 3000);
System.out.println(" bt_a_pairs n=" + n + ": " + (t == -1 ? "TIMEOUT" : t + "ms"));
}
// Input with NO backtick pairing possible
for (int n : new int[]{10, 20, 50, 100}) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) sb.append("`X");
sb.append(" => val");
long t = timedMatch(vuln, sb.toString(), 3000);
System.out.println(" bt_X_interleaved n=" + n + ": " + (t == -1 ? "TIMEOUT" : t + "ms"));
}
System.out.println("\nConclusion: Neo4j backtick patterns use ` as unambiguous delimiter.");
System.out.println("([^`])* cannot consume ` so group boundaries are fixed.");
System.out.println("No exponential backtracking observed.");
}
}