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
151 lines
5.6 KiB
Java
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);
|
|
}
|
|
}
|