java-topology/defects/cpython/unit/CpythonPkgutilTest.java
russell@unturf.com 9934133dcf whitepaper: 312 sites / 151 ecosystems — wave2+3 defect tables and PDF rebuild
Add 88 new defect entries to HIGH and MEDIUM tables:
  HIGH: mysql-0001/0002, mariadb-0001, redis-0001/0002, valkey-0001/0002, openvpn-0001,
        vlc-0001, prometheus-0001, otel-collector-0001, cockroachdb-0001..0004,
        tidb-0001..0008, kubernetes-0001/0002, go-0001, kotlin-0002, scala-0001,
        allegro5-0001, sdl2-0001, grafana-0001, clickhouse-0001, duckdb-0001,
        mongodb-0001, envoy-0001, istio-0001, cilium-0001, linkerd2-0001,
        linux-0001/0002/0003, tor-0002/0003, curl-0001, julia-0001, lua-0001,
        perl5-0001, nats-0001, spring-0003/0004, tomcat-0001, onos-0002, odl-0002

  MEDIUM: helm-0001, mariadb-0002, openssl-0001/0002, memcached-0001,
          cassandra-0001..0004, flink-0001, storm-0001/0002, zookeeper-0001..0003,
          pip-0001, gradle-0001, nginx-0001, haproxy-0001, caddy-0001, varnish-0001,
          ffmpeg-0001, gstreamer-0001, raylib-0001, love2d-0001, php-0001/0002,
          r-source-0001, cpython-0002, ruby-0001, rabbitmq-0003/0004, activemq-0001,
          ovs-0001, onos-0003, odl-0002, jetty-0001

PDF: 976K
2026-03-27 15:23:43 -04:00

125 lines
4.2 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.

package unit;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* CWE-407 unit test: cpython-0001
*
* Models pkgutil.extend_path() portion deduplication.
*
* DEFECT: for each portion, scan the accumulator list with O(n) contains().
* Total cost: O(n²) for n unique portions.
*
* FIX: maintain a parallel HashSet for O(1) membership; list preserves order.
* Total cost: O(n).
*
* Asserts: slowOps > fastOps * 10 at n=500 (actual ratio ≈ 250×).
*/
public class CpythonPkgutilTest {
/** Mirrors the defective pkgutil.extend_path loop. Returns comparison count. */
static long slow(int n) {
List<String> path = new ArrayList<>();
long ops = 0;
for (int i = 0; i < n; i++) {
String portion = "/opt/pkg" + i + "/ns";
// O(path.size()) scan — mirrors `if portion not in path`
boolean found = false;
for (String existing : path) {
ops++;
if (existing.equals(portion)) {
found = true;
break;
}
}
if (!found) {
path.add(portion);
}
}
return ops;
}
/** Mirrors the patched version: set for O(1) membership, list for order. */
static long fast(int n) {
List<String> path = new ArrayList<>();
Set<String> pathSet = new HashSet<>();
long ops = 0;
for (int i = 0; i < n; i++) {
String portion = "/opt/pkg" + i + "/ns";
ops++; // one hash probe — mirrors `if portion not in path_set`
if (!pathSet.contains(portion)) {
path.add(portion);
pathSet.add(portion);
}
}
return ops;
}
public static void main(String[] args) {
int passed = 0;
int total = 0;
// Test 1: slow is strictly more expensive than fast at n=100
{
total++;
int n = 100;
long sOps = slow(n);
long fOps = fast(n);
// Expected: sOps ≈ n*(n-1)/2 ≈ 4950; fOps = n = 100
boolean ok = sOps > fOps * 10L;
System.out.printf("Test 1 [n=100 slow=%d fast=%d ratio=%.1fx]: %s%n",
sOps, fOps, (double) sOps / fOps, ok ? "PASS" : "FAIL");
if (ok) passed++;
}
// Test 2: slow is at least 50× more expensive than fast at n=500
{
total++;
int n = 500;
long sOps = slow(n);
long fOps = fast(n);
// Expected: sOps ≈ 125000; fOps = 500
boolean ok = sOps > fOps * 50L;
System.out.printf("Test 2 [n=500 slow=%d fast=%d ratio=%.1fx]: %s%n",
sOps, fOps, (double) sOps / fOps, ok ? "PASS" : "FAIL");
if (ok) passed++;
}
// Test 3: slow is at least 200× more expensive than fast at n=1000
{
total++;
int n = 1000;
long sOps = slow(n);
long fOps = fast(n);
// Expected: sOps ≈ 500000; fOps = 1000
boolean ok = sOps > fOps * 200L;
System.out.printf("Test 3 [n=1000 slow=%d fast=%d ratio=%.1fx]: %s%n",
sOps, fOps, (double) sOps / fOps, ok ? "PASS" : "FAIL");
if (ok) passed++;
}
// Test 4: both produce identical result sets (correctness)
{
total++;
int n = 200;
List<String> slowPath = new ArrayList<>();
List<String> fastPath = new ArrayList<>();
Set<String> fastSet = new HashSet<>();
for (int i = 0; i < n; i++) {
String p = "/opt/pkg" + i + "/ns";
if (!slowPath.contains(p)) slowPath.add(p);
if (!fastSet.contains(p)) { fastPath.add(p); fastSet.add(p); }
}
boolean ok = slowPath.equals(fastPath);
System.out.printf("Test 4 [correctness n=200 equal=%b]: %s%n",
ok, ok ? "PASS" : "FAIL");
if (ok) passed++;
}
System.out.printf("%d/%d PASS%n", passed, total);
if (passed != total) System.exit(1);
}
}