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
6 KiB
Java
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);
|
|
}
|
|
}
|