java-topology/defects/tor/unit/TorKistSchedulerTest.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

151 lines
5.6 KiB
Java

package unit;
import java.util.*;
/**
* Unit test for tor-0003: kist_scheduler_run() re-add loop CWE-407.
*
* Defect: At the end of kist_scheduler_run() (scheduler_kist.c:756), channels
* in the `to_readd` list are guarded by smartlist_contains(cp, readd_chan)
* before re-insertion into the pending pqueue `cp`.
* smartlist_contains() is a linear pointer scan: O(|cp|) per call.
* For T channels in to_readd and C channels in cp: O(T * C) total.
* The code comment already notes the sched_heap_idx != -1 check is
* "in theory redundant with the smartlist_contains check".
*
* Fix: Remove the O(C) smartlist_contains call. Use only
* sched_heap_idx == -1 as the O(1) membership test.
* A channel is in cp iff its heap index is set (pqueue invariant).
*
* Model:
* Channel — has a heapIdx field (-1 means not in pqueue)
* DefectiveReadd — simulates the slow path: ArrayList.contains() O(C) per channel
* FixedReadd — simulates the fast path: heapIdx == -1 check O(1) per channel
*
* Measurement: count element-level pointer comparisons for each guard check.
*/
public class TorKistSchedulerTest {
// ── Channel model ─────────────────────────────────────────────────────────
static class Channel {
final int id;
int heapIdx; // -1 = not in pqueue
Channel(int id) {
this.id = id;
this.heapIdx = -1;
}
}
// ── Defective: simulates smartlist_contains(cp, readd_chan) ───────────────
/**
* Returns number of pointer comparisons performed (ArrayList.contains scan).
*/
static long defectiveGuard(List<Channel> cp, Channel readd_chan) {
long ops = 0;
for (Channel c : cp) {
ops++;
if (c == readd_chan) {
return ops; // found → skip re-add
}
}
return ops; // not found → would re-add
}
static long runSlow(List<Channel> cp, List<Channel> toReadd) {
long totalOps = 0;
// Simulate: each channel in to_readd that's NOT in cp gets re-added.
// We measure the cost of the contains check, not the add itself.
Set<Channel> cpSet = new HashSet<>(cp);
for (Channel readd : toReadd) {
totalOps += defectiveGuard(cp, readd);
// If truly not in cp, it would be added (we skip actual pqueue here)
}
return totalOps;
}
// ── Fixed: simulates heapIdx == -1 check ──────────────────────────────────
/**
* Returns number of comparisons: always 1 (single field read).
*/
static long fixedGuard(Channel readd_chan) {
// O(1): just check the heap index field
return 1L;
}
static long runFast(List<Channel> toReadd) {
long totalOps = 0;
for (Channel readd : toReadd) {
totalOps += fixedGuard(readd);
}
return totalOps;
}
// ── Test data generation ──────────────────────────────────────────────────
/**
* Build a scenario: C channels in the pending queue, T channels to re-add.
* Half the to_readd channels are already in cp (heap idx set);
* half are not (heap idx -1).
*/
static Object[] makeScenario(int C, int T) {
List<Channel> cp = new ArrayList<>();
for (int i = 0; i < C; i++) {
Channel c = new Channel(i);
c.heapIdx = i; // already in pqueue
cp.add(c);
}
List<Channel> toReadd = new ArrayList<>();
// Half from cp (already present)
for (int i = 0; i < T / 2; i++) {
toReadd.add(cp.get(i % C));
}
// Half are new channels (heap idx -1)
for (int i = 0; i < T - T / 2; i++) {
Channel fresh = new Channel(C + i);
fresh.heapIdx = -1;
toReadd.add(fresh);
}
return new Object[]{cp, toReadd};
}
// ── Main ─────────────────────────────────────────────────────────────────
public static void main(String[] args) {
int passed = 0;
int total = 0;
int[][] configs = {
{50, 20, 5}, // C=50, T=20, minFactor=5
{200, 50, 5}, // C=200, T=50, minFactor=5
{500, 100, 8}, // C=500, T=100, minFactor=8
{1000,200, 10}, // C=1000,T=200, minFactor=10
};
for (int[] cfg : configs) {
int C = cfg[0], T = cfg[1], minFactor = cfg[2];
total++;
@SuppressWarnings("unchecked")
Object[] scenario = makeScenario(C, T);
List<Channel> cp = (List<Channel>) scenario[0];
List<Channel> toReadd = (List<Channel>) scenario[1];
long slowOps = runSlow(cp, toReadd);
long fastOps = runFast(toReadd);
boolean ok = slowOps > fastOps * minFactor;
System.out.printf("tor-0003 C=%4d T=%3d: slow=%6d ops fast=%4d ops ratio=%.1fx %s%n",
C, T, slowOps, fastOps, (double) slowOps / fastOps,
ok ? "PASS" : "FAIL");
if (ok) passed++;
}
System.out.printf("%d/%d PASS%n", passed, total);
if (passed != total) System.exit(1);
}
}