java-topology/defects/tidb/unit/TiDBTest.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
6 KiB
Java

package unit;
import java.util.*;
/**
* TiDB CWE-407 unit tests — standalone, no JUnit.
*
* tidb-0001 getEnforcedMergeJoin / getNewJoinKeys offsets slices.Contains
* pkg/planner/core/operator/physicalop/physical_merge_join.go:173,513,527
*
* tidb-0002 mergeInAndNotEQLists removeValues slices.Contains
* pkg/planner/core/rule/rule_predicate_simplification.go:267
*/
public class TiDBTest {
// -----------------------------------------------------------------------
// tidb-0001: getNewJoinKeysByOffsets — slices.Contains vs map lookup
//
// Models: given N join keys and K offsets (already-placed keys), iterate
// all N keys and skip those whose position is in offsets.
// Slow: slices.Contains — O(K) per key, O(N*K) total.
// Fast: map/set — O(1) per key, O(N) total.
// -----------------------------------------------------------------------
/** Slow: scan offsets slice for every key position. Returns op count. */
static long mergeJoinSlowOps(int numJoinKeys, int numOffsets) {
List<Integer> offsets = new ArrayList<>();
Random rng = new Random(7);
Set<Integer> added = new HashSet<>();
while (offsets.size() < numOffsets) {
int o = rng.nextInt(numJoinKeys);
if (added.add(o)) offsets.add(o);
}
long ops = 0;
// getNewJoinKeysByOffsets inner loop: for each pos, scan offsets
for (int pos = 0; pos < numJoinKeys; pos++) {
for (int i = 0; i < offsets.size(); i++) {
ops++;
if (offsets.get(i) == pos) break;
}
}
return ops;
}
/** Fast: build map once, then O(1) lookup per key. Returns op count. */
static long mergeJoinFastOps(int numJoinKeys, int numOffsets) {
List<Integer> offsets = new ArrayList<>();
Random rng = new Random(7);
Set<Integer> added = new HashSet<>();
while (offsets.size() < numOffsets) {
int o = rng.nextInt(numJoinKeys);
if (added.add(o)) offsets.add(o);
}
long ops = 0;
// Build map: O(K)
Set<Integer> offsetSet = new HashSet<>(offsets);
ops += offsets.size(); // building cost
// getNewJoinKeysByOffsets inner loop: O(1) per pos
for (int pos = 0; pos < numJoinKeys; pos++) {
ops++; // one map lookup
offsetSet.contains(pos);
}
return ops;
}
// -----------------------------------------------------------------------
// tidb-0002: mergeInAndNotEQLists — removeValues slice vs map
//
// Models the filter pass: given N predicates and R indices to remove,
// iterate all N and check membership in the remove-set.
// Slow: slices.Contains — O(R) per predicate, O(N*R) total.
// Fast: map — O(1) per predicate, O(N) total.
// -----------------------------------------------------------------------
/** Slow: scan removeValues list for every predicate. Returns op count. */
static long predicateSimplifySlowOps(int numPredicates, int numRemoved) {
// Simulate a double-loop that marks some indices for removal
List<Integer> removeValues = new ArrayList<>();
// mark the first numRemoved predicates for removal (worst case: all removed come late)
for (int i = numPredicates - numRemoved; i < numPredicates; i++) {
removeValues.add(i);
}
long ops = 0;
// Filter pass: for each predicate, scan removeValues
for (int i = 0; i < numPredicates; i++) {
for (int j = 0; j < removeValues.size(); j++) {
ops++;
if (removeValues.get(j) == i) break;
}
}
return ops;
}
/** Fast: use a HashSet for O(1) removal check. Returns op count. */
static long predicateSimplifyFastOps(int numPredicates, int numRemoved) {
Set<Integer> removeSet = new HashSet<>();
for (int i = numPredicates - numRemoved; i < numPredicates; i++) {
removeSet.add(i);
}
long ops = 0;
// Filter pass: O(1) per predicate
for (int i = 0; i < numPredicates; i++) {
ops++; // one set lookup
removeSet.contains(i);
}
return ops;
}
// -----------------------------------------------------------------------
// Test runner
// -----------------------------------------------------------------------
public static void main(String[] args) {
int passed = 0;
int failed = 0;
// tidb-0001: join key counts
int[][] joinSizes = {{20, 10}, {50, 25}, {100, 50}, {200, 100}};
for (int[] sz : joinSizes) {
int n = sz[0], k = sz[1];
long slow = mergeJoinSlowOps(n, k);
long fast = mergeJoinFastOps(n, k);
// Slow should be significantly more: O(N*K) vs O(N+K)
// At N=20,K=10: slow~100, fast~30 → ratio ~3x minimum
boolean pass = slow > fast * 2;
System.out.printf("tidb-0001 N=%-4d K=%-4d slow=%6d fast=%4d ratio=%5.1fx %s%n",
n, k, slow, fast, (double) slow / fast, pass ? "PASS" : "FAIL");
if (pass) passed++; else failed++;
}
// tidb-0002: predicate + removed counts
int[][] predSizes = {{50, 25}, {100, 50}, {200, 100}, {500, 250}};
for (int[] sz : predSizes) {
int n = sz[0], r = sz[1];
long slow = predicateSimplifySlowOps(n, r);
long fast = predicateSimplifyFastOps(n, r);
// Slow = O(N*R), fast = O(N). At N=50,R=25: slow~625, fast~50 → 12.5x
boolean pass = slow > fast * 5;
System.out.printf("tidb-0002 N=%-4d R=%-4d slow=%6d fast=%4d ratio=%5.1fx %s%n",
n, r, slow, fast, (double) slow / fast, pass ? "PASS" : "FAIL");
if (pass) passed++; else failed++;
}
System.out.printf("%nTotal: %d/%d PASS%n", passed, passed + failed);
if (failed > 0) System.exit(1);
}
}