undefect. CWE-407 — 92 sites, 42 ecosystems
B&W print-friendly diagrams + tinkerpop-0001 + wave-3 proof sections. Squash of 94 local commits onto remote master.
This commit is contained in:
parent
0a580b313d
commit
db29a08762
1311 changed files with 371202 additions and 1188 deletions
248
tools/Makefile
Normal file
248
tools/Makefile
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
# CWE-407 Scan Makefile
|
||||
# Tracks all scan targets, results, and triage state.
|
||||
# Results are files — make skips targets that are already up to date.
|
||||
#
|
||||
# Usage:
|
||||
# make scan-networkx # single target
|
||||
# make scan-critical # all critical-priority targets
|
||||
# make scan-networking # all networking targets
|
||||
# make scan-scientific # all scientific computing targets
|
||||
# make scan-databases # all database targets
|
||||
# make scan-eda # all EDA/chip targets
|
||||
# make scan-web-infra # all web infrastructure targets
|
||||
# make scan-all # everything
|
||||
# make report # summarize all completed results
|
||||
# make clean-results # remove all result files (re-run everything)
|
||||
#
|
||||
# Prerequisites:
|
||||
# ~/.unsandbox/accounts.csv must exist (see: un key)
|
||||
# Row 0: portal-playground, Row 1: russ-test (for -j2 parallel)
|
||||
# UN := path to un binary (default: ~/git/un-inception/build/un)
|
||||
|
||||
UN ?= $(HOME)/git/un-inception/build/un
|
||||
RESULTS := scan-results
|
||||
SCANS := scans
|
||||
|
||||
# Account slots from ~/.unsandbox/accounts.csv (0-based index)
|
||||
# -j2 uses both slots in parallel — no env vars needed
|
||||
ACCT1 ?= 1
|
||||
ACCT2 ?= 0
|
||||
|
||||
# Network mode: semitrusted required for targets that git clone
|
||||
NET_CLONE := -n semitrusted
|
||||
NET_NONE :=
|
||||
|
||||
# ── Result file targets ──────────────────────────────────────────────────────
|
||||
# Each target produces scan-results/<name>.txt
|
||||
# Make tracks freshness: re-run only if .sh is newer than .txt
|
||||
|
||||
$(RESULTS)/frrouting.txt: $(SCANS)/frrouting.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/networkx.txt: $(SCANS)/networkx.sh
|
||||
$(UN) --account $(ACCT2) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/exabgp.txt: $(SCANS)/exabgp.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/postgresql.txt: $(SCANS)/postgresql.sh
|
||||
$(UN) --account $(ACCT2) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/verilator.txt: $(SCANS)/verilator.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/yosys.txt: $(SCANS)/yosys.sh
|
||||
$(UN) --account $(ACCT2) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/sqlite.txt: $(SCANS)/sqlite.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/mysql.txt: $(SCANS)/mysql.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/bird.txt: $(SCANS)/bird.sh
|
||||
$(UN) --account $(ACCT2) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/onos.txt: $(SCANS)/onos.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/opendaylight.txt: $(SCANS)/opendaylight.sh
|
||||
$(UN) --account $(ACCT2) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/v8.txt: $(SCANS)/v8.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/spidermonkey.txt: $(SCANS)/spidermonkey.sh
|
||||
$(UN) --account $(ACCT2) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/bazel.txt: $(SCANS)/bazel.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/kicad.txt: $(SCANS)/kicad.sh
|
||||
$(UN) --account $(ACCT2) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/gnu-octave.txt: $(SCANS)/gnu-octave.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/php-zend.txt: $(SCANS)/php-zend.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/redis.txt: $(SCANS)/redis.sh
|
||||
$(UN) --account $(ACCT2) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/varnish.txt: $(SCANS)/varnish.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/nginx.txt: $(SCANS)/nginx.sh
|
||||
$(UN) --account $(ACCT2) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/apache2.txt: $(SCANS)/apache2.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/memcached.txt: $(SCANS)/memcached.sh
|
||||
$(UN) --account $(ACCT2) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/ant.txt: $(SCANS)/ant.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/sbt.txt: $(SCANS)/sbt.sh
|
||||
$(UN) --account $(ACCT2) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/bundler.txt: $(SCANS)/bundler.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/duckdb.txt: $(SCANS)/duckdb.sh
|
||||
$(UN) --account $(ACCT2) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/composer.txt: $(SCANS)/composer.sh
|
||||
$(UN) --account $(ACCT1) $(NET_CLONE) $< | tee $@
|
||||
|
||||
$(RESULTS)/full-43lang.txt: ../tools/unsandbox-scan.sh
|
||||
$(UN) --account $(ACCT1) $(NET_NONE) $< | tee $@
|
||||
|
||||
# ── Grouped phony targets ────────────────────────────────────────────────────
|
||||
|
||||
.PHONY: scan-critical scan-networking scan-scientific scan-databases \
|
||||
scan-eda scan-compilers scan-web-infra scan-package-managers scan-all \
|
||||
scan-frrouting scan-networkx scan-exabgp scan-postgresql scan-sqlite \
|
||||
scan-verilator scan-yosys scan-mysql scan-bird scan-onos \
|
||||
scan-opendaylight scan-v8 scan-spidermonkey scan-bazel \
|
||||
scan-kicad scan-gnu-octave scan-php-zend scan-redis \
|
||||
scan-varnish scan-nginx scan-apache2 scan-memcached \
|
||||
scan-ant scan-sbt scan-bundler scan-duckdb scan-composer \
|
||||
scan-43lang report clean-results help
|
||||
|
||||
# Convenience aliases
|
||||
scan-frrouting: $(RESULTS)/frrouting.txt
|
||||
scan-networkx: $(RESULTS)/networkx.txt
|
||||
scan-exabgp: $(RESULTS)/exabgp.txt
|
||||
scan-postgresql: $(RESULTS)/postgresql.txt
|
||||
scan-sqlite: $(RESULTS)/sqlite.txt
|
||||
scan-verilator: $(RESULTS)/verilator.txt
|
||||
scan-yosys: $(RESULTS)/yosys.txt
|
||||
scan-mysql: $(RESULTS)/mysql.txt
|
||||
scan-bird: $(RESULTS)/bird.txt
|
||||
scan-onos: $(RESULTS)/onos.txt
|
||||
scan-opendaylight: $(RESULTS)/opendaylight.txt
|
||||
scan-v8: $(RESULTS)/v8.txt
|
||||
scan-spidermonkey: $(RESULTS)/spidermonkey.txt
|
||||
scan-bazel: $(RESULTS)/bazel.txt
|
||||
scan-kicad: $(RESULTS)/kicad.txt
|
||||
scan-gnu-octave: $(RESULTS)/gnu-octave.txt
|
||||
scan-php-zend: $(RESULTS)/php-zend.txt
|
||||
scan-redis: $(RESULTS)/redis.txt
|
||||
scan-varnish: $(RESULTS)/varnish.txt
|
||||
scan-nginx: $(RESULTS)/nginx.txt
|
||||
scan-apache2: $(RESULTS)/apache2.txt
|
||||
scan-memcached: $(RESULTS)/memcached.txt
|
||||
scan-ant: $(RESULTS)/ant.txt
|
||||
scan-sbt: $(RESULTS)/sbt.txt
|
||||
scan-bundler: $(RESULTS)/bundler.txt
|
||||
scan-duckdb: $(RESULTS)/duckdb.txt
|
||||
scan-composer: $(RESULTS)/composer.txt
|
||||
scan-43lang: $(RESULTS)/full-43lang.txt
|
||||
|
||||
# Priority groups
|
||||
scan-critical: scan-frrouting scan-networkx scan-exabgp
|
||||
|
||||
scan-networking: \
|
||||
scan-frrouting scan-exabgp scan-bird scan-onos scan-opendaylight
|
||||
|
||||
scan-scientific: \
|
||||
scan-networkx scan-gnu-octave
|
||||
|
||||
scan-databases: \
|
||||
scan-postgresql scan-sqlite scan-mysql
|
||||
|
||||
scan-eda: \
|
||||
scan-verilator scan-yosys scan-kicad
|
||||
|
||||
scan-compilers: \
|
||||
scan-v8 scan-spidermonkey scan-bazel
|
||||
|
||||
scan-web-infra: \
|
||||
scan-php-zend scan-redis scan-varnish scan-nginx scan-apache2 scan-memcached
|
||||
|
||||
scan-package-managers: \
|
||||
scan-ant scan-sbt scan-bundler scan-duckdb scan-composer
|
||||
|
||||
scan-all: \
|
||||
scan-critical scan-networking scan-scientific \
|
||||
scan-databases scan-eda scan-compilers scan-web-infra scan-43lang
|
||||
|
||||
# ── Report ───────────────────────────────────────────────────────────────────
|
||||
|
||||
report:
|
||||
@echo ""
|
||||
@echo "═══════════════════════════════════════════════════════"
|
||||
@echo " CWE-407 Scan Report — $(shell date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
@echo "═══════════════════════════════════════════════════════"
|
||||
@echo ""
|
||||
@total=0; \
|
||||
for f in $(RESULTS)/*.txt; do \
|
||||
[ -f "$$f" ] || continue; \
|
||||
target=$$(basename $$f .txt); \
|
||||
hits=$$(grep -c '^CANDIDATE' "$$f" 2>/dev/null || true); \
|
||||
hits=$${hits:-0}; \
|
||||
total=$$((total + hits)); \
|
||||
if [ "$$hits" -gt 0 ]; then \
|
||||
printf " %-20s %3d candidates\n" "$$target" "$$hits"; \
|
||||
grep '^CANDIDATE' "$$f" | head -3 | sed 's/^/ /'; \
|
||||
else \
|
||||
printf " %-20s CLEAN\n" "$$target"; \
|
||||
fi; \
|
||||
echo ""; \
|
||||
done; \
|
||||
echo " Total candidates: $$total"
|
||||
@echo "═══════════════════════════════════════════════════════"
|
||||
@echo ""
|
||||
|
||||
# ── Maintenance ──────────────────────────────────────────────────────────────
|
||||
|
||||
clean-results:
|
||||
rm -f $(RESULTS)/*.txt
|
||||
@echo "All result files removed — next make scan-* will re-run from scratch"
|
||||
|
||||
help:
|
||||
@echo ""
|
||||
@echo "Targets:"
|
||||
@echo " scan-critical frrouting, networkx, exabgp (highest impact)"
|
||||
@echo " scan-networking all routing/SDN targets"
|
||||
@echo " scan-scientific networkx, gnu-octave"
|
||||
@echo " scan-databases postgresql, mysql"
|
||||
@echo " scan-eda verilator, yosys, kicad"
|
||||
@echo " scan-compilers v8, spidermonkey, bazel"
|
||||
@echo " scan-web-infra php-zend, redis, varnish, nginx, apache2, memcached"
|
||||
@echo " scan-43lang full golden-image scan (no clone needed)"
|
||||
@echo " scan-all everything"
|
||||
@echo " report summarize all completed results"
|
||||
@echo " clean-results force re-run of all scans"
|
||||
@echo ""
|
||||
@echo "Variables:"
|
||||
@echo " UN=path path to un binary (default: ~/git/un-inception/build/un)"
|
||||
@echo " ACCT1=N primary account index in ~/.unsandbox/accounts.csv (default: 1)"
|
||||
@echo " ACCT2=N secondary account index (default: 0, used for -j2 parallel)"
|
||||
@echo ""
|
||||
@echo "Parallel execution (uses both account slots):"
|
||||
@echo " make -j2 scan-critical"
|
||||
@echo ""
|
||||
40
tools/mc-bench/README.md
Normal file
40
tools/mc-bench/README.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# mc-bench — Minecraft Server Load Benchmark
|
||||
|
||||
Benchmarks vanilla vs patched Minecraft server-26.1 under simulated load.
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
# JDK 25 required
|
||||
JAVA=/tmp/jdk25/bin/java
|
||||
# Server jar (bundler)
|
||||
SERVER_JAR=/home/fox/Downloads/server.jar
|
||||
# Install both servers
|
||||
bash bench-server.sh vanilla 40
|
||||
bash bench-server.sh patched 40
|
||||
```
|
||||
|
||||
## Tools
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `bench-server.sh` | Full benchmark: startup + `/reload` + bot wave |
|
||||
| `gen-modpack-tags.py` | Generates synthetic depth-N diamond tag data |
|
||||
| `raw-connect.mjs` | Raw TCP handshake bot (version-agnostic) |
|
||||
| `sim-players.mjs` | mineflayer bot runner (requires matching protocol version) |
|
||||
| `rcon.py` | RCON command injection |
|
||||
|
||||
## What it measures
|
||||
|
||||
- **Startup time** (wall clock, JVM launch → "Done")
|
||||
- **/reload time** (RCON-triggered, measures tag reload)
|
||||
- **Connection capacity** (how many handshakes the server accepts simultaneously)
|
||||
- **Handshake latency** (p50/p95/max)
|
||||
|
||||
## Notes
|
||||
|
||||
- Real-world improvement requires a genuine modpack with tag depth ≥ 10.
|
||||
- Synthetic tag data uses HashMap iteration (hash-ordered), which may not trigger
|
||||
worst-case DFS. Real modpacks load tags alphabetically (base before root) which
|
||||
reliably triggers the exponential in vanilla.
|
||||
- See `tests/bench/LoadSimBenchmark.java` for controlled algorithmic benchmark.
|
||||
205
tools/mc-bench/bench-server.sh
Executable file
205
tools/mc-bench/bench-server.sh
Executable file
|
|
@ -0,0 +1,205 @@
|
|||
#!/usr/bin/env bash
|
||||
# bench-server.sh — benchmark a Minecraft server: startup + /reload + bot load
|
||||
#
|
||||
# Usage: ./bench-server.sh <tier> [bot-count] [--play]
|
||||
#
|
||||
# Tiers:
|
||||
# unpatched control — vanilla jar, depth-16 datapack (defect present)
|
||||
# mitigated fix applied — patched jar, depth-16 datapack (same game, fast)
|
||||
# enriched new territory — patched jar, depth-24 300-ns datapack (impossible before patch)
|
||||
#
|
||||
# Aliases: vanilla=unpatched, patched=mitigated
|
||||
#
|
||||
# --play: after benchmarks, keep server up for human play testing.
|
||||
# Prints connection info and waits for Ctrl-C.
|
||||
set -euo pipefail
|
||||
export PYTHONUNBUFFERED=1
|
||||
|
||||
TIER="${1:-unpatched}"
|
||||
BOTS="${2:-20}"
|
||||
|
||||
# --play flag: accept anywhere in args
|
||||
PLAY_MODE=0
|
||||
for _arg in "$@"; do [ "$_arg" = "--play" ] && PLAY_MODE=1; done
|
||||
|
||||
# ── Tier configuration ────────────────────────────────────────────────────────
|
||||
case "$TIER" in
|
||||
unpatched|vanilla)
|
||||
TIER=unpatched
|
||||
DIR=/tmp/mc-bench/unpatched
|
||||
PORT=25565
|
||||
RCON=25575
|
||||
SERVER_JAR=/home/fox/Downloads/server.jar
|
||||
DATAPACK_DEPTH=16
|
||||
DATAPACK_NS=200
|
||||
DATAPACK_XREFS=6
|
||||
TIER_NOTE="control — DependencySorter defect present"
|
||||
;;
|
||||
mitigated|patched)
|
||||
TIER=mitigated
|
||||
DIR=/tmp/mc-bench/mitigated
|
||||
PORT=25566
|
||||
RCON=25576
|
||||
SERVER_JAR=/tmp/mc-bench/server-patched.jar
|
||||
DATAPACK_DEPTH=16
|
||||
DATAPACK_NS=200
|
||||
DATAPACK_XREFS=6
|
||||
TIER_NOTE="fix applied — same game, defect eliminated"
|
||||
;;
|
||||
enriched)
|
||||
DIR=/tmp/mc-bench/enriched
|
||||
PORT=25567
|
||||
RCON=25577
|
||||
SERVER_JAR=/tmp/mc-bench/server-patched.jar
|
||||
DATAPACK_DEPTH=48
|
||||
DATAPACK_NS=1000
|
||||
DATAPACK_XREFS=32
|
||||
TIER_NOTE="enriched — D=48 / 1000 NS / 32 xrefs: impossible before patch"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 unpatched|mitigated|enriched [bot-count] [--play]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
JAVA=/tmp/jdk25/bin/java
|
||||
LOG="$DIR/bench.log"
|
||||
FIFO="$DIR/server.stdin"
|
||||
|
||||
pkill -f "port $PORT " 2>/dev/null || true
|
||||
sleep 1
|
||||
rm -f "$LOG" "$FIFO"
|
||||
rm -rf "$DIR/world"
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
python3 "$SCRIPT_DIR/gen-modpack-tags.py" "$DIR" "$DATAPACK_DEPTH" "$DATAPACK_NS" "$DATAPACK_XREFS"
|
||||
|
||||
mkfifo "$FIFO"
|
||||
|
||||
echo "=========================================="
|
||||
echo " $TIER — Minecraft Server Benchmark"
|
||||
echo " $TIER_NOTE"
|
||||
echo "=========================================="
|
||||
echo " depth-${DATAPACK_DEPTH} ${DATAPACK_NS} namespaces ${DATAPACK_XREFS} xrefs · $BOTS bots"
|
||||
echo ""
|
||||
|
||||
# ── §1 Startup ────────────────────────────────────────────────────────────────
|
||||
echo "§1 Starting server..."
|
||||
START_MS=$(date +%s%3N)
|
||||
|
||||
exec 3<>"$FIFO"
|
||||
|
||||
(cd "$DIR" && exec $JAVA -Xmx3G -Xms512m \
|
||||
--enable-native-access=ALL-UNNAMED \
|
||||
-DbundlerRepoDir=. \
|
||||
-jar "$SERVER_JAR" \
|
||||
--nogui --port "$PORT" \
|
||||
<"$FIFO" >>"$LOG" 2>&1) &
|
||||
SERVER_PID=$!
|
||||
|
||||
for i in $(seq 1 180); do
|
||||
sleep 1
|
||||
if grep -q "Done (" "$LOG" 2>/dev/null; then
|
||||
STARTUP_MS=$(( $(date +%s%3N) - START_MS ))
|
||||
DONE_LINE=$(grep "Done (" "$LOG" | tail -1)
|
||||
echo " startup: ${STARTUP_MS} ms"
|
||||
echo " server: $DONE_LINE"
|
||||
break
|
||||
fi
|
||||
if ! kill -0 $SERVER_PID 2>/dev/null; then
|
||||
echo "ERROR: server exited prematurely"
|
||||
tail -12 "$LOG"
|
||||
exit 1
|
||||
fi
|
||||
[ $(( i % 10 )) -eq 0 ] && echo " ...${i}s"
|
||||
done
|
||||
|
||||
if ! grep -q "Done (" "$LOG" 2>/dev/null; then
|
||||
echo "ERROR: did not start in 180s"
|
||||
kill $SERVER_PID 2>/dev/null
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sleep 2 # let RCON bind
|
||||
|
||||
# ── §2 First bot wave ─────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "§2 First bot wave: $BOTS bots joining..."
|
||||
node "$SCRIPT_DIR/raw-connect.mjs" localhost "$PORT" "$BOTS" 2>&1
|
||||
sleep 2
|
||||
|
||||
# ── §3 /reload timing ─────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "§3 /reload timing..."
|
||||
|
||||
RELOAD_LINE=$(wc -l < "$LOG")
|
||||
RELOAD_START=$(date +%s%3N)
|
||||
|
||||
python3 "$SCRIPT_DIR/rcon.py" localhost "$RCON" benchpass "reload" 2>&1 || \
|
||||
{ echo "RCON failed, sending via stdin"; echo "reload" >&3; }
|
||||
|
||||
RELOAD_MS=""
|
||||
for i in $(seq 1 180); do
|
||||
sleep 1
|
||||
if tail -n +"$RELOAD_LINE" "$LOG" 2>/dev/null | grep -qE "Loaded [0-9]+ recipes"; then
|
||||
RELOAD_MS=$(( $(date +%s%3N) - RELOAD_START ))
|
||||
echo " /reload: ${RELOAD_MS} ms"
|
||||
tail -n +"$RELOAD_LINE" "$LOG" | grep -E "Loaded [0-9]+ (recipes|advancements)" | head -3 | while IFS= read -r l; do echo " $l"; done
|
||||
break
|
||||
fi
|
||||
done
|
||||
[ -z "$RELOAD_MS" ] && { echo " /reload: did not complete in 180s"; RELOAD_MS="-1"; }
|
||||
|
||||
# ── §4 Second bot wave (post-reload) ─────────────────────────────────────────
|
||||
echo ""
|
||||
echo "§4 Post-reload bot wave: $BOTS bots..."
|
||||
node "$SCRIPT_DIR/raw-connect.mjs" localhost "$PORT" "$BOTS" 2>&1
|
||||
|
||||
# ── §5 Play test mode (human) ─────────────────────────────────────────────────
|
||||
if [ "$PLAY_MODE" = "1" ]; then
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " PLAY TEST MODE — server staying up"
|
||||
echo "=========================================="
|
||||
echo " Connect to: localhost:$PORT"
|
||||
echo " Tier: $TIER ($TIER_NOTE)"
|
||||
echo " Log: $LOG"
|
||||
echo ""
|
||||
echo " Press Ctrl-C to stop the server and finish benchmark."
|
||||
echo ""
|
||||
# Wait for Ctrl-C; trap cleans up
|
||||
trap 'echo ""; echo "Stopping server..."; echo "stop" >&3; exec 3>&-; wait $SERVER_PID 2>/dev/null || true; rm -f "$FIFO"; echo "Server stopped."; exit 0' INT TERM
|
||||
while kill -0 $SERVER_PID 2>/dev/null; do sleep 5; done
|
||||
echo "Server exited on its own."
|
||||
exec 3>&- 2>/dev/null || true
|
||||
rm -f "$FIFO"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── Stop ─────────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "Stopping server..."
|
||||
echo "stop" >&3
|
||||
exec 3>&-
|
||||
wait $SERVER_PID 2>/dev/null || true
|
||||
rm -f "$FIFO"
|
||||
|
||||
# ── Results ──────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " $TIER RESULTS"
|
||||
echo "=========================================="
|
||||
echo " startup: ${STARTUP_MS} ms"
|
||||
echo " reload: ${RELOAD_MS} ms"
|
||||
echo " bots: $BOTS"
|
||||
echo " depth: $DATAPACK_DEPTH ns: $DATAPACK_NS xrefs: $DATAPACK_XREFS"
|
||||
echo ""
|
||||
cat > "$DIR/results.txt" << EOF
|
||||
label=$TIER
|
||||
startup_ms=$STARTUP_MS
|
||||
reload_ms=$RELOAD_MS
|
||||
bots=$BOTS
|
||||
datapack_depth=$DATAPACK_DEPTH
|
||||
datapack_ns=$DATAPACK_NS
|
||||
datapack_xrefs=$DATAPACK_XREFS
|
||||
EOF
|
||||
202
tools/mc-bench/gen-modpack-tags.py
Normal file
202
tools/mc-bench/gen-modpack-tags.py
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
gen-modpack-tags.py — generates synthetic modpack tag data for Minecraft server benchmarking.
|
||||
|
||||
Design: reliably triggers the exponential DependencySorter.isCyclic defect in vanilla
|
||||
Minecraft server by exploiting the two-pass dependency-building algorithm.
|
||||
|
||||
HOW THE DEFECT TRIGGERS
|
||||
========================
|
||||
DependencySorter.orderByDependencies() runs two sequential passes over contents (HashMap):
|
||||
|
||||
Pass 1: contents.forEach((k, v) -> v.visitRequiredDependencies(
|
||||
dep -> addDependencyIfNotCyclic(multimap, k, dep)))
|
||||
Pass 2: contents.forEach((k, v) -> v.visitOptionalDependencies(
|
||||
dep -> addDependencyIfNotCyclic(multimap, k, dep)))
|
||||
|
||||
Pass 1 adds ALL required edges into `multimap` (for all namespaces).
|
||||
Pass 2 then processes optional edges — and by then the multimap is FULLY POPULATED.
|
||||
|
||||
addDependencyIfNotCyclic calls isCyclic(multimap, src, dst) which recurses through
|
||||
dst's subtree WITHOUT a visited set. On a diamond DAG of depth D, this is O(2^D).
|
||||
|
||||
GENERATOR STRATEGY
|
||||
==================
|
||||
Required deps: all internal diamond edges (bbb_tier → bbb_tier, bbb_tier_1 → aaa_base)
|
||||
Optional deps: root → top-tier edges (zzz_root → bbb_tier_D_left/right)
|
||||
cross-namespace mid-refs (zzz_root → foreign bbb_tier_mid)
|
||||
|
||||
Result: after Pass 1 every namespace's full diamond is in `multimap`. Then Pass 2
|
||||
triggers isCyclic on EVERY zzz_root's optional edges — worst-case for 100% of
|
||||
namespaces, not just the ~1/34 that happen to win the HashMap ordering lottery.
|
||||
|
||||
Expected visits per namespace at depth D:
|
||||
2 × isCyclic calls × 2^(D+1) nodes each ≈ 4 × 2^D
|
||||
|
||||
With N=200 namespaces at D=16:
|
||||
vanilla: 200 × 4 × 2^16 ≈ 52 M recursive calls (~5 s at 100 ns/call)
|
||||
patched: 200 × 4 × (1 visited-set lookup) ≈ negligible
|
||||
|
||||
Usage: python3 gen-modpack-tags.py [server-dir [depth]]
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
|
||||
random.seed(42)
|
||||
|
||||
SERVER_DIR = sys.argv[1] if len(sys.argv) > 1 else "/tmp/mc-bench/vanilla"
|
||||
DEPTH = int(sys.argv[2]) if len(sys.argv) > 2 else 16
|
||||
NS_COUNT = int(sys.argv[3]) if len(sys.argv) > 3 else 200
|
||||
CROSS_REFS = int(sys.argv[4]) if len(sys.argv) > 4 else 6
|
||||
|
||||
# Real mod names first, padded with synthetic to reach NS_COUNT
|
||||
_REAL_NS = [
|
||||
"create", "ae2", "mekanism", "thermal", "botania",
|
||||
"immersiveengineering", "pneumaticraft", "naturesaura", "tinkers", "ars_nouveau",
|
||||
"occultism", "apotheosis", "cofh_core", "sophisticated_storage", "cyclic",
|
||||
"waystones", "refined_storage", "functional_storage", "modular_routers", "pipez",
|
||||
]
|
||||
_synth = max(0, NS_COUNT - len(_REAL_NS))
|
||||
MOD_NAMESPACES = _REAL_NS[:min(len(_REAL_NS), NS_COUNT)] + [f"simmod_{i:03d}" for i in range(_synth)]
|
||||
|
||||
WORLD_DIR = os.path.join(SERVER_DIR, "world")
|
||||
DATAPACK_DIR = os.path.join(WORLD_DIR, "datapacks", "modpack-sim", "data")
|
||||
|
||||
# ── Tag name helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
def ns_base(ns): return f"{ns}:aaa_base"
|
||||
def ns_left(ns, d): return f"{ns}:bbb_tier_{d:02d}_left"
|
||||
def ns_right(ns, d): return f"{ns}:bbb_tier_{d:02d}_right"
|
||||
def ns_root(ns): return f"{ns}:zzz_root"
|
||||
def ns_mid(ns): return ns_left(ns, DEPTH // 2)
|
||||
|
||||
# Tag JSON value entry helpers
|
||||
def required_ref(tag_id): return f"#{tag_id}"
|
||||
def optional_ref(tag_id): return {"id": f"#{tag_id}", "required": False}
|
||||
|
||||
|
||||
# ── Diamond builder ────────────────────────────────────────────────────────────
|
||||
|
||||
def build_namespace_tags(ns, other_namespaces):
|
||||
"""
|
||||
Build the full tag set for one namespace.
|
||||
|
||||
aaa_base ← leaf (minecraft:iron_ingot), REQUIRED
|
||||
↑ ↑ (required)
|
||||
bbb_tier_01_left bbb_tier_01_right ← both ref aaa_base ×2
|
||||
↑ ↑ (required)
|
||||
bbb_tier_02_* bbb_tier_02_*
|
||||
...
|
||||
bbb_tier_DEPTH_* bbb_tier_DEPTH_*
|
||||
↑ ↑ (OPTIONAL — triggers expensive isCyclic in Pass 2)
|
||||
zzz_root ──optional──> CROSS_REFS × foreign bbb_tier_mid nodes
|
||||
|
||||
Internal edges (required) → added to multimap in Pass 1 (no expensive isCyclic there,
|
||||
because multimap is sparse when each edge is processed in hash-bucket order).
|
||||
|
||||
zzz_root's optional edges → processed in Pass 2 when multimap is FULLY built →
|
||||
each triggers isCyclic that traverses the complete 2^DEPTH diamond.
|
||||
"""
|
||||
tags = {}
|
||||
|
||||
# Leaf: aaa_base (required item ref, no tag deps)
|
||||
tags[ns_base(ns)] = [required_ref("minecraft:iron_ingot")]
|
||||
|
||||
prev_l = ns_base(ns)
|
||||
prev_r = ns_base(ns)
|
||||
|
||||
for d in range(1, DEPTH + 1):
|
||||
l = ns_left(ns, d)
|
||||
r = ns_right(ns, d)
|
||||
# REQUIRED deps: internal diamond edges
|
||||
tags[l] = [required_ref(prev_l), required_ref(prev_r)]
|
||||
tags[r] = [required_ref(prev_l), required_ref(prev_r)]
|
||||
prev_l, prev_r = l, r
|
||||
|
||||
# zzz_root: OPTIONAL deps on top-tier diamond nodes → triggers exponential isCyclic
|
||||
cross = [
|
||||
optional_ref(ns_mid(o))
|
||||
for o in random.sample(other_namespaces, min(CROSS_REFS, len(other_namespaces)))
|
||||
]
|
||||
tags[ns_root(ns)] = [optional_ref(prev_l), optional_ref(prev_r)] + cross
|
||||
|
||||
return tags
|
||||
|
||||
|
||||
# ── Writers ───────────────────────────────────────────────────────────────────
|
||||
|
||||
def write_namespace_tags(ns, tags):
|
||||
for tag_id, values in tags.items():
|
||||
tag_ns, path = tag_id.split(":", 1)
|
||||
tag_file = os.path.join(DATAPACK_DIR, tag_ns, "tags", "item", f"{path}.json")
|
||||
os.makedirs(os.path.dirname(tag_file), exist_ok=True)
|
||||
with open(tag_file, "w") as f:
|
||||
json.dump({"replace": False, "values": values}, f, indent=2)
|
||||
|
||||
|
||||
def write_common_tags():
|
||||
"""Global aggregator in 'c' namespace + conventional per-mod aliases."""
|
||||
common_dir = os.path.join(DATAPACK_DIR, "c", "tags", "item")
|
||||
os.makedirs(common_dir, exist_ok=True)
|
||||
|
||||
# Top-level aggregator (optional refs — if a mod's root doesn't load, skip it)
|
||||
combined = {
|
||||
"replace": False,
|
||||
"values": [optional_ref(ns_root(ns)) for ns in MOD_NAMESPACES]
|
||||
}
|
||||
with open(os.path.join(common_dir, "zzz_combined_ingots.json"), "w") as f:
|
||||
json.dump(combined, f, indent=2)
|
||||
|
||||
# Per-mod aliases
|
||||
ingots_dir = os.path.join(common_dir, "ingots")
|
||||
os.makedirs(ingots_dir, exist_ok=True)
|
||||
for ns in MOD_NAMESPACES:
|
||||
with open(os.path.join(ingots_dir, f"{ns}.json"), "w") as f:
|
||||
json.dump({"replace": False, "values": [optional_ref(ns_root(ns))]}, f, indent=2)
|
||||
|
||||
|
||||
def write_pack_meta():
|
||||
meta_dir = os.path.join(WORLD_DIR, "datapacks", "modpack-sim")
|
||||
os.makedirs(meta_dir, exist_ok=True)
|
||||
with open(os.path.join(meta_dir, "pack.mcmeta"), "w") as f:
|
||||
json.dump({
|
||||
"pack": {
|
||||
"pack_format": 71,
|
||||
"description": (
|
||||
f"MC-0001 trigger: depth {DEPTH}, "
|
||||
f"{len(MOD_NAMESPACES)} namespaces, optional root deps"
|
||||
)
|
||||
}
|
||||
}, f, indent=2)
|
||||
|
||||
|
||||
# ── Main ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
print(f"Generating modpack datapack → {SERVER_DIR}/world/datapacks/modpack-sim/")
|
||||
print(f" depth: {DEPTH}, namespaces: {len(MOD_NAMESPACES)}, cross-refs/root: {CROSS_REFS}")
|
||||
|
||||
# Estimate: isCyclic traversal for 2 direct + CROSS_REFS foreign optional deps per zzz_root
|
||||
direct_calls = 2 * (2 ** (DEPTH + 1)) # per namespace: 2 roots × 2^(D+1) nodes
|
||||
cross_calls = CROSS_REFS * (2 ** (DEPTH // 2 + 1))
|
||||
vanilla_calls = len(MOD_NAMESPACES) * (direct_calls + cross_calls)
|
||||
patched_calls = len(MOD_NAMESPACES) * (2 + CROSS_REFS) # O(1) per call with visited set
|
||||
|
||||
print(f" expected vanilla isCyclic nodes visited: ~{vanilla_calls:,}")
|
||||
print(f" expected patched isCyclic nodes visited: ~{patched_calls:,}")
|
||||
print(f" theoretical speedup: ~{vanilla_calls // max(patched_calls, 1):,}×")
|
||||
|
||||
write_pack_meta()
|
||||
write_common_tags()
|
||||
|
||||
total_tags = 0
|
||||
for ns in MOD_NAMESPACES:
|
||||
others = [o for o in MOD_NAMESPACES if o != ns]
|
||||
tags = build_namespace_tags(ns, others)
|
||||
write_namespace_tags(ns, tags)
|
||||
total_tags += len(tags)
|
||||
|
||||
print(f" wrote {total_tags} tag files across {len(MOD_NAMESPACES)} namespaces")
|
||||
print("Done.")
|
||||
193
tools/mc-bench/raw-connect.mjs
Normal file
193
tools/mc-bench/raw-connect.mjs
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/**
|
||||
* raw-connect.mjs — raw Minecraft protocol handshake for any server version.
|
||||
*
|
||||
* Performs the LOGIN handshake only (does not need minecraft-data for the version).
|
||||
* Measures connection accept latency and capacity: how many simultaneous TCP
|
||||
* connections the server accepts before refusing.
|
||||
*
|
||||
* Protocol: Minecraft Handshake → Login Start → (server login success or kick)
|
||||
* Works with any version since the handshake packet structure is stable.
|
||||
*
|
||||
* Usage: node raw-connect.mjs <host> <port> <count>
|
||||
*/
|
||||
import net from 'net';
|
||||
|
||||
const HOST = process.argv[2] || 'localhost';
|
||||
const PORT = parseInt(process.argv[3] || '25565');
|
||||
const COUNT = parseInt(process.argv[4] || '20');
|
||||
|
||||
// ── Minecraft VarInt encoding ─────────────────────────────────────────────────
|
||||
function writeVarInt(val) {
|
||||
const bytes = [];
|
||||
do {
|
||||
let b = val & 0x7f;
|
||||
val >>>= 7;
|
||||
if (val !== 0) b |= 0x80;
|
||||
bytes.push(b);
|
||||
} while (val !== 0);
|
||||
return Buffer.from(bytes);
|
||||
}
|
||||
|
||||
function writeString(str) {
|
||||
const strBuf = Buffer.from(str, 'utf8');
|
||||
return Buffer.concat([writeVarInt(strBuf.length), strBuf]);
|
||||
}
|
||||
|
||||
function packet(id, ...bufs) {
|
||||
const payload = Buffer.concat([writeVarInt(id), ...bufs]);
|
||||
return Buffer.concat([writeVarInt(payload.length), payload]);
|
||||
}
|
||||
|
||||
// ── Handshake packet (ID 0x00, state HANDSHAKING) ────────────────────────────
|
||||
// Fields: protocol_version (VarInt), server_address (string), server_port (u16), next_state (VarInt=2 login)
|
||||
function handshakePacket(protocolVersion, host, port) {
|
||||
return packet(0x00,
|
||||
writeVarInt(protocolVersion), // protocol version
|
||||
writeString(host),
|
||||
Buffer.from([port >> 8, port & 0xff]),
|
||||
writeVarInt(2) // next state: LOGIN
|
||||
);
|
||||
}
|
||||
|
||||
// ── Login Start packet (ID 0x00, state LOGIN) ─────────────────────────────────
|
||||
// Fields: name (string), uuid (optional)
|
||||
function loginStartPacket(name) {
|
||||
return packet(0x00, writeString(name));
|
||||
}
|
||||
|
||||
// ── Connect one bot ───────────────────────────────────────────────────────────
|
||||
async function connectBot(index, protocolVersion) {
|
||||
return new Promise((resolve) => {
|
||||
const name = `bench_${String(index).padStart(3, '0')}`;
|
||||
const t0 = Date.now();
|
||||
const sock = new net.Socket();
|
||||
let done = false;
|
||||
|
||||
const finish = (status, detail) => {
|
||||
if (done) return;
|
||||
done = true;
|
||||
const ms = Date.now() - t0;
|
||||
sock.destroy();
|
||||
resolve({ index, name, status, detail, ms });
|
||||
};
|
||||
|
||||
sock.setTimeout(15000);
|
||||
sock.on('timeout', () => finish('timeout', 'connection timed out'));
|
||||
sock.on('error', (e) => finish('error', e.message));
|
||||
|
||||
sock.connect(PORT, HOST, () => {
|
||||
// Connected — send handshake then login start
|
||||
sock.write(handshakePacket(protocolVersion, HOST, PORT));
|
||||
sock.write(loginStartPacket(name));
|
||||
});
|
||||
|
||||
sock.on('data', (buf) => {
|
||||
// We just need to know the server responded (any response = accepted)
|
||||
// Response could be: Login Success (0x02), Login Disconnect (0x00), Set Compression (0x03)
|
||||
if (buf.length > 0) {
|
||||
// Check first packet byte after length VarInt: try to identify packet type
|
||||
const packetByte = buf[buf.length > 2 ? 2 : 1];
|
||||
let statusStr = 'connected';
|
||||
if (packetByte === 0x00) statusStr = 'kicked'; // Disconnect
|
||||
else if (packetByte === 0x02) statusStr = 'accepted'; // Login Success
|
||||
else if (packetByte === 0x03) statusStr = 'compress'; // Set Compression (pre-auth)
|
||||
finish(statusStr, `${buf.length} bytes`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ── Probe server for protocol version ────────────────────────────────────────
|
||||
async function probeVersion() {
|
||||
return new Promise((resolve) => {
|
||||
const sock = new net.Socket();
|
||||
sock.setTimeout(5000);
|
||||
sock.on('error', () => resolve(0));
|
||||
sock.on('timeout', () => { sock.destroy(); resolve(0); });
|
||||
|
||||
sock.connect(PORT, HOST, () => {
|
||||
// Status handshake: next_state=1 (STATUS)
|
||||
const handshake = packet(0x00,
|
||||
writeVarInt(0), // version 0 = unknown
|
||||
writeString(HOST),
|
||||
Buffer.from([PORT >> 8, PORT & 0xff]),
|
||||
writeVarInt(1) // STATUS
|
||||
);
|
||||
const statusReq = packet(0x00); // Status Request
|
||||
sock.write(Buffer.concat([handshake, statusReq]));
|
||||
});
|
||||
|
||||
sock.on('data', (buf) => {
|
||||
// Try to parse JSON from status response
|
||||
try {
|
||||
const str = buf.toString();
|
||||
const jsonStart = str.indexOf('{');
|
||||
const jsonEnd = str.lastIndexOf('}');
|
||||
if (jsonStart >= 0 && jsonEnd > jsonStart) {
|
||||
const json = JSON.parse(str.slice(jsonStart, jsonEnd + 1));
|
||||
const protocol = json?.version?.protocol || 0;
|
||||
const versionName = json?.version?.name || 'unknown';
|
||||
resolve({ protocol, name: versionName, players: json?.players });
|
||||
}
|
||||
} catch (_) {}
|
||||
sock.destroy();
|
||||
resolve(0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ── Main ─────────────────────────────────────────────────────────────────────
|
||||
console.log(`=== Minecraft Raw Connection Benchmark ===`);
|
||||
console.log(` server: ${HOST}:${PORT}`);
|
||||
console.log(` bots: ${COUNT}`);
|
||||
|
||||
// Probe server version
|
||||
const serverInfo = await probeVersion();
|
||||
const protocolVersion = typeof serverInfo === 'object' ? serverInfo.protocol : 0;
|
||||
if (typeof serverInfo === 'object') {
|
||||
console.log(` server version: ${serverInfo.name} (protocol ${protocolVersion})`);
|
||||
if (serverInfo.players) {
|
||||
console.log(` online: ${serverInfo.players.online}/${serverInfo.players.max}`);
|
||||
}
|
||||
}
|
||||
console.log(``);
|
||||
|
||||
if (!protocolVersion) {
|
||||
console.log('Could not probe server. Is it running?');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const wallStart = Date.now();
|
||||
const results = [];
|
||||
|
||||
// Spawn all connections with stagger
|
||||
for (let i = 0; i < COUNT; i++) {
|
||||
await new Promise(r => setTimeout(r, 100));
|
||||
results.push(connectBot(i, protocolVersion));
|
||||
process.stdout.write(`\r connecting ${i + 1}/${COUNT}...`);
|
||||
}
|
||||
console.log('');
|
||||
const all = await Promise.all(results);
|
||||
const wallMs = Date.now() - wallStart;
|
||||
|
||||
// Analyse
|
||||
const accepted = all.filter(r => ['accepted','compress','connected','kicked'].includes(r.status));
|
||||
const errors = all.filter(r => r.status === 'error' || r.status === 'timeout');
|
||||
const latencies = accepted.map(r => r.ms).sort((a,b) => a-b);
|
||||
|
||||
function pct(arr, p) {
|
||||
const i = Math.ceil(p/100*arr.length)-1;
|
||||
return arr[Math.max(0, Math.min(arr.length-1, i))];
|
||||
}
|
||||
|
||||
console.log(`=== Results ===`);
|
||||
console.log(` wall time: ${(wallMs/1000).toFixed(1)} s`);
|
||||
console.log(` accepted: ${accepted.length}/${COUNT}`);
|
||||
console.log(` errors: ${errors.length}`);
|
||||
if (latencies.length > 0) {
|
||||
console.log(` handshake latency:`);
|
||||
console.log(` p50: ${pct(latencies, 50)} ms`);
|
||||
console.log(` p95: ${pct(latencies, 95)} ms`);
|
||||
console.log(` max: ${latencies[latencies.length-1]} ms`);
|
||||
}
|
||||
console.log(``);
|
||||
35
tools/mc-bench/rcon.py
Normal file
35
tools/mc-bench/rcon.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Minimal RCON client for Minecraft server command injection."""
|
||||
import socket, struct, sys, time
|
||||
|
||||
def rcon(host, port, password, command, timeout=10):
|
||||
def packet(pid, ptype, body):
|
||||
b = body.encode() + b'\x00\x00'
|
||||
return struct.pack('<iii', 4 + 4 + len(b), pid, ptype) + b
|
||||
|
||||
def recv_packet(s):
|
||||
hdr = b''
|
||||
while len(hdr) < 4:
|
||||
hdr += s.recv(4 - len(hdr))
|
||||
length = struct.unpack('<i', hdr)[0]
|
||||
data = b''
|
||||
while len(data) < length:
|
||||
data += s.recv(length - len(data))
|
||||
return struct.unpack('<ii', data[:8])[0], struct.unpack('<ii', data[:8])[1], data[8:-2].decode('utf-8', errors='replace')
|
||||
|
||||
s = socket.socket()
|
||||
s.settimeout(timeout)
|
||||
s.connect((host, port))
|
||||
s.send(packet(1, 3, password)) # auth
|
||||
recv_packet(s)
|
||||
s.send(packet(2, 2, command)) # command
|
||||
_, _, resp = recv_packet(s)
|
||||
s.close()
|
||||
return resp
|
||||
|
||||
if __name__ == '__main__':
|
||||
host = sys.argv[1] if len(sys.argv) > 1 else 'localhost'
|
||||
port = int(sys.argv[2]) if len(sys.argv) > 2 else 25575
|
||||
password = sys.argv[3] if len(sys.argv) > 3 else 'benchpass'
|
||||
command = ' '.join(sys.argv[4:]) if len(sys.argv) > 4 else 'list'
|
||||
print(rcon(host, port, password, command))
|
||||
129
tools/mc-bench/sim-players.mjs
Normal file
129
tools/mc-bench/sim-players.mjs
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* sim-players.mjs — mineflayer bot load simulation
|
||||
*
|
||||
* Connects N bots to a running Minecraft server, measures:
|
||||
* - Time for all bots to successfully join
|
||||
* - TPS estimate via keepalive packet timing
|
||||
* - Bot join failure/timeout rate
|
||||
*
|
||||
* Usage:
|
||||
* node sim-players.mjs [host] [port] [bot-count]
|
||||
*
|
||||
* Example:
|
||||
* node sim-players.mjs localhost 25565 40
|
||||
*/
|
||||
|
||||
import mineflayer from 'mineflayer';
|
||||
|
||||
const HOST = process.argv[2] || 'localhost';
|
||||
const PORT = parseInt(process.argv[3] || '25565');
|
||||
const COUNT = parseInt(process.argv[4] || '20');
|
||||
const STAGGER_MS = 200; // ms between bot spawns — avoids login queue overflow
|
||||
|
||||
console.log(`=== Minecraft Bot Load Simulation ===`);
|
||||
console.log(` server: ${HOST}:${PORT}`);
|
||||
console.log(` bots: ${COUNT}`);
|
||||
console.log(` stagger: ${STAGGER_MS}ms between joins`);
|
||||
console.log(``);
|
||||
|
||||
const results = [];
|
||||
const wallStart = Date.now();
|
||||
|
||||
async function spawnBot(index) {
|
||||
return new Promise((resolve) => {
|
||||
const name = `bench_bot_${String(index).padStart(3, '0')}`;
|
||||
const t_spawn = Date.now();
|
||||
|
||||
const bot = mineflayer.createBot({
|
||||
host: HOST,
|
||||
port: PORT,
|
||||
username: name,
|
||||
version: false, // auto-detect from server handshake
|
||||
auth: 'offline',
|
||||
hideErrors: false,
|
||||
});
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
results.push({ index, name, status: 'timeout', latency: Date.now() - t_spawn });
|
||||
try { bot.end(); } catch (_) {}
|
||||
resolve();
|
||||
}, 30000);
|
||||
|
||||
bot.once('spawn', () => {
|
||||
clearTimeout(timeout);
|
||||
const latency = Date.now() - t_spawn;
|
||||
results.push({ index, name, status: 'ok', latency });
|
||||
|
||||
// Stay connected for 10 seconds, move around to simulate activity
|
||||
let moved = 0;
|
||||
const moveInterval = setInterval(() => {
|
||||
if (moved++ > 20) {
|
||||
clearInterval(moveInterval);
|
||||
bot.end();
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
// Random movement to generate chunk loading
|
||||
const dx = (Math.random() - 0.5) * 2;
|
||||
const dz = (Math.random() - 0.5) * 2;
|
||||
bot.entity.position.x += dx;
|
||||
bot.entity.position.z += dz;
|
||||
}, 500);
|
||||
});
|
||||
|
||||
bot.on('error', (err) => {
|
||||
clearTimeout(timeout);
|
||||
results.push({ index, name, status: 'error', msg: err.message, latency: Date.now() - t_spawn });
|
||||
resolve();
|
||||
});
|
||||
|
||||
bot.on('kicked', (reason) => {
|
||||
clearTimeout(timeout);
|
||||
results.push({ index, name, status: 'kicked', msg: reason, latency: Date.now() - t_spawn });
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Spawn bots with stagger
|
||||
const promises = [];
|
||||
for (let i = 0; i < COUNT; i++) {
|
||||
await new Promise(r => setTimeout(r, STAGGER_MS));
|
||||
promises.push(spawnBot(i));
|
||||
process.stdout.write(`\r spawning bot ${i + 1}/${COUNT}...`);
|
||||
}
|
||||
|
||||
console.log(`\r all ${COUNT} bots spawned, waiting for joins...`);
|
||||
await Promise.all(promises);
|
||||
|
||||
const wallMs = Date.now() - wallStart;
|
||||
|
||||
// Analyse results
|
||||
const ok = results.filter(r => r.status === 'ok');
|
||||
const failed = results.filter(r => r.status !== 'ok');
|
||||
const latencies = ok.map(r => r.latency).sort((a, b) => a - b);
|
||||
|
||||
function pct(arr, p) {
|
||||
const i = Math.ceil(p / 100 * arr.length) - 1;
|
||||
return arr[Math.max(0, Math.min(arr.length - 1, i))];
|
||||
}
|
||||
|
||||
console.log(``);
|
||||
console.log(`=== Results ===`);
|
||||
console.log(` wall time: ${(wallMs / 1000).toFixed(1)} s`);
|
||||
console.log(` successful: ${ok.length} / ${COUNT}`);
|
||||
console.log(` failed/kicked: ${failed.length}`);
|
||||
if (latencies.length > 0) {
|
||||
console.log(` join latency:`);
|
||||
console.log(` p50: ${pct(latencies, 50)} ms`);
|
||||
console.log(` p95: ${pct(latencies, 95)} ms`);
|
||||
console.log(` p99: ${pct(latencies, 99)} ms`);
|
||||
console.log(` max: ${latencies[latencies.length - 1]} ms`);
|
||||
}
|
||||
if (failed.length > 0) {
|
||||
console.log(` failures:`);
|
||||
for (const f of failed.slice(0, 5)) {
|
||||
console.log(` ${f.name}: ${f.status} — ${f.msg || ''}`);
|
||||
}
|
||||
}
|
||||
console.log(``);
|
||||
54
tools/mc-patch/README.md
Normal file
54
tools/mc-patch/README.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Minecraft DependencySorter Patch
|
||||
|
||||
Patched `server-26.1.jar` (inner jar, extracted from bundler) with fixed
|
||||
`DependencySorter.isCyclic` — adds `Set<K> visited` parameter to prevent
|
||||
exponential revisiting of diamond dependency graphs.
|
||||
|
||||
## Files
|
||||
|
||||
- `server-26.1-patched.jar` — inner jar with patched DependencySorter.class
|
||||
- `../defects/minecraft/DependencySorter-before.java` — decompiled original
|
||||
- `../defects/minecraft/DependencySorter-after.java` — fixed version
|
||||
|
||||
## To apply to a full server.jar
|
||||
|
||||
```python
|
||||
import zipfile, os
|
||||
|
||||
with open('server-26.1-patched.jar', 'rb') as f:
|
||||
patched_inner = f.read()
|
||||
|
||||
with zipfile.ZipFile('server.jar', 'r') as zin, \
|
||||
zipfile.ZipFile('server-patched.jar', 'w',
|
||||
compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zout:
|
||||
for item in zin.infolist():
|
||||
if item.filename == 'META-INF/versions/26.1/server-26.1.jar':
|
||||
zout.writestr(item, patched_inner)
|
||||
else:
|
||||
zout.writestr(item, zin.read(item.filename))
|
||||
```
|
||||
|
||||
## Why the signing is stripped
|
||||
|
||||
Mojang signs `server-26.1.jar` with SHA-384 manifests (`META-INF/MOJANGCS.SF`/`.RSA`).
|
||||
Any class modification invalidates the signature. The patched jar removes:
|
||||
- `META-INF/MOJANGCS.SF`
|
||||
- `META-INF/MOJANGCS.RSA`
|
||||
- Manifest stanzas for `DependencySorter.class` and `DependencySorter$Entry.class`
|
||||
|
||||
All other class digests are preserved intact.
|
||||
|
||||
## Benchmark
|
||||
|
||||
See `tests/bench/DependencySorterBenchmark.java`.
|
||||
|
||||
| Diamond depth | Tags | BEFORE (ns) | AFTER (ns) | Speedup |
|
||||
|---------------|------|-------------|------------|---------|
|
||||
| 8 | 18 | 98,384 | 22,779 | 4.3x |
|
||||
| 10 | 22 | 436,388 | 37,353 | 11.7x |
|
||||
| 12 | 26 | 1,633,446 | 51,872 | 31.5x |
|
||||
| 14 | 30 | 6,486,367 | 73,704 | 88.0x |
|
||||
| 16 | 34 | OVERFLOW | 98,626 | — |
|
||||
|
||||
Vanilla server (500 tags, shallow diamonds): no measurable boot difference.
|
||||
Large modpack (1000+ tags, depth 8-14): 11-88x speedup predicted.
|
||||
BIN
tools/mc-patch/server-26.1-all-patched.jar
Normal file
BIN
tools/mc-patch/server-26.1-all-patched.jar
Normal file
Binary file not shown.
BIN
tools/mc-patch/server-26.1-patched.jar
Normal file
BIN
tools/mc-patch/server-26.1-patched.jar
Normal file
Binary file not shown.
94
tools/run-unsandbox-scan.sh
Normal file
94
tools/run-unsandbox-scan.sh
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#!/usr/bin/env bash
|
||||
# Submit CWE-407 scan to all 43 unsandbox language sandboxes in parallel.
|
||||
# Results land in tools/scan-results/<lang>.txt
|
||||
#
|
||||
# Usage: bash tools/run-unsandbox-scan.sh [lang...]
|
||||
# No args = all 43 languages
|
||||
# With args = only those languages (e.g. bash ... haskell ocaml ruby)
|
||||
set -euo pipefail
|
||||
|
||||
UN=~/git/un-inception/build/un
|
||||
SCAN_SCRIPT="$(cd "$(dirname "$0")" && pwd)/unsandbox-scan.sh"
|
||||
RESULTS_DIR="$(cd "$(dirname "$0")" && pwd)/scan-results"
|
||||
mkdir -p "$RESULTS_DIR"
|
||||
|
||||
export UNSANDBOX_PUBLIC_KEY=unsb-pk-russ-test-isth-best
|
||||
export UNSANDBOX_SECRET_KEY=unsb-sk-rk46c-3zvpg-zjf6z-hjrge
|
||||
|
||||
ALL_LANGS=(
|
||||
python javascript typescript ruby perl php lua bash
|
||||
r elixir erlang tcl scheme powershell clojure commonlisp
|
||||
crystal groovy deno awk raku c cpp go rust java kotlin
|
||||
cobol fortran d zig nim v objc dart julia haskell ocaml
|
||||
fsharp csharp dotnet prolog forth
|
||||
)
|
||||
|
||||
LANGS=("${@:-${ALL_LANGS[@]}}")
|
||||
|
||||
echo "Submitting scan to ${#LANGS[@]} sandboxes..."
|
||||
echo ""
|
||||
|
||||
run_scan() {
|
||||
local lang="$1"
|
||||
local out="$RESULTS_DIR/${lang}.txt"
|
||||
local tmpscript="/tmp/cwe407-scan-${lang}.sh"
|
||||
|
||||
# Inject language name and write self-contained script
|
||||
{ echo "#!/usr/bin/env bash"
|
||||
echo "LANG=${lang}"
|
||||
tail -n +2 "$SCAN_SCRIPT"
|
||||
} > "$tmpscript"
|
||||
chmod +x "$tmpscript"
|
||||
|
||||
printf " [%-12s] submitting...\n" "$lang"
|
||||
local exit_code=0
|
||||
"$UN" "$tmpscript" > "$out" 2>&1 || exit_code=$?
|
||||
if [ $exit_code -eq 0 ] || grep -q "^CANDIDATE\|^# scan complete" "$out" 2>/dev/null; then
|
||||
local hits
|
||||
hits=$(grep -c "^CANDIDATE" "$out" 2>/dev/null || true)
|
||||
hits=${hits:-0}
|
||||
printf " [%-12s] done — %s candidates\n" "$lang" "$hits"
|
||||
else
|
||||
printf " [%-12s] ERROR: $(tail -1 "$out")\n" "$lang"
|
||||
fi
|
||||
rm -f "$tmpscript"
|
||||
}
|
||||
|
||||
export -f run_scan
|
||||
export UN SCAN_SCRIPT RESULTS_DIR
|
||||
|
||||
# Run with concurrency limit — default 2 for tier 5, override with CONCURRENCY env var
|
||||
MAX=${CONCURRENCY:-2}
|
||||
pids=()
|
||||
for lang in "${LANGS[@]}"; do
|
||||
run_scan "$lang" &
|
||||
pids+=($!)
|
||||
if (( ${#pids[@]} >= MAX )); then
|
||||
wait "${pids[0]}"
|
||||
pids=("${pids[@]:1}")
|
||||
fi
|
||||
sleep 1 # stagger submissions to avoid burst rejection
|
||||
done
|
||||
wait
|
||||
|
||||
echo ""
|
||||
echo "=== RESULTS SUMMARY ==="
|
||||
echo ""
|
||||
total_candidates=0
|
||||
for lang in "${LANGS[@]}"; do
|
||||
out="$RESULTS_DIR/${lang}.txt"
|
||||
if [ -f "$out" ]; then
|
||||
hits=$(grep -c "^CANDIDATE" "$out" 2>/dev/null || echo 0)
|
||||
roots=$(grep "^# roots:" "$out" | sed 's/# roots://' | tr ' ' '\n' | grep -v '^$' | wc -l || echo 0)
|
||||
if [ "$hits" -gt 0 ]; then
|
||||
printf " %-14s %2d candidates (roots: %d)\n" "$lang" "$hits" "$roots"
|
||||
grep "^CANDIDATE" "$out" | head -3 | sed 's/^/ /'
|
||||
else
|
||||
printf " %-14s CLEAN (roots: %d)\n" "$lang" "$roots"
|
||||
fi
|
||||
total_candidates=$(( total_candidates + hits ))
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
echo "Total candidates: $total_candidates"
|
||||
echo "Results in: $RESULTS_DIR/"
|
||||
91
tools/scan-cwe407.sh
Executable file
91
tools/scan-cwe407.sh
Executable file
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scanner: O(n) linear membership checks in graph traversal code.
|
||||
#
|
||||
# Pattern: Any call to a linear-scan membership check (.contains, "in list",
|
||||
# std::find, etc.) inside a function whose name suggests graph traversal
|
||||
# (tarjan, scc, dfs, topo, cycle, closure, reachab*).
|
||||
#
|
||||
# Usage:
|
||||
# scan-cwe407.sh <repo-root> [file-glob]
|
||||
#
|
||||
# Output: TSV — file:line | function-context | snippet | verdict
|
||||
#
|
||||
# Supports: .java .py .kt .scala .cpp .h .c .go .rs .rb .js .ts .cs .swift
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="${1:-.}"
|
||||
GLOB="${2:-}"
|
||||
|
||||
# ── Membership check patterns per language ─────────────────────────────────────
|
||||
JAVA_MEM='\.contains\s*\(|List\.contains|ArrayList\.contains|LinkedList\.contains|Deque\.contains|ArrayDeque\.contains'
|
||||
PY_MEM='[^a-z]in (stack|path|visited|seen|queue|nodes)|path\.append|\.contains\('
|
||||
KT_MEM='\.contains\s*\(|in\s+(?:stack|path|visited|list|nodes)\b'
|
||||
SCALA_MEM='\.contains\s*\(|\.exists\s*\{|List\.contains|Seq\.contains|ArrayBuffer\.contains'
|
||||
CPP_MEM='std::find[(]|[.]count[(]|linear_search|find.*begin.*end'
|
||||
GO_MEM='slices\.Contains|contains\s*\(.*\[\]|for.*range.*==\s*\w'
|
||||
RS_MEM='\.contains\s*\(&|iter\(\)\.any\s*\(|\.position\s*\('
|
||||
|
||||
# ── Graph/traversal function name patterns ─────────────────────────────────────
|
||||
GRAPH_FN='tarjan|scc|strongly.connected|dfs|bfs|topolog|topo.sort|cycle|closure|reachab|postorder|preorder|dominator|liveness|worklist|scfg|cfg'
|
||||
|
||||
# ── Scan a single file ─────────────────────────────────────────────────────────
|
||||
scan_file() {
|
||||
local f="$1"
|
||||
local ext="${f##*.}"
|
||||
local mem_pat=""
|
||||
|
||||
case "$ext" in
|
||||
java) mem_pat="$JAVA_MEM" ;;
|
||||
py) mem_pat="$PY_MEM" ;;
|
||||
kt|kts) mem_pat="$KT_MEM" ;;
|
||||
scala) mem_pat="$SCALA_MEM" ;;
|
||||
cpp|cc|cxx|h|hpp|c) mem_pat="$CPP_MEM" ;;
|
||||
go) mem_pat="$GO_MEM" ;;
|
||||
rs) mem_pat="$RS_MEM" ;;
|
||||
*) return ;;
|
||||
esac
|
||||
|
||||
# Two-pass: find graph-related functions first, then check for membership
|
||||
# within ±20 lines of any match.
|
||||
local graph_lines
|
||||
graph_lines=$(grep -inE "$GRAPH_FN" "$f" 2>/dev/null | cut -d: -f1 || true)
|
||||
[ -z "$graph_lines" ] && return
|
||||
|
||||
while IFS= read -r lineno; do
|
||||
local start=$(( lineno - 20 ))
|
||||
local end=$(( lineno + 20 ))
|
||||
[ $start -lt 1 ] && start=1
|
||||
|
||||
# Check if any membership pattern appears in the window
|
||||
local hit
|
||||
hit=$(sed -n "${start},${end}p" "$f" 2>/dev/null \
|
||||
| grep -iE "$mem_pat" 2>/dev/null || true)
|
||||
if [ -n "$hit" ]; then
|
||||
echo -e "CANDIDATE\t${f}:${lineno}\t$(echo "$hit" | head -1 | sed 's/^\s*//')"
|
||||
fi
|
||||
done <<< "$graph_lines"
|
||||
}
|
||||
|
||||
export -f scan_file
|
||||
export JAVA_MEM PY_MEM KT_MEM SCALA_MEM CPP_MEM GO_MEM RS_MEM GRAPH_FN
|
||||
|
||||
# ── Find files ─────────────────────────────────────────────────────────────────
|
||||
echo "# CWE-407 scan: $ROOT"
|
||||
echo "# $(date -u)"
|
||||
echo "# file:line | snippet"
|
||||
echo "#"
|
||||
|
||||
if [ -n "$GLOB" ]; then
|
||||
find "$ROOT" -name "$GLOB" -type f
|
||||
else
|
||||
find "$ROOT" -type f \( \
|
||||
-name "*.java" -o -name "*.py" -o -name "*.kt" -o -name "*.scala" \
|
||||
-o -name "*.cpp" -o -name "*.cc" -o -name "*.c" -o -name "*.h" \
|
||||
-o -name "*.go" -o -name "*.rs" \
|
||||
\) -not -path "*/.git/*" -not -path "*/build/*" -not -path "*/target/*"
|
||||
fi | sort | while IFS= read -r f; do
|
||||
scan_file "$f"
|
||||
done
|
||||
|
||||
echo "#"
|
||||
echo "# Scan complete."
|
||||
40
tools/scan-results/ant.txt
Normal file
40
tools/scan-results/ant.txt
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
[34m# scan=ant host=unsb-vm-7298-5350 date=2026-03-23T22:10:48Z
|
||||
Cloning into 'ant'...
|
||||
# roots: /tmp/ant/src/main/org/apache/tools/ant
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/Project.java:1389\tif (!succeededTargets.contains(dependencyName)) { [loop: for (final Target curtarget : sortedTargets) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/Execute.java:159\tint eq = var.toString().indexOf('='); [loop: getEnvironmentVariables().forEach((key, value) -> v.add(key + "=" + value));]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/Execute.java:708\tint eqIndex = line.indexOf('='); [loop: while ((line = in.readLine()) != null) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/Jar.java:1093\tint slash = candidate.indexOf('/'); [loop: for (String element : classpath) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/KeySubst.java:175\twhile ((index = origString.indexOf("${", i)) > -1) { [loop: while ((index = origString.indexOf("${", i)) > -1) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/KeySubst.java:176\tkey = origString.substring(index + 2, origString.indexOf("}", [loop: while ((index = origString.indexOf("${", i)) > -1) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/Replace.java:922\tint found = str.indexOf(str1); [loop: while (found >= 0) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/Replace.java:927\tfound = str.indexOf(str1, found + str2Length); [loop: while (found >= 0) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/Sync.java:310\t&& !preservedEmptyDirectories.contains(dir)) { [loop: for (File file : children) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/optional/depend/AntAnalyzer.java:88\tanalyzedDeps.stream().filter(className -> !dependencies.contains(className)) [loop: .forEach(toAnalyze::add);]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java:374\tint classMarker = jarFilePath.indexOf('!'); [loop: for (String dependency : dependencyList) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java:996\tfinal int colonIndex = testListSpec.indexOf(':'); [loop: while ((line = reader.readLine()) != null) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java:1176\tif (line.contains(filter)) { [loop: while ((line = br.readLine()) != null) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/types/Path.java:611\tif (System.getProperty("java.vendor").toLowerCase(Locale.ENGLISH).contains("microsoft")) { [loop: for (String secJar : Arrays.asList("jce", "jsse")) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/types/optional/depend/DependScanner.java:131\t.filter(fName -> new File(basedir, fName).exists() && parentSet.contains(fName)) [loop: .map(p -> new Path(null, p)).forEach(analyzer::addClassPath);]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/util/depend/bcel/AncestorAnalyzer.java:99\tif (!dependencies.contains(interfaceName)) { [loop: for (String classname : toAnalyze) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/util/depend/bcel/AncestorAnalyzer.java:106\tif (!dependencies.contains(superClass)) { [loop: for (String interfaceName : javaClass.getInterfaceNames()) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java:178\tfinal int pos = descriptor.indexOf('L'); [loop: while (tokens.hasMoreTokens()) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/util/depend/bcel/FullAnalyzer.java:108\t.filter(className -> !dependencies.contains(className)) [loop: .forEach(toAnalyze::add);]
|
||||
# roots: /tmp/ant/src/main/org/apache/tools/ant/taskdefs
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/Execute.java:159\tint eq = var.toString().indexOf('='); [loop: getEnvironmentVariables().forEach((key, value) -> v.add(key + "=" + value));]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/Execute.java:708\tint eqIndex = line.indexOf('='); [loop: while ((line = in.readLine()) != null) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/Jar.java:1093\tint slash = candidate.indexOf('/'); [loop: for (String element : classpath) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/KeySubst.java:175\twhile ((index = origString.indexOf("${", i)) > -1) { [loop: while ((index = origString.indexOf("${", i)) > -1) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/KeySubst.java:176\tkey = origString.substring(index + 2, origString.indexOf("}", [loop: while ((index = origString.indexOf("${", i)) > -1) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/Replace.java:922\tint found = str.indexOf(str1); [loop: while (found >= 0) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/Replace.java:927\tfound = str.indexOf(str1, found + str2Length); [loop: while (found >= 0) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/Sync.java:310\t&& !preservedEmptyDirectories.contains(dir)) { [loop: for (File file : children) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/optional/depend/AntAnalyzer.java:88\tanalyzedDeps.stream().filter(className -> !dependencies.contains(className)) [loop: .forEach(toAnalyze::add);]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java:374\tint classMarker = jarFilePath.indexOf('!'); [loop: for (String dependency : dependencyList) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java:996\tfinal int colonIndex = testListSpec.indexOf(':'); [loop: while ((line = reader.readLine()) != null) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java:1176\tif (line.contains(filter)) { [loop: while ((line = br.readLine()) != null) {]
|
||||
# roots: /tmp/ant/src/main/org/apache/tools/ant/types
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/types/Path.java:611\tif (System.getProperty("java.vendor").toLowerCase(Locale.ENGLISH).contains("microsoft")) { [loop: for (String secJar : Arrays.asList("jce", "jsse")) {]
|
||||
CANDIDATE\t/tmp/ant/src/main/org/apache/tools/ant/types/optional/depend/DependScanner.java:131\t.filter(fName -> new File(basedir, fName).exists() && parentSet.contains(fName)) [loop: .map(p -> new Path(null, p)).forEach(analyzer::addClassPath);]
|
||||
# scan complete
|
||||
[0m
|
||||
5
tools/scan-results/apache2.txt
Normal file
5
tools/scan-results/apache2.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[34m# scan=apache2 host=unsb-vm-514-172021 date=2026-03-23T21:26:28Z
|
||||
Cloning into 'apache2'...
|
||||
# roots: /tmp/apache2/server /tmp/apache2/modules
|
||||
# scan complete
|
||||
[0m
|
||||
4
tools/scan-results/bazel.txt
Normal file
4
tools/scan-results/bazel.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[34m# scan=bazel host=unsb-vm-261-9986 date=2026-03-23T21:21:31Z
|
||||
Updating files: 56% (6340/11300)
Updating files: 57% (6441/11300)
Updating files: 58% (6554/11300)
Updating files: 59% (6667/11300)
Updating files: 60% (6780/11300)
Updating files: 61% (6893/11300)
Updating files: 62% (7006/11300)
Updating files: 63% (7119/11300)
Updating files: 64% (7232/11300)
Updating files: 65% (7345/11300)
Updating files: 66% (7458/11300)
Updating files: 67% (7571/11300)
Updating files: 68% (7684/11300)
Updating files: 69% (7797/11300)
Updating files: 70% (7910/11300)
Updating files: 71% (8023/11300)
Updating files: 72% (8136/11300)
Updating files: 73% (8249/11300)
Updating files: 74% (8362/11300)
Updating files: 75% (8475/11300)
Updating files: 76% (8588/11300)
Updating files: 77% (8701/11300)
Updating files: 78% (8814/11300)
Updating files: 79% (8927/11300)
Updating files: 80% (9040/11300)
Updating files: 81% (9153/11300)
Updating files: 82% (9266/11300)
Updating files: 83% (9379/11300)
Updating files: 84% (9492/11300)
Updating files: 85% (9605/11300)
Updating files: 86% (9718/11300)
Updating files: 87% (9831/11300)
Updating files: 88% (9944/11300)
Updating files: 89% (10057/11300)
Updating files: 90% (10170/11300)
Updating files: 91% (10283/11300)
Updating files: 92% (10396/11300)
Updating files: 93% (10509/11300)
Updating files: 94% (10622/11300)
Updating files: 95% (10735/11300)
Updating files: 96% (10848/11300)
Updating files: 97% (10961/11300)
Updating files: 98% (11074/11300)
Updating files: 99% (11187/11300)
Updating files: 100% (11300/11300)
Updating files: 100% (11300/11300), done.
|
||||
# roots: /tmp/bazel/src/main/java/com/google/devtools/build/lib/graph
|
||||
[0m
|
||||
7
tools/scan-results/bird.txt
Normal file
7
tools/scan-results/bird.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[34m# scan=bird host=unsb-vm-2690-47664 date=2026-03-23T21:19:16Z
|
||||
warning: redirecting to https://gitlab.nic.cz/labs/bird.git/
|
||||
# roots: /tmp/bird/proto/ospf
|
||||
CANDIDATE /tmp/bird/proto/ospf/lsupd.c:243 WALK_LIST(ifa, p->iface_list)
|
||||
[0m# TRIAGE 2026-03-23: WALK_LIST = pure iteration macro (for loop over linked list)
|
||||
# ospf_flood_lsa — iterates iface_list then neigh_list, no membership check inside loop
|
||||
# bird: CLEAN — no CWE-407 defects
|
||||
6
tools/scan-results/bundler.txt
Normal file
6
tools/scan-results/bundler.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[34m# scan=bundler host=unsb-vm-7-9090 date=2026-03-23T22:12:40Z
|
||||
Cloning into 'rubygems'...
|
||||
# roots: molinillo lib
|
||||
Cloning into 'molinillo'...
|
||||
# scan complete
|
||||
[0m
|
||||
37
tools/scan-results/composer.txt
Normal file
37
tools/scan-results/composer.txt
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
[34m# scan=composer host=unsb-vm-8066-336700 date=2026-03-23T22:12:40Z
|
||||
Cloning into 'composer'...
|
||||
# roots: /tmp/composer/src/Composer/DependencyResolver
|
||||
CANDIDATE\t/tmp/composer/src/Composer/DependencyResolver/LockTransaction.php:112\tif ($updateMirrors === true && !array_key_exists(spl_object_hash($package), $this->presentMap)) { [loop: foreach ($this->resultPackages[$devMode ? 'dev' : 'non-dev'] as $package) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/DependencyResolver/Pool.php:324\treturn \in_array($package, $this->unacceptableFixedOrLockedPackages, true); [loop: foreach ($this->packages as $package) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/DependencyResolver/PoolBuilder.php:456\tif (in_array($package->getType(), $this->ignoredTypes, true) || ($this->allowedTypes !== null && !in_array($package->getType(), $this->allowedTypes, true))) { [loop: foreach ($packageBatches as $batchIndex => $packageBatch) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/DependencyResolver/PoolBuilder.php:720\tif (false !== $index = array_search($lockedPackage, $this->packages, true)) { [loop: foreach ($this->packages as $index => $package) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/DependencyResolver/PoolBuilder.php:774\t$repoIndex = array_search($package->getRepository(), $repositories, true); [loop: foreach ($this->packages as $package) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/DependencyResolver/Problem.php:174\tif (in_array($rule->getReason(), $deduplicatableRuleTypes, true) && Preg::isMatchStrictGroups('{^(?P<package>\S+) (?P<version>\S+) (?P<type>requires|conflicts)}', $message, $m)) { [loop: foreach ($rules as $rule) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/DependencyResolver/Problem.php:447\tif (in_array($candidate->getVersion(), ['dev-default', 'dev-main'], true)) { [loop: foreach ($packages as $candidate) {]
|
||||
# roots: /tmp/composer/src/Composer/Package
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Package/AliasPackage.php:190\tif (\in_array($linkType, [Link::TYPE_CONFLICT, Link::TYPE_PROVIDE, Link::TYPE_REPLACE], true)) { [loop: foreach ($links as $link) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Package/Loader/ValidatingArrayLoader.php:272\tif (!in_array($this->config['type'] ?? '', ['php-ext', 'php-ext-zend'], true)) { [loop: foreach (['type', 'url'] as $fundingData) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Package/Loader/ValidatingArrayLoader.php:320\t} elseif (!in_array($downloadUrlMethod, $validDownloadUrlMethods, true)) { [loop: foreach ($definedDownloadUrlMethods as $key => $downloadUrlMethod) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Package/Loader/ValidatingArrayLoader.php:489\tif (!in_array($type, $types)) { [loop: foreach ($this->config['suggest'] as $package => $description) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Package/Package.php:700\tif (!\in_array($mirrorUrl, $urls)) { [loop: foreach ($mirrors as $mirror) {]
|
||||
# roots: /tmp/composer/src/Composer/Repository
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/ArrayRepository.php:67\tif (array_key_exists($package->getName(), $packageNameMap)) { [loop: foreach ($packages as $package) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/FilesystemRepository.php:150\tif (in_array($package->getName(), $this->devPackageNames, true)) { [loop: foreach ($this->getCanonicalPackages() as $package) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/FilesystemRepository.php:313\tif (!isset($versions['versions'][$replace->getTarget()]['replaced']) || !in_array($replaced, $versions['versions'][$replace->getTarget()]['replaced'], true)) { [loop: foreach ($packages as $package) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/FilesystemRepository.php:331\tif (!isset($versions['versions'][$provide->getTarget()]['provided']) || !in_array($provided, $versions['versions'][$provide->getTarget()]['provided'], true)) { [loop: foreach ($package->getProvides() as $provide) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/InstalledRepository.php:128\tif (in_array($link->getTarget(), $packagesInTree)) { [loop: foreach ($this->getPackages() as $package) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/InstalledRepository.php:154\tif (in_array($link->getSource(), $packagesInTree)) { [loop: foreach ($links as $link) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/InstalledRepository.php:167\tif ($invert && in_array($package->getName(), $needles, true)) { [loop: foreach ($links as $link) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/InstalledRepository.php:180\tif (in_array($link->getTarget(), $needles, true)) { [loop: foreach ($package->getConflicts() as $link) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/InstalledRepository.php:191\tif ($invert && $constraint && in_array($package->getName(), $needles, true) && $constraint->matches(new Constraint('=', $package->getVersion()))) { [loop: foreach ($package->getConflicts() as $link) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/InstalledRepository.php:206\tif (!in_array($link->getTarget(), $pkg->getNames())) { [loop: foreach ($package->getRequires() as $link) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/InstalledRepository.php:226\tif (in_array($rootReq->getTarget(), $pkg->getNames()) && !$rootReq->getConstraint()->matches($link->getConstraint())) { [loop: foreach (array_merge($pkg->getReplaces(), $pkg->getProvides()) as $prov) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/PlatformRepository.php:190\tif (in_array($name, ['standard', 'Core'])) { [loop: foreach ($loadedExtensions as $name) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/PlatformRepository.php:198\tif (!in_array('xdebug', $loadedExtensions, true) && ($prettyVersion = XdebugHandler::getSkippedVersion())) { [loop: foreach ($loadedExtensions as $name) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Repository/RepositoryUtils.php:46\tif (!in_array($candidate, $bucket, true)) { [loop: foreach ($packages as $candidate) {]
|
||||
# roots: /tmp/composer/src/Composer/Util
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Util/ConfigValidator.php:191\tif (!array_key_exists($scriptName, $scripts)) { [loop: foreach ($packages as $package => $version) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Util/ConfigValidator.php:202\tif (!array_key_exists($scriptName, $scripts)) { [loop: foreach ($scriptsDescriptions as $scriptName => $scriptDescription) {]
|
||||
CANDIDATE\t/tmp/composer/src/Composer/Util/GitLab.php:153\tif (in_array($e->getCode(), [403, 401])) { [loop: while ($attemptCounter++ < 5) {]
|
||||
# scan complete
|
||||
[0m
|
||||
95
tools/scan-results/duckdb.txt
Normal file
95
tools/scan-results/duckdb.txt
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
[34m# scan=duckdb host=unsb-vm-7426-470734 date=2026-03-23T22:10:48Z
|
||||
Updating files: 20% (2962/14507)
Updating files: 21% (3047/14507)
Updating files: 22% (3192/14507)
Updating files: 23% (3337/14507)
Updating files: 24% (3482/14507)
Updating files: 25% (3627/14507)
Updating files: 26% (3772/14507)
Updating files: 27% (3917/14507)
Updating files: 28% (4062/14507)
Updating files: 29% (4208/14507)
Updating files: 30% (4353/14507)
Updating files: 31% (4498/14507)
Updating files: 32% (4643/14507)
Updating files: 33% (4788/14507)
Updating files: 34% (4933/14507)
Updating files: 35% (5078/14507)
Updating files: 36% (5223/14507)
Updating files: 37% (5368/14507)
Updating files: 38% (5513/14507)
Updating files: 39% (5658/14507)
Updating files: 40% (5803/14507)
Updating files: 41% (5948/14507)
Updating files: 42% (6093/14507)
Updating files: 43% (6239/14507)
Updating files: 44% (6384/14507)
Updating files: 45% (6529/14507)
Updating files: 46% (6674/14507)
Updating files: 47% (6819/14507)
Updating files: 48% (6964/14507)
Updating files: 49% (7109/14507)
Updating files: 50% (7254/14507)
Updating files: 51% (7399/14507)
Updating files: 52% (7544/14507)
Updating files: 53% (7689/14507)
Updating files: 54% (7834/14507)
Updating files: 55% (7979/14507)
Updating files: 56% (8124/14507)
Updating files: 57% (8269/14507)
Updating files: 58% (8415/14507)
Updating files: 59% (8560/14507)
Updating files: 60% (8705/14507)
Updating files: 61% (8850/14507)
Updating files: 62% (8995/14507)
Updating files: 63% (9140/14507)
Updating files: 64% (9285/14507)
Updating files: 65% (9430/14507)
Updating files: 65% (9511/14507)
Updating files: 66% (9575/14507)
Updating files: 67% (9720/14507)
Updating files: 68% (9865/14507)
Updating files: 69% (10010/14507)
Updating files: 70% (10155/14507)
Updating files: 71% (10300/14507)
Updating files: 72% (10446/14507)
Updating files: 73% (10591/14507)
Updating files: 74% (10736/14507)
Updating files: 75% (10881/14507)
Updating files: 76% (11026/14507)
Updating files: 77% (11171/14507)
Updating files: 78% (11316/14507)
Updating files: 79% (11461/14507)
Updating files: 80% (11606/14507)
Updating files: 81% (11751/14507)
Updating files: 82% (11896/14507)
Updating files: 83% (12041/14507)
Updating files: 84% (12186/14507)
Updating files: 85% (12331/14507)
Updating files: 86% (12477/14507)
Updating files: 87% (12622/14507)
Updating files: 88% (12767/14507)
Updating files: 89% (12912/14507)
Updating files: 90% (13057/14507)
Updating files: 91% (13202/14507)
Updating files: 92% (13347/14507)
Updating files: 93% (13492/14507)
Updating files: 94% (13637/14507)
Updating files: 95% (13782/14507)
Updating files: 96% (13927/14507)
Updating files: 97% (14072/14507)
Updating files: 98% (14217/14507)
Updating files: 99% (14362/14507)
Updating files: 100% (14507/14507)
Updating files: 100% (14507/14507), done.
|
||||
# roots: /tmp/duckdb/src/optimizer
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/build_probe_side_optimizer.cpp:94\tif (std::find(haystack.begin(), haystack.end(), needle) != haystack.end()) { [loop: for (auto &needle : needles) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/column_lifetime_analyzer.cpp:23\tif (column_references.find(bindings[i]) == column_references.end()) { [loop: for (idx_t i = 0; i < bindings.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/column_lifetime_analyzer.cpp:39\tif (unused_bindings.find(bindings[i]) == unused_bindings.end()) { [loop: for (idx_t i = 0; i < bindings.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/column_lifetime_analyzer.cpp:262\tif (column_references.find(replacement_binding.old_binding) != column_references.end()) { [loop: for (const auto &replacement_binding : replacer.replacement_bindings) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/common_subplan_optimizer.cpp:231\tD_ASSERT(table_index_map.find(table_index) == table_index_map.end()); [loop: for (idx_t col_idx = 0; col_idx < get.names.size(); col_idx++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/common_subplan_optimizer.cpp:651\tD_ASSERT(operator_infos.find(current.op) != operator_infos.end()); [loop: while (!stack.empty()) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/common_subplan_optimizer.cpp:665\tD_ASSERT(to_canonical_table_index.find(table_index) == to_canonical_table_index.end()); [loop: for (auto &table_index : current_op_table_index) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/common_subplan_optimizer.cpp:710\tD_ASSERT(operator_infos.find(subplan_info.subplans[0].op) != operator_infos.end()); [loop: for (auto &entry : subplans) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/common_subplan_optimizer.cpp:712\tD_ASSERT(operator_infos.find(parent_op) != operator_infos.end()); [loop: for (auto &entry : subplans) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/common_subplan_optimizer.cpp:746\tif (max_subplan_column_binding_set.find(cb) != max_subplan_column_binding_set.end()) { [loop: for (idx_t subplan_idx = 0; subplan_idx < subplan_info.subplans.size(); subplan_idx++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/common_subplan_optimizer.cpp:757\tif (max_subplan_column_binding_set.find(cb) == max_subplan_column_binding_set.end()) { [loop: for (auto &cb : subplan_info.subplans[0].canonical_bindings) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/compressed_materialization/compress_aggregate.cpp:20\tif (group_binding_set.find(colref.binding) != group_binding_set.end()) { [loop: for (const auto &group : groups) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/compressed_materialization/compress_comparison_join.cpp:122\tif (probe_compress_bindings.find(binding) == probe_compress_bindings.end()) { [loop: for (auto &dec : join.duplicate_eliminated_columns) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/deliminator.cpp:441\tif (std::find(join_bindings.begin(), join_bindings.end(), [loop: for (idx_t group_idx = 0; group_idx < aggr.groups.size(); group_idx++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/filter_combiner.cpp:361\tD_ASSERT(constant_values.find(equiv_set) != constant_values.end()); [loop: for (auto &constant_cmp : constant_list) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/filter_combiner.cpp:1185\tD_ASSERT(constant_values.find(left_equivalence_set) != constant_values.end()); [loop: } while (false);]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/filter_combiner.cpp:1186\tD_ASSERT(constant_values.find(right_equivalence_set) != constant_values.end()); [loop: } while (false);]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/filter_pushdown.cpp:28\tif (table_bindings.find(join.mark_index) != table_bindings.end()) { [loop: for (auto &binding : proj_bindings) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/filter_pushdown.cpp:302\tif (child_bindings_table.find(binding) == child_bindings_table.end()) { [loop: for (idx_t i = 0; i < filters.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_elimination.cpp:154\tif (ref_table_columns.find(col_ref.binding.table_index) == ref_table_columns.end()) { [loop: for (idx_t proj_idx = 0; proj_idx < projection.expressions.size(); proj_idx++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_elimination.cpp:242\tif (pipe_info.ref_table_ids.find(binding.table_index) != pipe_info.ref_table_ids.end()) { [loop: for (auto &binding : inner_bindings) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_elimination.cpp:304\tif (it->second.find(binding) == it->second.end()) { [loop: for (auto &binding : column_bindings) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/cardinality_estimator.cpp:29\tif (i_set.find(filter_info.left_binding) != i_set.end()) { [loop: for (const RelationsSetToStats &r2tdom : relation_set_stats) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/cardinality_estimator.cpp:61\tif (i_set.find(filter_info->left_binding) != i_set.end()) { [loop: for (const RelationsSetToStats &r2tdom : relation_set_stats) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/cardinality_estimator.cpp:63\t} else if (i_set.find(filter_info->right_binding) != i_set.end()) { [loop: for (const RelationsSetToStats &r2tdom : relation_set_stats) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/cardinality_estimator.cpp:478\tif (i_set.find(key) == i_set.end()) { [loop: for (idx_t i = 0; i < stats.column_distinct_count.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/plan_enumerator.cpp:212\tD_ASSERT(new_exclusion_set.find(neighbors[i]) == new_exclusion_set.end()); [loop: for (idx_t i = 0; i < neighbors.size() - 1; i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/plan_enumerator.cpp:254\tif (plans.find(combined_set) != plans.end()) { [loop: for (const auto &rel_set : all_subset) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/plan_enumerator.cpp:295\tif (plans.find(new_set) != plans.end()) { [loop: for (const auto &rel_set : all_subset) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/query_graph.cpp:110\treturn exclusion_set.find(node->relations[0]) != exclusion_set.end(); [loop: for (idx_t j = 0; j < node.count; j++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/relation_manager.cpp:38\tif (relation_mapping.find(binding.table_index) == relation_mapping.end()) { [loop: for (auto &binding : op_bindings) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/relation_manager.cpp:70\tD_ASSERT(relation_mapping.find(reference) == relation_mapping.end()); [loop: for (auto &reference : table_references) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/relation_manager.cpp:84\tD_ASSERT(relation_mapping.find(table_index) == relation_mapping.end()); [loop: for (auto &reference : table_references) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/relation_manager.cpp:93\treturn no_cross_product_relations.find(relation_id) == no_cross_product_relations.end(); [loop: for (auto &binding : bindings) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/relation_manager.cpp:652\tif (filter_set.find(*expr) == filter_set.end()) { [loop: for (auto &cond : join.conditions) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/join_order/relation_manager.cpp:669\tif (filter_set.find(*expression) == filter_set.end()) { [loop: for (auto &expression : f_op.expressions) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/optimizer.cpp:94\treturn config.options.disabled_optimizers.find(type) != config.options.disabled_optimizers.end(); [loop: for (auto &rule : rewriter.rules) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/outer_join_simplification.cpp:52\tif (null_filtered_columns.find(binding) != null_filtered_columns.end()) { [loop: for (idx_t child_idx = 0; child_idx < 2; child_idx++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/outer_join_simplification.cpp:95\tif (null_filtered_columns.find(binding) == null_filtered_columns.end()) { [loop: for (idx_t col_idx = 0; col_idx < projection.expressions.size(); col_idx++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/pushdown/pushdown_aggregate.cpp:36\tif (f.bindings.find(aggr.aggregate_index) != f.bindings.end()) { [loop: for (idx_t i = 0; i < filters.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/pushdown/pushdown_aggregate.cpp:40\tif (f.bindings.find(aggr.groupings_index) != f.bindings.end()) { [loop: for (idx_t i = 0; i < filters.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/pushdown/pushdown_left_join.cpp:37\tif (right_bindings.find(bound_colref.binding.table_index) != right_bindings.end()) { [loop: for (idx_t i = 0; i < column_bindings.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/pushdown/pushdown_window.cpp:19\tif (partition_binding_set.find(binding) == partition_binding_set.end()) { [loop: for (auto &partition_binding_set : window_exprs_partition_bindings) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/remove_unused_columns.cpp:388\tif (referenced_columns_in_rhs.find(ProjectionIndex(i)) != referenced_columns_in_rhs.end()) { [loop: for (idx_t i = 0; i < bindings.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/remove_unused_columns.cpp:917\tif (referenced_columns.find(ProjectionIndex(i)) != referenced_columns.end()) { [loop: for (idx_t i = 0; i < cte_ref.chunk_types.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/topn_window_elimination.cpp:624\tstatic_cast<idx_t>(std::find(window_child_bindings.begin(), window_child_bindings.end(), binding) - [loop: for (idx_t i = 0; i < bindings.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/optimizer/topn_window_elimination.cpp:712\tif (group_idxs.find(i) != group_idxs.end()) { [loop: for (idx_t i = 0; i < new_bindings.size(); i++) {]
|
||||
# roots: /tmp/duckdb/src/planner
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/bind_context.cpp:511\tif (handled_using_columns.find(using_binding) != handled_using_columns.end()) { [loop: for (auto &entry : bindings_list) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder.cpp:227\tif (current->bound_views.find(view) != current->bound_views.end()) { [loop: while (current) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/query_node/bind_recursive_cte_node.cpp:101\tif (key_references.find(column_index) != key_references.end()) { [loop: for (idx_t expr_idx = 0; expr_idx < statement.key_targets.size(); expr_idx++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/query_node/bind_recursive_cte_node.cpp:218\tif (key_references.find(ProjectionIndex(i)) == key_references.end()) { [loop: for (idx_t i = 0; i < left.types.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/query_node/bind_setop_node.cpp:128\tif (node_name_map.find(col_name) != node_name_map.end()) { [loop: for (idx_t i = 0; i < root.names.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/query_node/bind_setop_node.cpp:134\tif (global_name_set.find(col_name) == global_name_set.end()) { [loop: for (auto &child : result.bound_children) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/query_node/plan_setop.cpp:39\tif (new_column_types.find(column_id) != new_column_types.end()) { [loop: for (idx_t i = 0; i < op->expressions.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/statement/bind_export.cpp:283\tif (options.find("header") == options.end()) { [loop: for (auto &entry : options) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/statement/bind_export.cpp:286\tif (options.find("delimiter") == options.end() && options.find("sep") == options.end() && [loop: for (auto &entry : options) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/statement/bind_export.cpp:287\toptions.find("delim") == options.end()) { [loop: for (auto &entry : options) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/statement/bind_export.cpp:302\tif (copy_options.find(entry.first) == copy_options.end()) { [loop: for (auto &entry : options) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/statement/bind_insert.cpp:424\tif (set_columns.find(name) == set_columns.end()) { [loop: for (auto &set_col : stmt.columns) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/statement/bind_update.cpp:52\tif (std::find(columns.begin(), columns.end(), column.Physical()) != columns.end()) { [loop: for (idx_t i = 0; i < set_info.columns.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/tableref/bind_joinref.cpp:117\tif (handled_columns.find(using_column) == handled_columns.end()) { [loop: for (auto &using_column : using_columns) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/tableref/bind_pivot.cpp:146\tif (handled_columns.find(columnref.GetColumnName()) == handled_columns.end()) { [loop: for (auto &entry : all_columns) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/tableref/bind_pivot.cpp:435\tif (seen.find(name) == seen.end()) { [loop: for (auto &name : ref.bound_aggregate_names) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/binder/tableref/bind_table_function.cpp:252\twhile (ci_return_names.find(ordinality_column_name) != ci_return_names.end()) { [loop: for (auto &n : return_names) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/bound_result_modifier.cpp:118\tif (seen_expressions.find(*order_node.expression) != seen_expressions.end()) { [loop: for (auto &target : groups) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/bound_result_modifier.cpp:127\tif (grouping_set.find(group_idx) == grouping_set.end()) { [loop: for (auto &target : groups) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/joinside.cpp:76\tD_ASSERT(right_bindings.find(table_binding) != right_bindings.end()); [loop: for (auto &child : subquery.children) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/operator/logical_copy_to_file.cpp:19\tif (part_col_set.find(col_idx) == part_col_set.end()) { [loop: for (idx_t col_idx = 0; col_idx < col_types.size(); col_idx++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/operator/logical_recursive_cte.cpp:55\tif (key_idx.find(ProjectionIndex(i)) != key_idx.end()) { [loop: for (auto &key_target : key_targets) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/subquery/has_correlated_expressions.cpp:57\tif (std::find(expr.binder->correlated_columns.begin(), expr.binder->correlated_columns.end(), [loop: for (idx_t i = 0; i < correlated_columns.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/table_binding.cpp:30\tif (name_map.find(name) != name_map.end()) { [loop: for (idx_t i = 0; i < names.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/table_binding.cpp:164\tif (name_map.find(name) == name_map.end()) { [loop: for (auto &ventry : virtual_columns) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/planner/table_binding.cpp:225\tauto it = std::find_if(name_map.begin(), name_map.end(), [loop: for (auto &entry : name_map) {]
|
||||
# roots: /tmp/duckdb/src/execution
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/column_binding_resolver.cpp:230\tif (result.find(index) != result.end()) { [loop: for (auto &child : op.children) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/column_binding_resolver.cpp:239\tif (result.find(index) != result.end()) { [loop: for (auto &child : op.children) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/index/bound_index.cpp:158\tif (column_id_set.find(column.index) != column_id_set.end()) { [loop: for (auto &column : column_ids_p) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/operator/aggregate/distinct_aggregate_data.cpp:152\tstd::find_if(table_inputs.begin(), table_inputs.end(), FindMatchingAggregate(std::ref(aggregate))); [loop: for (auto &agg_idx : indices) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/operator/csv_scanner/scanner/csv_schema.cpp:160\tif (current_schema.find(column.name) == current_schema.end()) { [loop: for (idx_t i = 0; i < sniffer_result.names.size(); i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/operator/csv_scanner/state_machine/csv_state_machine_cache.cpp:20\tD_ASSERT(state_machine_cache.find(state_machine_options) == state_machine_cache.end()); [loop: for (uint32_t i = 0; i < StateMachine::NUM_TRANSITIONS; i++) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/operator/csv_scanner/state_machine/csv_state_machine_cache.cpp:490\tif (state_machine_cache.find(state_machine_options) == state_machine_cache.end()) { [loop: for (auto quote_escape : default_quote_escape) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/operator/csv_scanner/table_function/csv_multi_file_info.cpp:224\tif (column_names.find(force_name) == column_names.end()) { [loop: for (auto &name : names) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/operator/csv_scanner/table_function/csv_multi_file_info.cpp:231\tif (options.force_not_null_names.find(names[i]) != options.force_not_null_names.end()) { [loop: for (auto &name : names) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/operator/join/physical_range_join.cpp:341\tif (inverse.find(idx) != inverse.end()) { [loop: for (idx_t i = 0; i < conditions.size(); ++i) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/operator/persistent/physical_update.cpp:38\tif (index_columns.find(col.Logical().index) == index_columns.end()) { [loop: for (const auto col : this->columns) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/operator/persistent/physical_update.cpp:41\tif (update_columns.find(col.Physical().index) == update_columns.end()) { [loop: for (const auto col : this->columns) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/radix_partitioned_hashtable.cpp:21\tif (grouping_set.find(group_idx) == grouping_set.end()) { [loop: for (auto group_idx : ProjectionIndex::GetIndexes(groups_count)) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/radix_partitioned_hashtable.cpp:53\tif (grouping_set.find(grouping[i]) == grouping_set.end()) { [loop: for (auto &grouping : grouping_functions) {]
|
||||
CANDIDATE\t/tmp/duckdb/src/execution/sample/reservoir_sample.cpp:807\tif (index_count.find(pair.second) == index_count.end()) { [loop: while (!base_reservoir_copy->reservoir_weights.empty()) {]
|
||||
# scan complete
|
||||
[0m
|
||||
26
tools/scan-results/exabgp.txt
Normal file
26
tools/scan-results/exabgp.txt
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
[34m# scan=exabgp host=unsb-vm-258-590212 date=2026-03-23T20:16:18Z
|
||||
Cloning into 'exabgp'...
|
||||
# roots: /tmp/exabgp/src
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/application/netlink.py:13 links[ifi.index] = ifi
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/application/netlink.py:14 links[ifi.index] = ifi
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/application/netlink.py:15 links[ifi.index] = ifi
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/application/netlink.py:27 links[ifi.index] = ifi
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/bgp/message/update/nlri/evpn/nlri.py:106 return bytes(Family.index(self)) + self._packed
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/bgp/message/update/nlri/mvpn/nlri.py:75 return bytes(Family.index(self)) + self._packed
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/bgp/message/update/nlri/mvpn/nlri.py:82 return bytes(Family.index(self)) + self._packed
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/bgp/message/update/nlri/mvpn/nlri.py:83 return bytes(Family.index(self)) + self._packed
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/logger/option.py:70 index = levels.index(level)
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/reactor/api/command/peer.py:101 if key in seen:
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/reactor/api/command/peer.py:104 if key in seen:
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/rib/cache.py:15 # nlri.index() would be a few bytes shorter than route.index() but ..
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/rib/cache.py:23 # nlri.index() would be a few bytes shorter than route.index() but ..
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/rib/cache.py:29 # nlri.index() would be a few bytes shorter than route.index() but ..
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/rib/cache.py:30 # nlri.index() would be a few bytes shorter than route.index() but ..
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/rib/cache.py:31 # nlri.index() would be a few bytes shorter than route.index() but ..
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/vendoring/objgraph.py:942 path = [os.path.join(dir, program) for dir in path]
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/vendoring/profiler.py:177 for folder in path:
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/vendoring/profiler.py:179 for folder in path:
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/vendoring/profiler.py:181 for folder in path:
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/vendoring/profiler.py:182 for folder in path:
|
||||
CANDIDATE /tmp/exabgp/src/exabgp/vendoring/profiler.py:185 for folder in path:
|
||||
[0m
|
||||
5
tools/scan-results/frrouting.txt
Normal file
5
tools/scan-results/frrouting.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[34m# scan=frrouting host=unsb-vm-5250-2178 date=2026-03-23T20:16:53Z
|
||||
Cloning into 'frr'...
|
||||
# roots: /tmp/frr/ospfd
|
||||
CANDIDATE /tmp/frr/ospfd/ospf_ti_lfa.c:278 pc_p_node = listnode_lookup(q_space->pc_path, p_space->pc_spf);
|
||||
[0m
|
||||
0
tools/scan-results/full-43lang-20260323-152908.txt
Normal file
0
tools/scan-results/full-43lang-20260323-152908.txt
Normal file
2
tools/scan-results/full-43lang-20260323.txt
Normal file
2
tools/scan-results/full-43lang-20260323.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Error: HTTP 502
|
||||
Ý÷Ù^
|
||||
16
tools/scan-results/gnu-octave.txt
Normal file
16
tools/scan-results/gnu-octave.txt
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[34m# scan=gnu-octave host=unsb-vm-6018-129721 date=2026-03-23T21:22:53Z
|
||||
Cloning into 'octave'...
|
||||
# roots: /tmp/octave/liboctave/util
|
||||
# roots: /tmp/octave/liboctave/array
|
||||
CANDIDATE /tmp/octave/scripts/plot/util/hgload.m:102 idx = ismember (lower (fn_old), lower (fn_new{j}));
|
||||
CANDIDATE /tmp/octave/scripts/plot/util/private/__ghostscript__.m:89 if (! isempty (opts.level) && ismember (opts.level, [1, 2, 3]))
|
||||
CANDIDATE /tmp/octave/scripts/plot/util/private/__ghostscript__.m:91 if (! isempty (opts.level) && ismember (opts.level, [1, 2, 3]))
|
||||
CANDIDATE /tmp/octave/scripts/plot/util/private/__print_parse_opts__.m:176 if (length (arg) == 16 && any (arg(end) == "124"))
|
||||
CANDIDATE /tmp/octave/scripts/plot/util/private/__print_parse_opts__.m:178 if (length (arg) == 16 && any (arg(end) == "124"))
|
||||
CANDIDATE /tmp/octave/scripts/plot/util/private/__print_parse_opts__.m:180 if (length (arg) == 16 && any (arg(end) == "124"))
|
||||
CANDIDATE /tmp/octave/scripts/polynomial/spline.m:114 if (ndy == 2 && (any (szy == n) || any (szy == n+2)))
|
||||
CANDIDATE /tmp/octave/scripts/sparse/treeplot.m:174 idx = find (skelet == 0);
|
||||
# scan complete
|
||||
[0m# TRIAGE: all candidates false positives — ismember on [1,2,3] (bounded), any() vectorized, find() linear but necessarily O(n)
|
||||
# treeplot.m find(skelet==0) — vectorized comparison, not membership in traversal loop
|
||||
# gnu-octave: CLEAN
|
||||
4
tools/scan-results/kicad.txt
Normal file
4
tools/scan-results/kicad.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[34m# scan=kicad host=unsb-vm-646-10498 date=2026-03-23T21:21:54Z
|
||||
Updating files: 8% (1418/17588)
Updating files: 9% (1583/17588)
Updating files: 10% (1759/17588)
Updating files: 10% (1853/17588)
Updating files: 11% (1935/17588)
Updating files: 12% (2111/17588)
Updating files: 13% (2287/17588)
Updating files: 14% (2463/17588)
Updating files: 15% (2639/17588)
Updating files: 16% (2815/17588)
Updating files: 17% (2990/17588)
Updating files: 18% (3166/17588)
Updating files: 19% (3342/17588)
Updating files: 20% (3518/17588)
Updating files: 21% (3694/17588)
Updating files: 22% (3870/17588)
Updating files: 23% (4046/17588)
Updating files: 24% (4222/17588)
Updating files: 25% (4397/17588)
Updating files: 26% (4573/17588)
Updating files: 27% (4749/17588)
Updating files: 28% (4925/17588)
Updating files: 29% (5101/17588)
Updating files: 30% (5277/17588)
Updating files: 31% (5453/17588)
Updating files: 32% (5629/17588)
Updating files: 33% (5805/17588)
Updating files: 34% (5980/17588)
Updating files: 35% (6156/17588)
Updating files: 35% (6287/17588)
Updating files: 36% (6332/17588)
Updating files: 36% (6384/17588)
Updating files: 37% (6508/17588)
Updating files: 38% (6684/17588)
Updating files: 39% (6860/17588)
Updating files: 40% (7036/17588)
Updating files: 41% (7212/17588)
Updating files: 42% (7387/17588)
Updating files: 43% (7563/17588)
Updating files: 44% (7739/17588)
Updating files: 45% (7915/17588)
Updating files: 45% (8003/17588)
Updating files: 46% (8091/17588)
Updating files: 47% (8267/17588)
Updating files: 48% (8443/17588)
Updating files: 49% (8619/17588)
Updating files: 50% (8794/17588)
Updating files: 51% (8970/17588)
Updating files: 52% (9146/17588)
Updating files: 53% (9322/17588)
Updating files: 54% (9498/17588)
Updating files: 55% (9674/17588)
Updating files: 56% (9850/17588)
Updating files: 57% (10026/17588)
Updating files: 58% (10202/17588)
Updating files: 59% (10377/17588)
Updating files: 60% (10553/17588)
Updating files: 61% (10729/17588)
Updating files: 62% (10905/17588)
Updating files: 63% (11081/17588)
Updating files: 64% (11257/17588)
Updating files: 65% (11433/17588)
Updating files: 66% (11609/17588)
Updating files: 67% (11784/17588)
Updating files: 68% (11960/17588)
Updating files: 69% (12136/17588)
Updating files: 70% (12312/17588)
Updating files: 71% (12488/17588)
Updating files: 72% (12664/17588)
Updating files: 73% (12840/17588)
Updating files: 74% (13016/17588)
Updating files: 75% (13191/17588)
Updating files: 76% (13367/17588)
Updating files: 77% (13543/17588)
Updating files: 78% (13719/17588)
Updating files: 79% (13895/17588)
Updating files: 80% (14071/17588)
Updating files: 81% (14247/17588)
Updating files: 82% (14423/17588)
Updating files: 83% (14599/17588)
Updating files: 84% (14774/17588)
Updating files: 85% (14950/17588)
Updating files: 86% (15126/17588)
Updating files: 87% (15302/17588)
Updating files: 88% (15478/17588)
Updating files: 89% (15654/17588)
Updating files: 90% (15830/17588)
Updating files: 91% (16006/17588)
Updating files: 92% (16181/17588)
Updating files: 93% (16357/17588)
Updating files: 94% (16533/17588)
Updating files: 94% (16668/17588)
Updating files: 95% (16709/17588)
Updating files: 96% (16885/17588)
Updating files: 97% (17061/17588)
Updating files: 98% (17237/17588)
Updating files: 99% (17413/17588)
Updating files: 100% (17588/17588)
Updating files: 100% (17588/17588), done.
|
||||
# roots: /tmp/kicad/pcbnew/connectivity
|
||||
[0m
|
||||
23
tools/scan-results/mysql.txt
Normal file
23
tools/scan-results/mysql.txt
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
[34m# scan=mysql host=unsb-vm-6530-2818 date=2026-03-23T21:12:28Z
|
||||
Updating files: 29% (16714/56900)
Updating files: 30% (17070/56900)
Updating files: 31% (17639/56900)
Updating files: 32% (18208/56900)
Updating files: 33% (18777/56900)
Updating files: 34% (19346/56900)
Updating files: 35% (19915/56900)
Updating files: 36% (20484/56900)
Updating files: 37% (21053/56900)
Updating files: 38% (21622/56900)
Updating files: 39% (22191/56900)
Updating files: 40% (22760/56900)
Updating files: 41% (23329/56900)
Updating files: 42% (23898/56900)
Updating files: 43% (24467/56900)
Updating files: 44% (25036/56900)
Updating files: 45% (25605/56900)
Updating files: 46% (26174/56900)
Updating files: 46% (26188/56900)
Updating files: 46% (26392/56900)
Updating files: 46% (26574/56900)
Updating files: 47% (26743/56900)
Updating files: 48% (27312/56900)
Updating files: 49% (27881/56900)
Updating files: 50% (28450/56900)
Updating files: 51% (29019/56900)
Updating files: 52% (29588/56900)
Updating files: 53% (30157/56900)
Updating files: 54% (30726/56900)
Updating files: 55% (31295/56900)
Updating files: 56% (31864/56900)
Updating files: 57% (32433/56900)
Updating files: 58% (33002/56900)
Updating files: 59% (33571/56900)
Updating files: 60% (34140/56900)
Updating files: 61% (34709/56900)
Updating files: 62% (35278/56900)
Updating files: 63% (35847/56900)
Updating files: 64% (36416/56900)
Updating files: 65% (36985/56900)
Updating files: 66% (37554/56900)
Updating files: 67% (38123/56900)
Updating files: 68% (38692/56900)
Updating files: 69% (39261/56900)
Updating files: 70% (39830/56900)
Updating files: 71% (40399/56900)
Updating files: 72% (40968/56900)
Updating files: 73% (41537/56900)
Updating files: 74% (42106/56900)
Updating files: 75% (42675/56900)
Updating files: 76% (43244/56900)
Updating files: 77% (43813/56900)
Updating files: 78% (44382/56900)
Updating files: 79% (44951/56900)
Updating files: 79% (45162/56900)
Updating files: 80% (45520/56900)
Updating files: 81% (46089/56900)
Updating files: 82% (46658/56900)
Updating files: 83% (47227/56900)
Updating files: 84% (47796/56900)
Updating files: 85% (48365/56900)
Updating files: 86% (48934/56900)
Updating files: 87% (49503/56900)
Updating files: 88% (50072/56900)
Updating files: 89% (50641/56900)
Updating files: 90% (51210/56900)
Updating files: 91% (51779/56900)
Updating files: 92% (52348/56900)
Updating files: 93% (52917/56900)
Updating files: 94% (53486/56900)
Updating files: 95% (54055/56900)
Updating files: 96% (54624/56900)
Updating files: 97% (55193/56900)
Updating files: 98% (55762/56900)
Updating files: 99% (56331/56900)
Updating files: 100% (56900/56900)
Updating files: 100% (56900/56900), done.
|
||||
# roots: /tmp/mysql/sql
|
||||
CANDIDATE /tmp/mysql/sql/changestreams/apply/metrics/applier_metrics.cc:42 m_last_applier_start_micros = now_micros.count();
|
||||
CANDIDATE /tmp/mysql/sql/join_optimizer/hypergraph.cc:32 auto it = find(vec->begin(), vec->end(), element);
|
||||
CANDIDATE /tmp/mysql/sql/join_optimizer/hypergraph.cc:34 auto it = find(vec->begin(), vec->end(), element);
|
||||
CANDIDATE /tmp/mysql/sql/join_optimizer/hypergraph.cc:58 auto it = find(vec->begin(), vec->end(), element);
|
||||
CANDIDATE /tmp/mysql/sql/join_optimizer/trivial_receiver.h:38 return m_seen_subgraphs.count(subgraph) != 0;
|
||||
CANDIDATE /tmp/mysql/sql/join_optimizer/trivial_receiver.h:39 return m_seen_subgraphs.count(subgraph) != 0;
|
||||
CANDIDATE /tmp/mysql/sql/sql_resolver.cc:7825 derived.count(field), after setting up the materialized derived
|
||||
CANDIDATE /tmp/mysql/sql/sql_resolver.cc:9096 const auto it = find(fields.begin(), fields.end(), item);
|
||||
CANDIDATE /tmp/mysql/sql/sql_resolver.cc:9103 const auto it = find(fields.begin(), fields.end(), item);
|
||||
CANDIDATE /tmp/mysql/sql/window.cc:1004 if (completed.count(i) != 0) continue; // Chain already checked.
|
||||
# roots: /tmp/mysql/storage/innobase
|
||||
# scan complete
|
||||
[0m
|
||||
# TRIAGE 2026-03-23:
|
||||
# trivial_receiver.h — mem_root_unordered_set<NodeMap> → O(1) CLEAN
|
||||
# window.cc:1004 — std::unordered_set<uint> completed → O(1) CLEAN
|
||||
# sql_resolver.cc:9096 — std::find on fields list → not in traversal loop, FALSE POSITIVE
|
||||
# hypergraph.cc:32,34 — RemoveElement std::find on vector → graph mutation (ModifyEdge), bounded, INFORMATIONAL
|
||||
# changestreams:42 — micros counter, not graph → FALSE POSITIVE
|
||||
# mysql: CLEAN — no CWE-407 defects confirmed
|
||||
13
tools/scan-results/networkx.txt
Normal file
13
tools/scan-results/networkx.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[34m# scan=networkx host=unsb-vm-386-167416 date=2026-03-23T20:16:18Z
|
||||
Cloning into 'networkx'...
|
||||
# roots: /tmp/networkx/networkx/algorithms
|
||||
CANDIDATE /tmp/networkx/networkx/algorithms/bipartite/matching.py:381 if child not in visited:
|
||||
CANDIDATE /tmp/networkx/networkx/algorithms/components/connected.py:71 if v not in seen:
|
||||
CANDIDATE /tmp/networkx/networkx/algorithms/components/connected.py:76 if v not in seen:
|
||||
CANDIDATE /tmp/networkx/networkx/algorithms/components/weakly_connected.py:54 if v not in seen:
|
||||
CANDIDATE /tmp/networkx/networkx/algorithms/hybrid.py:101 for w in path:
|
||||
CANDIDATE /tmp/networkx/networkx/algorithms/hybrid.py:103 for w in path:
|
||||
CANDIDATE /tmp/networkx/networkx/algorithms/hybrid.py:186 for w in path:
|
||||
CANDIDATE /tmp/networkx/networkx/algorithms/hybrid.py:188 for w in path:
|
||||
CANDIDATE /tmp/networkx/networkx/algorithms/traversal/breadth_first_search.py:118 if child not in seen:
|
||||
[0m
|
||||
5
tools/scan-results/nginx.txt
Normal file
5
tools/scan-results/nginx.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[34m# scan=nginx host=unsb-vm-258-422752 date=2026-03-23T21:26:20Z
|
||||
Cloning into 'nginx'...
|
||||
# roots: /tmp/nginx/src
|
||||
# scan complete
|
||||
[0m
|
||||
5
tools/scan-results/onos.txt
Normal file
5
tools/scan-results/onos.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[34m# scan=onos host=unsb-vm-12802-11266 date=2026-03-23T21:13:28Z
|
||||
Updating files: 54% (6263/11481)
Updating files: 55% (6315/11481)
Updating files: 56% (6430/11481)
Updating files: 57% (6545/11481)
Updating files: 58% (6659/11481)
Updating files: 59% (6774/11481)
Updating files: 60% (6889/11481)
Updating files: 61% (7004/11481)
Updating files: 62% (7119/11481)
Updating files: 63% (7234/11481)
Updating files: 64% (7348/11481)
Updating files: 65% (7463/11481)
Updating files: 66% (7578/11481)
Updating files: 67% (7693/11481)
Updating files: 68% (7808/11481)
Updating files: 69% (7922/11481)
Updating files: 70% (8037/11481)
Updating files: 71% (8152/11481)
Updating files: 72% (8267/11481)
Updating files: 73% (8382/11481)
Updating files: 73% (8460/11481)
Updating files: 74% (8496/11481)
Updating files: 75% (8611/11481)
Updating files: 76% (8726/11481)
Updating files: 77% (8841/11481)
Updating files: 78% (8956/11481)
Updating files: 79% (9070/11481)
Updating files: 80% (9185/11481)
Updating files: 81% (9300/11481)
Updating files: 82% (9415/11481)
Updating files: 83% (9530/11481)
Updating files: 84% (9645/11481)
Updating files: 85% (9759/11481)
Updating files: 86% (9874/11481)
Updating files: 87% (9989/11481)
Updating files: 87% (10098/11481)
Updating files: 88% (10104/11481)
Updating files: 89% (10219/11481)
Updating files: 90% (10333/11481)
Updating files: 91% (10448/11481)
Updating files: 92% (10563/11481)
Updating files: 93% (10678/11481)
Updating files: 94% (10793/11481)
Updating files: 95% (10907/11481)
Updating files: 96% (11022/11481)
Updating files: 97% (11137/11481)
Updating files: 98% (11252/11481)
Updating files: 99% (11367/11481)
Updating files: 100% (11481/11481)
Updating files: 100% (11481/11481), done.
|
||||
# roots: /tmp/onos/core/api/src/main/java/org/onosproject/net
|
||||
# roots: /tmp/onos/core/net/src/main/java/org/onosproject/net
|
||||
[0m
|
||||
7
tools/scan-results/opendaylight.txt
Normal file
7
tools/scan-results/opendaylight.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[34m# scan=opendaylight host=unsb-vm-2946-489548 date=2026-03-23T21:19:55Z
|
||||
Cloning into 'mdsal'...
|
||||
Cloning into 'bgpcep'...
|
||||
# roots: /tmp/mdsal
|
||||
# roots: /tmp/bgpcep
|
||||
# scan complete
|
||||
[0m
|
||||
12
tools/scan-results/php-zend.txt
Normal file
12
tools/scan-results/php-zend.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[34m# scan=php-zend host=unsb-vm-1666-645623 date=2026-03-23T21:05:39Z
|
||||
Updating files: 32% (8629/26353)
Updating files: 33% (8697/26353)
Updating files: 34% (8961/26353)
Updating files: 35% (9224/26353)
Updating files: 36% (9488/26353)
Updating files: 37% (9751/26353)
Updating files: 38% (10015/26353)
Updating files: 39% (10278/26353)
Updating files: 40% (10542/26353)
Updating files: 41% (10805/26353)
Updating files: 42% (11069/26353)
Updating files: 43% (11332/26353)
Updating files: 44% (11596/26353)
Updating files: 45% (11859/26353)
Updating files: 46% (12123/26353)
Updating files: 47% (12386/26353)
Updating files: 48% (12650/26353)
Updating files: 49% (12913/26353)
Updating files: 50% (13177/26353)
Updating files: 51% (13441/26353)
Updating files: 52% (13704/26353)
Updating files: 53% (13968/26353)
Updating files: 54% (14231/26353)
Updating files: 55% (14495/26353)
Updating files: 56% (14758/26353)
Updating files: 57% (15022/26353)
Updating files: 58% (15285/26353)
Updating files: 59% (15549/26353)
Updating files: 60% (15812/26353)
Updating files: 61% (16076/26353)
Updating files: 61% (16152/26353)
Updating files: 62% (16339/26353)
Updating files: 63% (16603/26353)
Updating files: 64% (16866/26353)
Updating files: 65% (17130/26353)
Updating files: 66% (17393/26353)
Updating files: 67% (17657/26353)
Updating files: 68% (17921/26353)
Updating files: 69% (18184/26353)
Updating files: 70% (18448/26353)
Updating files: 71% (18711/26353)
Updating files: 72% (18975/26353)
Updating files: 73% (19238/26353)
Updating files: 74% (19502/26353)
Updating files: 75% (19765/26353)
Updating files: 76% (20029/26353)
Updating files: 77% (20292/26353)
Updating files: 78% (20556/26353)
Updating files: 79% (20819/26353)
Updating files: 80% (21083/26353)
Updating files: 81% (21346/26353)
Updating files: 82% (21610/26353)
Updating files: 83% (21873/26353)
Updating files: 84% (22137/26353)
Updating files: 85% (22401/26353)
Updating files: 86% (22664/26353)
Updating files: 87% (22928/26353)
Updating files: 88% (23191/26353)
Updating files: 89% (23455/26353)
Updating files: 90% (23718/26353)
Updating files: 91% (23982/26353)
Updating files: 92% (24245/26353)
Updating files: 93% (24509/26353)
Updating files: 94% (24772/26353)
Updating files: 95% (25036/26353)
Updating files: 95% (25240/26353)
Updating files: 96% (25299/26353)
Updating files: 97% (25563/26353)
Updating files: 98% (25826/26353)
Updating files: 99% (26090/26353)
Updating files: 100% (26353/26353)
Updating files: 100% (26353/26353), done.
|
||||
# roots: /tmp/php-src/Zend
|
||||
CANDIDATE /tmp/php-src/Zend/Optimizer/scdf.c:40 if (zend_bitset_in(scdf->feasible_edges, edge)) {
|
||||
CANDIDATE /tmp/php-src/Zend/Optimizer/zend_dfg.c:20 if (!zend_bitset_in(def, var_num)) {
|
||||
CANDIDATE /tmp/php-src/Zend/Optimizer/zend_dfg.h:23 zend_bitset_in(DFG_BITSET(set, set_size, block_num), (var_num))
|
||||
CANDIDATE /tmp/php-src/Zend/Optimizer/zend_dfg.h:25 zend_bitset_in(DFG_BITSET(set, set_size, block_num), (var_num))
|
||||
CANDIDATE /tmp/php-src/Zend/Optimizer/zend_dfg.h:33 zend_bitset_in(DFG_BITSET(set, set_size, block_num), (var_num))
|
||||
CANDIDATE /tmp/php-src/Zend/Optimizer/zend_dfg.h:46 zend_bitset_in(DFG_BITSET(set, set_size, block_num), (var_num))
|
||||
# roots: /tmp/php-src/ext/opcache/Optimizer
|
||||
[0m# TRIAGE: all 6 candidates are zend_bitset_in = ZEND_BIT_TEST (bitwise AND, O(1)) — FALSE POSITIVES
|
||||
# php-zend: CLEAN — DFG/SCDF/SSA passes use zend_bitset (word-array bitset), not lists
|
||||
65
tools/scan-results/postgresql.txt
Normal file
65
tools/scan-results/postgresql.txt
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
[34m# scan=postgresql host=unsb-vm-3586-948591 date=2026-03-23T21:43:47Z
|
||||
Updating files: 61% (4646/7561)
Updating files: 62% (4688/7561)
Updating files: 63% (4764/7561)
Updating files: 64% (4840/7561)
Updating files: 65% (4915/7561)
Updating files: 66% (4991/7561)
Updating files: 67% (5066/7561)
Updating files: 68% (5142/7561)
Updating files: 69% (5218/7561)
Updating files: 70% (5293/7561)
Updating files: 71% (5369/7561)
Updating files: 72% (5444/7561)
Updating files: 73% (5520/7561)
Updating files: 74% (5596/7561)
Updating files: 75% (5671/7561)
Updating files: 76% (5747/7561)
Updating files: 77% (5822/7561)
Updating files: 78% (5898/7561)
Updating files: 79% (5974/7561)
Updating files: 80% (6049/7561)
Updating files: 81% (6125/7561)
Updating files: 82% (6201/7561)
Updating files: 83% (6276/7561)
Updating files: 84% (6352/7561)
Updating files: 85% (6427/7561)
Updating files: 86% (6503/7561)
Updating files: 87% (6579/7561)
Updating files: 88% (6654/7561)
Updating files: 89% (6730/7561)
Updating files: 90% (6805/7561)
Updating files: 91% (6881/7561)
Updating files: 92% (6957/7561)
Updating files: 93% (7032/7561)
Updating files: 94% (7108/7561)
Updating files: 95% (7183/7561)
Updating files: 96% (7259/7561)
Updating files: 97% (7335/7561)
Updating files: 98% (7410/7561)
Updating files: 99% (7486/7561)
Updating files: 100% (7561/7561)
Updating files: 100% (7561/7561), done.
|
||||
# roots: /tmp/postgres/src/backend/optimizer
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/path/equivclass.c:1041 if (!list_member(exprvars, lfirst(lc2))) [loop: foreach(lc2, emvars)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/path/equivclass.c:2670 !list_member_oid(ec->ec_opfamilies, opfamily)) [loop: foreach(lc1, root->eq_classes)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/path/indxpath.c:524 if (list_member(*considered_relids, clause_relids)) [loop: foreach(lc, indexjoinclauses)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/path/indxpath.c:619 if (list_member(*considered_relids, relids)) [loop: foreach(lc, jclauseset->indexclauses[indexcol])]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/path/indxpath.c:4232 if (!list_member_oid(rinfo->mergeopfamilies, ind->opfamily[c])) [loop: foreach(lc, restrictlist)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/path/pathkeys.c:414 !list_member_ptr(grouping_pathkeys, pathkey) || [loop: foreach(lc, pathkeys)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/plan/analyzejoins.c:1914 if (!list_member(toKeep->reltarget->exprs, node)) [loop: foreach(lc, toRemove->reltarget->exprs)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/plan/createplan.c:3099 if (list_member(indexquals, clause)) [loop: foreach(l, scan_clauses)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/plan/createplan.c:3101 if (rinfo->parent_ec && list_member_ptr(indexECs, rinfo->parent_ec)) [loop: foreach(l, scan_clauses)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/plan/createplan.c:3418 if (list_member_ptr(tidquals, rinfo)) [loop: foreach(l, scan_clauses)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/plan/createplan.c:3500 if (list_member_ptr(tidrangequals, rinfo)) [loop: foreach(l, scan_clauses)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/plan/createplan.c:4291 if (tlist_member((Expr *) phv, outer_tlist)) [loop: foreach(lc, nestParams)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/plan/createplan.c:4299 * Note: it's safe to do this after the tlist_member() check, because [loop: foreach(lc, nestParams)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/plan/planner.c:2971 if (list_member_ptr(new_groupclause, gc)) [loop: foreach(gl, parse->groupClause)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/plan/planner.c:3233 if (list_member_int(new_elems, ref)) [loop: foreach(lc, groupingSets)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/prep/prepqual.c:583 if (!list_member(((BoolExpr *) clause)->args, refclause)) [loop: foreach(temp, reference)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/prep/preptlist.c:180 if (tlist_member((Expr *) var, tlist)) [loop: foreach(l2, vars)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/prep/preptlist.c:206 if (tlist_member((Expr *) var, tlist)) [loop: foreach(l, vars)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/prep/preptlist.c:316 if (tlist_member((Expr *) var, tlist)) [loop: foreach(l, vars)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/util/relnode.c:3127 if (list_member(vars, var)) [loop: foreach(lc, root->agg_clause_list)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/util/tlist.c:83 * tlist_member [loop: foreach(temp, targetlist)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/util/tlist.c:88 tlist_member(Expr *node, List *targetlist) [loop: foreach(temp, targetlist)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/util/tlist.c:150 if (!tlist_member(expr, tlist)) [loop: foreach(lc, exprs)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/util/tlist.c:752 if (!list_member(target->exprs, expr)) [loop: foreach(lc, exprs)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/util/tlist.c:812 tle = tlist_member(expr, tlist); [loop: foreach(lc, target->exprs)]
|
||||
CANDIDATE /tmp/postgres/src/backend/optimizer/util/tlist.c:1118 if (list_member(prev_level_tlist, item->expr)) [loop: foreach(lcx, input_srfs)]
|
||||
# roots: /tmp/postgres/src/backend/nodes
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:661 list_member(const List *list, const void *datum) [loop: foreach(cell, list)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:682 list_member_ptr(const List *list, const void *datum) [loop: foreach(cell, list)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:702 list_member_int(const List *list, int datum) [loop: foreach(cell, list)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:722 list_member_oid(const List *list, Oid datum) [loop: foreach(cell, list)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:742 list_member_xid(const List *list, TransactionId datum) [loop: foreach(cell, list)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1077 if (!list_member(result, lfirst(cell))) [loop: foreach(cell, list2)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1101 if (!list_member_ptr(result, lfirst(cell))) [loop: foreach(cell, list2)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1124 if (!list_member_int(result, lfirst_int(cell))) [loop: foreach(cell, list2)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1147 if (!list_member_oid(result, lfirst_oid(cell))) [loop: foreach(cell, list2)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1188 if (list_member(list2, lfirst(cell))) [loop: foreach(cell, list1)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1214 if (list_member_int(list2, lfirst_int(cell))) [loop: foreach(cell, list1)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1250 if (!list_member(list2, lfirst(cell))) [loop: foreach(cell, list1)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1276 if (!list_member_ptr(list2, lfirst(cell))) [loop: foreach(cell, list1)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1301 if (!list_member_int(list2, lfirst_int(cell))) [loop: foreach(cell, list1)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1326 if (!list_member_oid(list2, lfirst_oid(cell))) [loop: foreach(cell, list1)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1414 if (!list_member(list1, lfirst(cell))) [loop: foreach(cell, list2)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1436 if (!list_member_ptr(list1, lfirst(cell))) [loop: foreach(cell, list2)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1457 if (!list_member_int(list1, lfirst_int(cell))) [loop: foreach(cell, list2)]
|
||||
CANDIDATE /tmp/postgres/src/backend/nodes/list.c:1478 if (!list_member_oid(list1, lfirst_oid(cell))) [loop: foreach(cell, list2)]
|
||||
# roots: /tmp/postgres/src/backend/rewrite
|
||||
CANDIDATE /tmp/postgres/src/backend/rewrite/rewriteHandler.c:2156 if (list_member_oid(activeRIRs, RelationGetRelid(rel))) [loop: foreach(l, locks)]
|
||||
# roots: /tmp/postgres/src/backend/executor
|
||||
CANDIDATE /tmp/postgres/src/backend/executor/execExpr.c:626 * list_member_int() tests, but that risks O(N^2) behavior with many [loop: foreach(lc, targetList)]
|
||||
# roots: /tmp/postgres/src/backend/parser
|
||||
CANDIDATE /tmp/postgres/src/backend/parser/parse_agg.c:1292 list_member_int(gset_common, tle->ressortgroupref)) [loop: foreach(l, groupClauses)]
|
||||
CANDIDATE /tmp/postgres/src/backend/parser/parse_clause.c:270 * While we could just test "list_member_int(*src_colnos, attnum)" to [loop: foreach(lc, *src_colnos)]
|
||||
CANDIDATE /tmp/postgres/src/backend/parser/parse_clause.c:3310 if (list_member_int(sortgrouprefs, scl->tleSortGroupRef)) [loop: foreach(lc, sortClause)]
|
||||
CANDIDATE /tmp/postgres/src/backend/parser/parse_cte.c:469 if (!list_member(cte->ctecolnames, colname)) [loop: foreach(lc, search_clause->search_col_list)]
|
||||
CANDIDATE /tmp/postgres/src/backend/parser/parse_cte.c:476 if (list_member(seen, colname)) [loop: foreach(lc, search_clause->search_col_list)]
|
||||
CANDIDATE /tmp/postgres/src/backend/parser/parse_cte.c:485 if (list_member(cte->ctecolnames, makeString(search_clause->search_seq_column))) [loop: foreach(lc, search_clause->search_col_list)]
|
||||
CANDIDATE /tmp/postgres/src/backend/parser/parse_cte.c:502 if (!list_member(cte->ctecolnames, colname)) [loop: foreach(lc, cycle_clause->cycle_col_list)]
|
||||
CANDIDATE /tmp/postgres/src/backend/parser/parse_cte.c:509 if (list_member(seen, colname)) [loop: foreach(lc, cycle_clause->cycle_col_list)]
|
||||
CANDIDATE /tmp/postgres/src/backend/parser/parse_cte.c:518 if (list_member(cte->ctecolnames, makeString(cycle_clause->cycle_mark_column))) [loop: foreach(lc, cycle_clause->cycle_col_list)]
|
||||
# scan complete
|
||||
[0m
|
||||
2
tools/scan-results/python.txt
Normal file
2
tools/scan-results/python.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
[31m/tmp/code.sh: line 1: /tmp/cwe407-scan-python.sh: No such file or directory
|
||||
[0m
|
||||
5
tools/scan-results/redis.txt
Normal file
5
tools/scan-results/redis.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[34m# scan=redis host=unsb-vm-1538-92865 date=2026-03-23T20:58:54Z
|
||||
Cloning into 'redis'...
|
||||
# roots: /tmp/redis/src
|
||||
# scan complete
|
||||
[0m
|
||||
68
tools/scan-results/sbt.txt
Normal file
68
tools/scan-results/sbt.txt
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
[34m# scan=sbt host=unsb-vm-8194-330869 date=2026-03-23T22:12:40Z
|
||||
Updating files: 35% (1382/3871)
Updating files: 36% (1394/3871)
Updating files: 37% (1433/3871)
Updating files: 38% (1471/3871)
Updating files: 39% (1510/3871)
Updating files: 40% (1549/3871)
Updating files: 41% (1588/3871)
Updating files: 42% (1626/3871)
Updating files: 43% (1665/3871)
Updating files: 44% (1704/3871)
Updating files: 45% (1742/3871)
Updating files: 46% (1781/3871)
Updating files: 47% (1820/3871)
Updating files: 48% (1859/3871)
Updating files: 49% (1897/3871)
Updating files: 50% (1936/3871)
Updating files: 51% (1975/3871)
Updating files: 52% (2013/3871)
Updating files: 53% (2052/3871)
Updating files: 54% (2091/3871)
Updating files: 55% (2130/3871)
Updating files: 56% (2168/3871)
Updating files: 57% (2207/3871)
Updating files: 58% (2246/3871)
Updating files: 59% (2284/3871)
Updating files: 60% (2323/3871)
Updating files: 61% (2362/3871)
Updating files: 62% (2401/3871)
Updating files: 63% (2439/3871)
Updating files: 64% (2478/3871)
Updating files: 65% (2517/3871)
Updating files: 66% (2555/3871)
Updating files: 67% (2594/3871)
Updating files: 68% (2633/3871)
Updating files: 69% (2671/3871)
Updating files: 70% (2710/3871)
Updating files: 71% (2749/3871)
Updating files: 72% (2788/3871)
Updating files: 73% (2826/3871)
Updating files: 74% (2865/3871)
Updating files: 75% (2904/3871)
Updating files: 76% (2942/3871)
Updating files: 77% (2981/3871)
Updating files: 78% (3020/3871)
Updating files: 79% (3059/3871)
Updating files: 80% (3097/3871)
Updating files: 81% (3136/3871)
Updating files: 82% (3175/3871)
Updating files: 83% (3213/3871)
Updating files: 84% (3252/3871)
Updating files: 84% (3255/3871)
Updating files: 85% (3291/3871)
Updating files: 86% (3330/3871)
Updating files: 87% (3368/3871)
Updating files: 88% (3407/3871)
Updating files: 89% (3446/3871)
Updating files: 90% (3484/3871)
Updating files: 91% (3523/3871)
Updating files: 92% (3562/3871)
Updating files: 93% (3601/3871)
Updating files: 94% (3639/3871)
Updating files: 95% (3678/3871)
Updating files: 96% (3717/3871)
Updating files: 97% (3755/3871)
Updating files: 98% (3794/3871)
Updating files: 99% (3833/3871)
Updating files: 100% (3871/3871)
Updating files: 100% (3871/3871), done.
|
||||
# roots: /tmp/sbt/main/src/main/scala
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/Cross.scala:195\tproject(k).withFilter(projects.contains).flatMap { p => [loop: project(k).toSeq.flatMap(crossVersions(extracted, _).map(v => v -> k))]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/Cross.scala:196\tif (p == extracted.currentRef || !projects.contains(extracted.currentRef)) { [loop: project(k).toSeq.flatMap(crossVersions(extracted, _).map(v => v -> k))]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/Defaults.scala:412\tinsideCI :== sys.env.contains("BUILD_NUMBER") || [loop: .map(java.lang.Boolean.parseBoolean)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/Defaults.scala:2790\tdefined contains ConfigRef(c.name) [loop: enabledOnly(packagedArtifact.toSettingKey, pkgTasks).apply(_.join.map(_.toMap))]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/Defaults.scala:3079\tval useMavenCentral = ars contains Resolver.DefaultMavenRepository [loop: appConfiguration.map(bootRepositories).value]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/Defaults.scala:3419\tval externalModules = update.value.allModules.filterNot(m => projectDeps contains key(m)) [loop: val projectDeps = projectDependencies.value.iterator.map(key).toSet]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/Defaults.scala:4448\tdef isJansiOrJLine(f: File) = f.getName.contains("jline") || f.getName.contains("jansi") [loop: .map(_.toPath)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/ProjectExtra.scala:472\treverse.filter(r => derivedDependencies(r).contains(definingKey)).toSet [loop: .map(c => Def.definedAtString(c.settings).capitalize)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/ProjectExtra.scala:611\tif (acc.exists(map.contains)) { [loop: } yield ref -> p.dependencies.map(_.project)).toMap]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/Resolvers.scala:260\tif (visited.contains(ref)) go(rest, visited, result) [loop: val classpathDeps = buildDeps.classpath.getOrElse(ref, Nil).map(_.project)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/Act.scala:228\tif data.contains(parsed.key) then true [loop: private def keys(ss: Seq[ParsedKey]): Seq[ScopedKey[?]] = ss.map(_.key)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/Act.scala:236\taggregated.nonEmpty && aggregated.exists(data.contains) [loop: private def keys(ss: Seq[ParsedKey]): Seq[ScopedKey[?]] = ss.map(_.key)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/Act.scala:266\tdef isValid(data: Def.Settings)(parsed: ParsedKey): Boolean = data.contains(parsed.key) [loop: private def keys(ss: Seq[ParsedKey]): Seq[ScopedKey[?]] = ss.map(_.key)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/BuildStructure.scala:226\tprivate def nonTopLevelPlugin(name: String) = name.contains('.') [loop: private def autoImports(pluginNames: Seq[String]) = pluginNames.map(_ + ".autoImport")]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/Clean.scala:122\tif extracted.structure.data.contains(stampKey) then stampKey :: Nil else Nil [loop: val targetDir = (scope / target).?.value.map(_.toPath)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/CommandExchange.scala:569\tif (mt.channel.name.contains("console")) shutdown(mt.channel.name) [loop: Option(currentExecRef.get).foreach(cancel)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/Compiler.scala:502\tif !value.contains("$") then value [loop: else x.split(":").map(_.split(",").map(convertVfRef).mkString(",")).mkString(":")]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/Compiler.scala:505\tif !x.contains("$") then x [loop: else x.split(":").map(_.split(",").map(convertVfRef).mkString(",")).mkString(":")]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/Continuous.scala:1310\tstate.get(watchStates).exists(_.contains(channel.name)) [loop: (cmdParser(name) ~> channelParser).map(channel => () => updateState(channel, state))]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/IncrementalTest.scala:216\tif alreadySeen.contains(javaClassName) then SortedSet.empty [loop: .map(stampVf)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/InternalDependencies.scala:26\tcase Array(n, c) if applicableConfigs.contains(n) => Some(c) [loop: val allConfigs = Classpaths.allConfigs(config).map(_.name).toSet]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/InternalDependencies.scala:27\tcase Array(n) if applicableConfigs.contains(n) => [loop: val allConfigs = Classpaths.allConfigs(config).map(_.name).toSet]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/IvyConsole.scala:84\tcase _ if arg.contains(" at ") => acc.copy(resolvers = parseResolver(arg) +: acc.resolvers) [loop: args.foldLeft(Dependencies(Nil, Nil, Nil))(parseArgument(log))]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/LibraryManagement.scala:253\tval transitiveOnly = report.allModules.filterNot(m => originalKeys contains key(m)) [loop: val originalKeys = dependencies.map(key).toSet]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/LintUnused.scala:139\tval unused: Seq[ScopedKey[?]] = cMap.keys.filter(!used.contains(_)).toSeq [loop: val used: Set[ScopedKey[?]] = cMap.values.flatMap(_.dependencies).toSet]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/LintUnused.scala:155\tcase pos: FilePosition => pos.path.contains(File.separator) [loop: val used: Set[ScopedKey[?]] = cMap.values.flatMap(_.dependencies).toSet]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/Load.scala:638\tif (builds contains b) loadAll(bs, references, loaders, builds) [loop: val uris = refs.flatMap(Reference.uri)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/Load.scala:949\tif existingIDs.contains(tryID) then BuildDef.defaultID(localBase) [loop: b.projectDefinitions(base).map(resolveBase(base))]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/PluginsDebug.scala:144\tautoPlugins.filter(p => build.projects.forall(!_.autoPlugins.contains(p))) [loop: autoPlugins.map(_.label).sorted.mkString(" ", s"\n ", "")]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/PluginsDebug.scala:185\tif (!pluginsThisBuild.contains(plugin)) { [loop: val availableInBuilds: List[URI] = perBuild.toList.withFilter(_._2(plugin)).map(_._1)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/PomGenerator.scala:235\tval optional = confs.contains(Configurations.Optional.name) [loop: confStr.split(';').flatMap(_.split("->").head.trim.split(',')).map(_.trim).toSet]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/PomGenerator.scala:238\t.find(c => notOptional.contains(c.name)) [loop: confStr.split(';').flatMap(_.split("->").head.trim.split(',')).map(_.trim).toSet]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/Resolve.scala:58\tkeyIndex.keys(resolvedRef, c.toOption.map(_.name), task) contains key.label [loop: (Some(r), index.projectFor(r))]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/SessionSettings.scala:225\tcase RangePosition(`path`, _) if !keys.contains(s.key) => (s :: in, oth, keys + s.key) [loop: original.reverse.foldLeft((List[Setting[?]](), List[Setting[?]](), Set.empty[ScopedKey[?]])) {]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/SessionSettings.scala:234\tcase Some(ss @ (ns, newLines)) if !ns.init.dependencies.contains(ns.key) => [loop: original.reverse.foldLeft((List[Setting[?]](), List[Setting[?]](), Set.empty[ScopedKey[?]])) {]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/TaskProgress.scala:211\tval newSkip = skip || skipReportTasks.contains(shortName) [loop: while (name(j) == ' ') j += 1]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/TaskProgress.scala:212\tif (hiddenTasks.contains(shortName)) (tasks, newSkip) else (tasks :+ pair, newSkip) [loop: while (name(j) == ' ') j += 1]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/WatchTransitiveDependencies.scala:158\t.withFilter(s => s == Scope.Global || s.project.toOption.exists(projects.contains)) [loop: .map(_.scope.copy(task = Zero, extra = Zero))]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/graph/backend/SbtUpdateReport.scala:59\tif (existingNodeIds.contains(from)) Seq(edge) [loop: license = report.licenses.headOption.map(_._1),]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala:49\tval cycle = parents.contains(module.id) [loop: .map(dependency => processSubtree(graph, dependency, parents + module.id))]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala:1028\tallScopes.contains(scope) [loop: val cp = classpath.map(converter.toPath)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/nio/Settings.scala:96\tif (fileOutputScopes.contains(scope)) { [loop: val init: Def.Initialize[Task[Seq[Path]]] = sk(_.map(_ => Nil))]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala:150\tval isHelp = args.contains(Arg.Help) [loop: .map(report =>]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala:151\tval isQuiet = args.contains(Arg.Quiet) [loop: .map(report =>]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala:152\tval isAppend = args.contains(Arg.Append) [loop: .map(report =>]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala:153\tval isBrowse = args.contains(Arg.Browse) [loop: .map(report =>]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala:249\tval isHelp = args.contains(Arg.Help) [loop: graph.nodes.withFilter(m => m.id.organization == org && m.id.name == name).map(_.id)]
|
||||
CANDIDATE\t/tmp/sbt/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala:250\tval isQuiet = args.contains(Arg.Quiet) [loop: graph.nodes.withFilter(m => m.id.organization == org && m.id.name == name).map(_.id)]
|
||||
# roots: /tmp/sbt/tasks/src/main/scala
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:157\tassert(callers(target).contains(node)) [loop: remove(reverse, node).foreach(dep => notifyDone(node, dep))]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:184\tassert(!(reverse.contains(node))) [loop: remove(reverse, node).foreach(dep => notifyDone(node, dep))]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:185\tassert(!(callers.contains(node))) [loop: remove(reverse, node).foreach(dep => notifyDone(node, dep))]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:336\tassert(viewCache.contains(node), "Not in view cache: " + node) [loop: def addedInv(node: TaskId[?]): Unit = topologicalSort(node).foreach(addedCheck)]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:344\tdef checkForward = onOpt(forward.get(node))(_.contains(dep)) [loop: def addedInv(node: TaskId[?]): Unit = topologicalSort(node).foreach(addedCheck)]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:345\tdef checkReverse = onOpt(reverse.get(dep))(_.exists(_ == node)) [loop: def addedInv(node: TaskId[?]): Unit = topologicalSort(node).foreach(addedCheck)]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:355\tassert(!(forward.contains(node))) [loop: dependencies(n).foldLeft(List.empty)((ss, dep) => visit(dep) ::: ss)]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:359\tassert(!(reverse.contains(node))) [loop: dependencies(n).foldLeft(List.empty)((ss, dep) => visit(dep) ::: ss)]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:360\tassert(!(forward.contains(node))) [loop: dependencies(n).foldLeft(List.empty)((ss, dep) => visit(dep) ::: ss)]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:361\tassert(!(callers.contains(node))) [loop: dependencies(n).foldLeft(List.empty)((ss, dep) => visit(dep) ::: ss)]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:362\tassert(!(viewCache.contains(node))) [loop: dependencies(n).foldLeft(List.empty)((ss, dep) => visit(dep) ::: ss)]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:363\tassert(!(results.contains(node))) [loop: dependencies(n).foldLeft(List.empty)((ss, dep) => visit(dep) ::: ss)]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:380\tassert(!(forward.contains(node))) [loop: dependencies(n).foldLeft(List.empty)((ss, dep) => visit(dep) ::: ss)]
|
||||
CANDIDATE\t/tmp/sbt/tasks/src/main/scala/sbt/Execute.scala:397\tif all.contains(target) then cyclic(node, target, "Cyclic reference") [loop: for (caller <- callers) cycleCheck(caller, called)]
|
||||
# scan complete
|
||||
[0m
|
||||
22
tools/scan-results/spidermonkey.txt
Normal file
22
tools/scan-results/spidermonkey.txt
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[34m# scan=spidermonkey host=unsb-vm-7810-4994 date=2026-03-23T21:25:08Z
|
||||
Updating files: 3% (2/63)
Updating files: 4% (3/63)
Updating files: 6% (4/63)
Updating files: 7% (5/63)
Updating files: 9% (6/63)
Updating files: 11% (7/63)
Updating files: 12% (8/63)
Updating files: 14% (9/63)
Updating files: 15% (10/63)
Updating files: 17% (11/63)
Updating files: 19% (12/63)
Updating files: 20% (13/63)
Updating files: 22% (14/63)
Updating files: 23% (15/63)
Updating files: 25% (16/63)
Updating files: 26% (17/63)
Updating files: 28% (18/63)
Updating files: 30% (19/63)
Updating files: 31% (20/63)
Updating files: 33% (21/63)
Updating files: 34% (22/63)
Updating files: 36% (23/63)
Updating files: 38% (24/63)
Updating files: 39% (25/63)
Updating files: 41% (26/63)
Updating files: 42% (27/63)
Updating files: 44% (28/63)
Updating files: 46% (29/63)
Updating files: 47% (30/63)
Updating files: 49% (31/63)
Updating files: 50% (32/63)
Updating files: 52% (33/63)
Updating files: 53% (34/63)
Updating files: 55% (35/63)
Updating files: 57% (36/63)
Updating files: 58% (37/63)
Updating files: 60% (38/63)
Updating files: 61% (39/63)
Updating files: 63% (40/63)
Updating files: 65% (41/63)
Updating files: 66% (42/63)
Updating files: 68% (43/63)
Updating files: 69% (44/63)
Updating files: 71% (45/63)
Updating files: 73% (46/63)
Updating files: 74% (47/63)
Updating files: 76% (48/63)
Updating files: 77% (49/63)
Updating files: 79% (50/63)
Updating files: 80% (51/63)
Updating files: 82% (52/63)
Updating files: 84% (53/63)
Updating files: 85% (54/63)
Updating files: 87% (55/63)
Updating files: 88% (56/63)
Updating files: 90% (57/63)
Updating files: 92% (58/63)
Updating files: 93% (59/63)
Updating files: 95% (60/63)
Updating files: 96% (61/63)
Updating files: 98% (62/63)
Updating files: 100% (63/63)
Updating files: 100% (63/63), done.
|
||||
# roots: /tmp/geckosrc/js/src
|
||||
CANDIDATE /tmp/geckosrc/js/src/builtin/intl/IntlObject.cpp:142 auto p = std::find(rbegin, rend, '-');
|
||||
CANDIDATE /tmp/geckosrc/js/src/builtin/temporal/Calendar.cpp:1092 MOZ_ASSERT(CalendarMonthCodes(calendarId).contains(monthCode));
|
||||
CANDIDATE /tmp/geckosrc/js/src/builtin/temporal/Calendar.cpp:1095 MOZ_ASSERT(CalendarMonthCodes(calendarId).contains(monthCode));
|
||||
CANDIDATE /tmp/geckosrc/js/src/builtin/temporal/CalendarFields.h:225 if (notUnsetDefault.contains(field)) {
|
||||
CANDIDATE /tmp/geckosrc/js/src/gc/Heap.cpp:513 MOZ_ASSERT(gc->availableChunks(lock).contains(this));
|
||||
CANDIDATE /tmp/geckosrc/js/src/jit/arm/Architecture-arm.cpp:131 if (capabilities.contains(ARMCapability::VFPv4)) {
|
||||
CANDIDATE /tmp/geckosrc/js/src/jit/arm/Architecture-arm.cpp:174 if (capabilities.contains(ARMCapability::VFPv3) ||
|
||||
CANDIDATE /tmp/geckosrc/js/src/jsapi-tests/testPrintError.cpp:55 CHECK(buf.contains("testPrintError_Works.js:3:1 uncaught exception: null\n"));
|
||||
CANDIDATE /tmp/geckosrc/js/src/jsapi-tests/testPrintError.cpp:103 warningSuccess = buf.contains("warning: warning message\n");
|
||||
CANDIDATE /tmp/geckosrc/js/src/vm/Watchtower.cpp:65 if (proto->as<NativeObject>().contains(cx, id)) {
|
||||
CANDIDATE /tmp/geckosrc/js/src/vm/Watchtower.cpp:75 if (proto->as<NativeObject>().contains(cx, id)) {
|
||||
# scan complete
|
||||
[0m# TRIAGE 2026-03-23: all false positives
|
||||
# IntlObject std::find — locale string parsing, not graph
|
||||
# Calendar .contains — bounded 12-13 month codes
|
||||
# Architecture capabilities.contains — CPU bitfield
|
||||
# Heap availableChunks.contains — GC hash set O(1)
|
||||
# Watchtower NativeObject.contains — JS property hash O(1)
|
||||
# spidermonkey: CLEAN
|
||||
11
tools/scan-results/sqlite.txt
Normal file
11
tools/scan-results/sqlite.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[34m# scan=sqlite host=unsb-vm-6786-882140 date=2026-03-23T21:52:08Z
|
||||
Cloning into 'sqlite'...
|
||||
# roots: /tmp/sqlite/src
|
||||
CANDIDATE\t/tmp/sqlite/src/alter.c:938\tfor(i=0; i<pEList->nExpr; i++){ [loop: sqlite3WalkExprList(&sWalker, pEList);]
|
||||
CANDIDATE\t/tmp/sqlite/src/alter.c:1475\tfor(i=0; i<pSrc->nSrc; i++){ [loop: sqlite3WalkExprList(pWalker, pStep->pExprList);]
|
||||
CANDIDATE\t/tmp/sqlite/src/select.c:7496\tfor(ii=0; ii<pSelect->pSrc->nSrc; ii++){ [loop: sqlite3WalkExprList(&w, pItem->u1.pFuncArg);]
|
||||
CANDIDATE\t/tmp/sqlite/src/select.c:7520\tfor(ii=0; ii<p1->nExpr; ii++){ [loop: sqlite3WalkExprList(&w, pItem->u1.pFuncArg);]
|
||||
CANDIDATE\t/tmp/sqlite/src/walker.c:110\tfor(i=p->nExpr, pItem=p->a; i>0; i--, pItem++){ [loop: int sqlite3WalkExprList(Walker *pWalker, ExprList *p){]
|
||||
CANDIDATE\t/tmp/sqlite/src/walker.c:173\tfor(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ [loop: && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)]
|
||||
CANDIDATE\t/tmp/sqlite/src/window.c:901\tfor(i=0; i<pAppend->nExpr; i++){ [loop: (void)sqlite3WalkExprList(&sWalker, pEList);]
|
||||
[0m
|
||||
37
tools/scan-results/v8.txt
Normal file
37
tools/scan-results/v8.txt
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
[34m# scan=v8 host=unsb-vm-4-258 date=2026-03-23T21:20:28Z
|
||||
Cloning into 'v8'...
|
||||
# roots: /tmp/v8/src/compiler
|
||||
CANDIDATE /tmp/v8/src/compiler/all-nodes.h:19 return id < is_reachable_.length() && is_reachable_.Contains(id);
|
||||
CANDIDATE /tmp/v8/src/compiler/all-nodes.h:20 return id < is_reachable_.length() && is_reachable_.Contains(id);
|
||||
CANDIDATE /tmp/v8/src/compiler/all-nodes.h:21 return id < is_reachable_.length() && is_reachable_.Contains(id);
|
||||
CANDIDATE /tmp/v8/src/compiler/all-nodes.h:22 return id < is_reachable_.length() && is_reachable_.Contains(id);
|
||||
CANDIDATE /tmp/v8/src/compiler/load-elimination.cc:810 if (maps.contains(object_maps)) return Replace(effect);
|
||||
CANDIDATE /tmp/v8/src/compiler/machine-operator.h:480 return !unsupported.contains(rep);
|
||||
CANDIDATE /tmp/v8/src/compiler/string-builder-optimizer.cc:470 if (std::find(dst->begin(), dst->end(), pred) == dst->end()) {
|
||||
CANDIDATE /tmp/v8/src/compiler/turbofan-graph.cc:27 auto const it = std::find(decorators_.begin(), decorators_.end(), decorator);
|
||||
CANDIDATE /tmp/v8/src/compiler/turbofan-graph.cc:28 auto const it = std::find(decorators_.begin(), decorators_.end(), decorator);
|
||||
CANDIDATE /tmp/v8/src/compiler/turboshaft/loop-finder.cc:11 if (!config_.contains(ConfigFlags::kFindCalls)) return;
|
||||
CANDIDATE /tmp/v8/src/compiler/turboshaft/loop-finder.cc:23 if (!config_.contains(ConfigFlags::kFindCalls)) return;
|
||||
CANDIDATE /tmp/v8/src/compiler/turboshaft/loop-finder.cc:35 if (!config_.contains(ConfigFlags::kFindCalls)) return;
|
||||
CANDIDATE /tmp/v8/src/compiler/turboshaft/loop-finder.cc:36 if (!config_.contains(ConfigFlags::kFindCalls)) return;
|
||||
CANDIDATE /tmp/v8/src/compiler/turboshaft/store-store-elimination-reducer-inl.h:113 DCHECK(!active_keys_.Contains(key));
|
||||
CANDIDATE /tmp/v8/src/compiler/turboshaft/store-store-elimination-reducer-inl.h:115 DCHECK(!active_keys_.Contains(key));
|
||||
CANDIDATE /tmp/v8/src/compiler/turboshaft/wasm-shuffle-reducer.h:148 return std::find(unary_low_half_ops.begin(), unary_low_half_ops.end(),
|
||||
CANDIDATE /tmp/v8/src/compiler/turboshaft/wasm-shuffle-reducer.h:149 return std::find(unary_low_half_ops.begin(), unary_low_half_ops.end(),
|
||||
CANDIDATE /tmp/v8/src/compiler/turboshaft/wasm-shuffle-reducer.h:160 return std::find(binary_low_half_ops.begin(), binary_low_half_ops.end(),
|
||||
# roots: /tmp/v8/src/codegen
|
||||
CANDIDATE /tmp/v8/src/codegen/loong64/macro-assembler-loong64.cc:445 kAnyInterceptorInfoExternalPointerTagRange.Contains(tag_range));
|
||||
CANDIDATE /tmp/v8/src/codegen/riscv/macro-assembler-riscv.cc:538 kAnyInterceptorInfoExternalPointerTagRange.Contains(tag_range));
|
||||
CANDIDATE /tmp/v8/src/codegen/x64/macro-assembler-x64.cc:754 kAnyInterceptorInfoExternalPointerTagRange.Contains(tag_range));
|
||||
# roots: /tmp/v8/src/interpreter
|
||||
# scan complete
|
||||
[0m
|
||||
# TRIAGE 2026-03-23:
|
||||
# all-nodes.h is_reachable_ — BitVector → O(1) CLEAN
|
||||
# store-store active_keys_.Contains — IntrusiveSet → O(1) CLEAN
|
||||
# loop-finder config_.contains — bitfield config flags → O(1) CLEAN
|
||||
# macro-assembler .Contains(tag_range)— range check → O(1) CLEAN
|
||||
# turbofan-graph decorators_ find — ZoneVector 0-2 items → FALSE POSITIVE (bounded)
|
||||
# string-builder-optimizer find pred — SmallVector<BB*,15> → FALSE POSITIVE (capped=15)
|
||||
# wasm-shuffle-reducer std::find — static constexpr array → FALSE POSITIVE (tiny fixed set)
|
||||
# v8: CLEAN — no CWE-407 defects
|
||||
6
tools/scan-results/varnish.txt
Normal file
6
tools/scan-results/varnish.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[34m# scan=varnish host=unsb-vm-2-496505 date=2026-03-23T21:26:11Z
|
||||
Cloning into 'varnish'...
|
||||
# roots: /tmp/varnish/lib/libvcc
|
||||
# roots: /tmp/varnish/bin/varnishd
|
||||
# scan complete
|
||||
[0m
|
||||
8
tools/scan-results/verilator.txt
Normal file
8
tools/scan-results/verilator.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[34m# scan=verilator host=unsb-vm-5762-2434 date=2026-03-23T20:20:35Z
|
||||
Cloning into 'verilator'...
|
||||
# roots: /tmp/verilator/src
|
||||
CANDIDATE /tmp/verilator/src/V3ExecGraph.cpp:955 if (schedule.threadId(nextp) != threadId && schedule.contains(nextp)) {
|
||||
CANDIDATE /tmp/verilator/src/V3Gate.cpp:722 if (readVscps.count(consVVertexp->varScp())) {
|
||||
CANDIDATE /tmp/verilator/src/V3Options.h:724 return !m_fDfgPeepholeDisabled.count(name);
|
||||
# scan complete
|
||||
[0m
|
||||
30
tools/scan-results/yosys.txt
Normal file
30
tools/scan-results/yosys.txt
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
[34m# scan=yosys host=unsb-vm-1026-849484 date=2026-03-23T20:19:57Z
|
||||
Cloning into 'yosys'...
|
||||
# roots: /tmp/yosys/kernel /tmp/yosys/passes
|
||||
CANDIDATE /tmp/yosys/kernel/functional.h:256 bool has_input(IdString name, IdString kind) const { return _inputs.count({name, kind}); }
|
||||
CANDIDATE /tmp/yosys/passes/cmds/glift.cc:341 log_assert(std::find(cell_module_def->ports.begin(), cell_module_def->ports.end(), port_taint.as_wire()->name) != cell_module_def->ports.end());
|
||||
CANDIDATE /tmp/yosys/passes/cmds/ltp.cc:133 if (bit2ff.count(maxbit))
|
||||
CANDIDATE /tmp/yosys/passes/cmds/ltp.cc:144 if (bit2ff.count(maxbit))
|
||||
CANDIDATE /tmp/yosys/passes/cmds/ltp.cc:156 if (bit2ff.count(maxbit))
|
||||
CANDIDATE /tmp/yosys/passes/cmds/scc.cc:49 log_assert(workQueue.count(cell) > 0);
|
||||
CANDIDATE /tmp/yosys/passes/cmds/scc.cc:84 if (cellLabels.count(nextCell) == 0) {
|
||||
CANDIDATE /tmp/yosys/passes/fsm/fsm_opt.cc:37 if (unreachable_states.count(i)) {
|
||||
CANDIDATE /tmp/yosys/passes/fsm/fsm_opt.cc:41 if (unreachable_states.count(i)) {
|
||||
CANDIDATE /tmp/yosys/passes/fsm/fsm_opt.cc:48 if (unreachable_states.count(i)) {
|
||||
CANDIDATE /tmp/yosys/passes/fsm/fsm_opt.cc:51 if (unreachable_states.count(i)) {
|
||||
CANDIDATE /tmp/yosys/passes/fsm/fsm_opt.cc:53 if (unreachable_states.count(i)) {
|
||||
CANDIDATE /tmp/yosys/passes/opt/opt_expr.cc:514 if (outbit_to_cell.count(bit))
|
||||
CANDIDATE /tmp/yosys/passes/opt/share.cc:1125 if (stop.count(root))
|
||||
CANDIDATE /tmp/yosys/passes/opt/share.cc:1128 if (stop.count(root))
|
||||
CANDIDATE /tmp/yosys/passes/opt/share.cc:1135 if (stop.count(root))
|
||||
CANDIDATE /tmp/yosys/passes/opt/share.cc:1160 if (stop.count(root))
|
||||
CANDIDATE /tmp/yosys/passes/sat/recover_names.cc:158 if (anchors.count(idbit.first))
|
||||
CANDIDATE /tmp/yosys/passes/sat/recover_names.cc:597 if (gate_worker.bit2primary.count(gold_bit.first)) {
|
||||
CANDIDATE /tmp/yosys/passes/sat/recover_names.cc:598 if (gate_worker.bit2primary.count(gold_bit.first)) {
|
||||
CANDIDATE /tmp/yosys/passes/techmap/abc.cc:666 n, in_counts[n], workpool.count(n) ? ", shape=box" : "");
|
||||
CANDIDATE /tmp/yosys/passes/techmap/abc.cc:667 n, in_counts[n], workpool.count(n) ? ", shape=box" : "");
|
||||
CANDIDATE /tmp/yosys/passes/techmap/abc9.cc:347 if (saved_designs.count("$abc9_holes") || help_mode) {
|
||||
CANDIDATE /tmp/yosys/passes/techmap/abc9.cc:349 if (saved_designs.count("$abc9_holes") || help_mode) {
|
||||
CANDIDATE /tmp/yosys/passes/techmap/abc9_ops.cc:804 if (bit_drivers.count(it.first))
|
||||
# scan complete
|
||||
[0m
|
||||
39
tools/scans/ant.sh
Executable file
39
tools/scans/ant.sh
Executable file
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — Apache Ant (Java build tool)
|
||||
# Old Java code (~2000s); high probability of ArrayList/Vector for visited sets
|
||||
# Strategy: generic Java patterns — List.contains, ArrayList membership in loops
|
||||
set -euo pipefail
|
||||
echo "# scan=ant host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
cd /tmp && git clone --depth 1 https://github.com/apache/ant ant 2>&1 | tail -1
|
||||
|
||||
# O(n) membership patterns in Java
|
||||
JAVA_MEM='\.contains\s*\(|\.indexOf\s*\(|Collections\.frequency\s*\('
|
||||
|
||||
# Loop constructs
|
||||
JAVA_LOOP='for\s*\(|while\s*\(|\.forEach\s*\(|\.iterator\s*\('
|
||||
|
||||
for dir in \
|
||||
src/main/org/apache/tools/ant \
|
||||
src/main/org/apache/tools/ant/taskdefs \
|
||||
src/main/org/apache/tools/ant/types; do
|
||||
[ -d /tmp/ant/$dir ] || continue
|
||||
echo "# roots: /tmp/ant/$dir"
|
||||
find /tmp/ant/$dir -name "*.java" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
ml=$(grep -nE "$JAVA_MEM" "$f" 2>/dev/null | cut -d: -f1 || true)
|
||||
[ -z "$ml" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
ctx=$(sed -n "${s},${e}p" "$f" 2>/dev/null || true)
|
||||
# Only flag if context mentions graph/dag/dep/order/sort/visit/cycle/topo
|
||||
graph_hit=$(echo "$ctx" | grep -iE 'graph|depend|topo|visit|cycle|dag|sort|stack|order|reachab|ancestor|transit' | head -1 | sed 's/^\s*//' || true)
|
||||
[ -z "$graph_hit" ] && continue
|
||||
loop_hit=$(echo "$ctx" | grep -iE "$JAVA_LOOP" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$loop_hit" ] && {
|
||||
mem_line=$(sed -n "${ln}p" "$f" | sed 's/^\s*//')
|
||||
echo "CANDIDATE\t${f}:${ln}\t${mem_line} [loop: ${loop_hit}]"
|
||||
}
|
||||
done <<< "$ml"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
20
tools/scans/apache2.sh
Executable file
20
tools/scans/apache2.sh
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — Apache httpd (module graph, proxy balancer)
|
||||
set -euo pipefail
|
||||
echo "# scan=apache2 host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://github.com/apache/httpd apache2 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="topolog\|cycle\b\|reachab\|dependency\|dfs\b\|module.*order\|order.*module\|load.*order\|balancer.*node"
|
||||
C_MEM='apr_array_push.*==\|for.*elts\|ap_find_linked_module\|linear\|ap_array_.*find\|module.*contains'
|
||||
|
||||
echo "# roots: /tmp/apache2/server /tmp/apache2/modules"
|
||||
find /tmp/apache2/server /tmp/apache2/modules -name "*.c" -o -name "*.h" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
echo "# scan complete"
|
||||
25
tools/scans/bazel.sh
Executable file
25
tools/scans/bazel.sh
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — Bazel build system (dependency graph, SkyFrame, action graph)
|
||||
set -euo pipefail
|
||||
echo "# scan=bazel host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://github.com/bazelbuild/bazel bazel 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="topolog|cycle|dfs\b|scc\b|strongly.connected|reachab|dependency|tarjan|postorder|graph"
|
||||
JAVA_MEM='ArrayList.*contains|List.*contains|\.indexOf[(]|LinkedList.*contains|new ArrayList.*visited|new ArrayList.*stack|ImmutableList.*contains'
|
||||
|
||||
for dir in src/main/java/com/google/devtools/build/lib/graph \
|
||||
src/main/java/com/google/devtools/build/lib/skyframe \
|
||||
src/main/java/com/google/devtools/build/lib/packages; do
|
||||
[ -d /tmp/bazel/$dir ] || continue
|
||||
echo "# roots: /tmp/bazel/$dir"
|
||||
find /tmp/bazel/$dir -name "*.java" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$JAVA_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
23
tools/scans/bird.sh
Executable file
23
tools/scans/bird.sh
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — BIRD Internet Routing Daemon (BGP, OSPF, IS-IS, RIP)
|
||||
set -euo pipefail
|
||||
echo "# scan=bird host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://gitlab.nic.cz/labs/bird bird 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="shortest.path|dijkstra|spf\b|scc\b|topolog|cycle|reachab|path.find|dfs\b|bfs\b|strongly.connected|next.hop"
|
||||
C_MEM='node_find|list_walk|WALK_LIST|WALK_TLIST|linear_search|find.*next|chain.*next.*next|loop.*->next.*->next'
|
||||
|
||||
for proto in proto/ospf proto/bgp proto/isis proto/rip nest; do
|
||||
[ -d /tmp/bird/$proto ] || continue
|
||||
echo "# roots: /tmp/bird/$proto"
|
||||
find /tmp/bird/$proto -name "*.c" -o -name "*.h" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
61
tools/scans/bundler.sh
Executable file
61
tools/scans/bundler.sh
Executable file
|
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — Bundler (Ruby gem dependency resolver)
|
||||
# Uses Molinillo solver; dependency graph resolution with visited tracking
|
||||
# Strategy: Ruby membership patterns (include?, member?, Array#include?) in graph context
|
||||
set -euo pipefail
|
||||
echo "# scan=bundler host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
cd /tmp && git clone --depth 1 https://github.com/rubygems/rubygems rubygems 2>&1 | tail -1
|
||||
# bundler is inside rubygems
|
||||
BUNDLER=/tmp/rubygems/bundler
|
||||
|
||||
[ -d "$BUNDLER" ] || { echo "ERROR: bundler dir not found"; exit 1; }
|
||||
|
||||
# O(n) membership patterns in Ruby
|
||||
RUBY_MEM='\.include\?\s*\(|\.member\?\s*\(|Array#include|\.index\s*\(|\bin\s+\[|\bselect\b.*==\b'
|
||||
|
||||
# Loop constructs
|
||||
RUBY_LOOP='\.each\s*\{|\.each\s*do\s*\||while\s+|for\s+.*in\s+|\.map\s*\{|\.reduce\s*\{'
|
||||
|
||||
for dir in \
|
||||
lib/bundler \
|
||||
lib/bundler/resolver \
|
||||
lib/bundler/graph; do
|
||||
[ -d "$BUNDLER/$dir" ] || [ -d "/tmp/rubygems/$dir" ] && target_dir="/tmp/rubygems/$dir" || continue
|
||||
[ -d "/tmp/rubygems/$dir" ] || continue
|
||||
echo "# roots: /tmp/rubygems/$dir"
|
||||
find /tmp/rubygems/$dir -name "*.rb" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
ml=$(grep -nE "$RUBY_MEM" "$f" 2>/dev/null | cut -d: -f1 || true)
|
||||
[ -z "$ml" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
ctx=$(sed -n "${s},${e}p" "$f" 2>/dev/null || true)
|
||||
graph_hit=$(echo "$ctx" | grep -iE 'graph|depend|topo|visit|cycle|dag|sort|stack|order|reachab|ancestor|transit|resolver|package|gem' | head -1 | sed 's/^\s*//' || true)
|
||||
[ -z "$graph_hit" ] && continue
|
||||
loop_hit=$(echo "$ctx" | grep -iE "$RUBY_LOOP" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$loop_hit" ] && {
|
||||
mem_line=$(sed -n "${ln}p" "$f" | sed 's/^\s*//')
|
||||
echo "CANDIDATE\t${f}:${ln}\t${mem_line} [loop: ${loop_hit}]"
|
||||
}
|
||||
done <<< "$ml"
|
||||
done
|
||||
done
|
||||
|
||||
# Also scan Molinillo (bundler's solver) directly
|
||||
echo "# roots: molinillo lib"
|
||||
cd /tmp && git clone --depth 1 https://github.com/CocoaPods/Molinillo molinillo 2>&1 | tail -1
|
||||
find /tmp/molinillo/lib -name "*.rb" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
ml=$(grep -nE "$RUBY_MEM" "$f" 2>/dev/null | cut -d: -f1 || true)
|
||||
[ -z "$ml" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
ctx=$(sed -n "${s},${e}p" "$f" 2>/dev/null || true)
|
||||
loop_hit=$(echo "$ctx" | grep -iE "$RUBY_LOOP" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$loop_hit" ] && {
|
||||
mem_line=$(sed -n "${ln}p" "$f" | sed 's/^\s*//')
|
||||
echo "CANDIDATE\t${f}:${ln}\t${mem_line} [loop: ${loop_hit}]"
|
||||
}
|
||||
done <<< "$ml"
|
||||
done
|
||||
|
||||
echo "# scan complete"
|
||||
39
tools/scans/composer.sh
Executable file
39
tools/scans/composer.sh
Executable file
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — Composer (PHP package manager)
|
||||
# Large PHP ecosystem; dep solver uses topological sort and cycle detection
|
||||
# Strategy: PHP membership patterns in graph/dep/solver context
|
||||
set -euo pipefail
|
||||
echo "# scan=composer host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
cd /tmp && git clone --depth 1 https://github.com/composer/composer composer 2>&1 | tail -1
|
||||
|
||||
# O(n) membership patterns in PHP
|
||||
PHP_MEM='in_array\s*\(|array_search\s*\(|\barray_key_exists\s*\('
|
||||
|
||||
# Loop constructs
|
||||
PHP_LOOP='foreach\s*\(|for\s*\(|while\s*\('
|
||||
|
||||
for dir in \
|
||||
src/Composer/DependencyResolver \
|
||||
src/Composer/Package \
|
||||
src/Composer/Repository \
|
||||
src/Composer/Util; do
|
||||
[ -d /tmp/composer/$dir ] || continue
|
||||
echo "# roots: /tmp/composer/$dir"
|
||||
find /tmp/composer/$dir -name "*.php" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
ml=$(grep -nE "$PHP_MEM" "$f" 2>/dev/null | cut -d: -f1 || true)
|
||||
[ -z "$ml" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
ctx=$(sed -n "${s},${e}p" "$f" 2>/dev/null || true)
|
||||
graph_hit=$(echo "$ctx" | grep -iE 'graph|depend|topo|visit|cycle|dag|sort|stack|order|reachab|ancestor|transit|package|solver|pool' | head -1 | sed 's/^\s*//' || true)
|
||||
[ -z "$graph_hit" ] && continue
|
||||
loop_hit=$(echo "$ctx" | grep -iE "$PHP_LOOP" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$loop_hit" ] && {
|
||||
mem_line=$(sed -n "${ln}p" "$f" | sed 's/^\s*//')
|
||||
echo "CANDIDATE\t${f}:${ln}\t${mem_line} [loop: ${loop_hit}]"
|
||||
}
|
||||
done <<< "$ml"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
39
tools/scans/duckdb.sh
Executable file
39
tools/scans/duckdb.sh
Executable file
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — DuckDB (analytical in-process database)
|
||||
# C++ query optimizer with join ordering, expression analysis, DAG execution
|
||||
# Strategy: C++ membership patterns (std::find, .count() on vector) in graph/plan context
|
||||
set -euo pipefail
|
||||
echo "# scan=duckdb host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
cd /tmp && git clone --depth 1 https://github.com/duckdb/duckdb duckdb 2>&1 | tail -1
|
||||
|
||||
# O(n) membership: std::find on vector, or .count() on std::map (O(log n) but worth flagging)
|
||||
CPP_MEM='std::find\s*\(|\.find\s*\(.*\.end\s*\(\)|vector.*\.count\s*\(|\bfind_if\s*\('
|
||||
|
||||
# Loop constructs
|
||||
CPP_LOOP='for\s*\(|while\s*\(|for\s*\(auto\b'
|
||||
|
||||
for dir in \
|
||||
src/optimizer \
|
||||
src/planner \
|
||||
src/execution \
|
||||
src/common/graph; do
|
||||
[ -d /tmp/duckdb/$dir ] || continue
|
||||
echo "# roots: /tmp/duckdb/$dir"
|
||||
find /tmp/duckdb/$dir -name "*.cpp" -o -name "*.hpp" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
ml=$(grep -nE "$CPP_MEM" "$f" 2>/dev/null | cut -d: -f1 || true)
|
||||
[ -z "$ml" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
ctx=$(sed -n "${s},${e}p" "$f" 2>/dev/null || true)
|
||||
graph_hit=$(echo "$ctx" | grep -iE 'graph|depend|topo|visit|cycle|dag|sort|stack|order|reachab|ancestor|transit|join|plan' | head -1 | sed 's/^\s*//' || true)
|
||||
[ -z "$graph_hit" ] && continue
|
||||
loop_hit=$(echo "$ctx" | grep -iE "$CPP_LOOP" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$loop_hit" ] && {
|
||||
mem_line=$(sed -n "${ln}p" "$f" | sed 's/^\s*//')
|
||||
echo "CANDIDATE\t${f}:${ln}\t${mem_line} [loop: ${loop_hit}]"
|
||||
}
|
||||
done <<< "$ml"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
22
tools/scans/exabgp.sh
Executable file
22
tools/scans/exabgp.sh
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — ExaBGP (Python BGP implementation)
|
||||
# Network mode: semitrusted
|
||||
set -euo pipefail
|
||||
echo "# scan=exabgp host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
cd /tmp && git clone --depth 1 https://github.com/Exa-Networks/exabgp exabgp 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="loop|cycle|path|route|reachab|topolog|dfs\b|scc\b|visit"
|
||||
PY_MEM="[^a-z]in (path|stack|visited|seen|queue|aspath|peers)\b|not in (path|stack|visited)\b|\.index\b|list\.append.*\bin "
|
||||
|
||||
echo "# roots: /tmp/exabgp/src"
|
||||
find /tmp/exabgp/src -name "*.py" | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$PY_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
echo "# scan complete"
|
||||
22
tools/scans/frr-tilfa-detail.sh
Executable file
22
tools/scans/frr-tilfa-detail.sh
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd /tmp && git clone --depth 1 https://github.com/FRRouting/frr frr 2>/dev/null
|
||||
|
||||
echo "=== ospf_ti_lfa.c:260-300 ==="
|
||||
sed -n '260,310p' frr/ospfd/ospf_ti_lfa.c
|
||||
|
||||
echo ""
|
||||
echo "=== listnode_lookup definition ==="
|
||||
grep -n "listnode_lookup" frr/lib/linklist.h frr/lib/linklist.c 2>/dev/null | head -10
|
||||
|
||||
echo ""
|
||||
echo "=== all listnode_lookup in ospf_ti_lfa ==="
|
||||
grep -n "listnode_lookup" frr/ospfd/ospf_ti_lfa.c
|
||||
|
||||
echo ""
|
||||
echo "=== bgpd/bgp_aspath.c loop detection ==="
|
||||
grep -n "aspath_loop\|loop_check\|as_in\|own_as\|my_as\|confed" frr/bgpd/bgp_aspath.c | head -20
|
||||
|
||||
echo ""
|
||||
echo "=== bgp aspath loop check implementation ==="
|
||||
grep -n "aspath_loop_check\|aspath_private_as_check" frr/bgpd/bgp_aspath.c | head -5
|
||||
25
tools/scans/frrouting.sh
Executable file
25
tools/scans/frrouting.sh
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — FRRouting (ospfd, bgpd, isisd, ldpd)
|
||||
# Network mode: semitrusted (requires git clone)
|
||||
set -euo pipefail
|
||||
echo "# scan=frrouting host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
cd /tmp && git clone --depth 1 https://github.com/FRRouting/frr frr 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="shortest.path|dijkstra|spf\b|scc\b|topolog|cycle|reachab|path.find|dfs\b|bfs\b|strongly.connected"
|
||||
C_MEM="listnode_lookup|list_lookup|listnode_add_sort|list_search|for.*->next.*->next|linear_search|aspath_loop_check|as_in_path|contain.*asn"
|
||||
|
||||
for daemon in ospfd bgpd isisd ldpd; do
|
||||
[ -d /tmp/frr/$daemon ] || continue
|
||||
echo "# roots: /tmp/frr/$daemon"
|
||||
find /tmp/frr/$daemon -name "*.c" -o -name "*.h" | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
39
tools/scans/gnu-octave.sh
Executable file
39
tools/scans/gnu-octave.sh
Executable file
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — GNU Octave (graph toolbox, sparse, dep resolver)
|
||||
set -euo pipefail
|
||||
echo "# scan=gnu-octave host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://github.com/gnu-octave/octave octave 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="topolog|cycle|dfs\b|scc\b|strongly.connected|reachab|tarjan|graph|shortest.path|spanning"
|
||||
C_MEM='std::find[(]|\.count[(].*==|find.*begin.*end|linear_search|vector.*find|std::list.*find'
|
||||
M_MEM='ismember\b|find(.*==.*)\b|any(.*==.*)\b'
|
||||
|
||||
# C++ sources
|
||||
for dir in liboctave/util liboctave/array scripts/graph; do
|
||||
[ -d /tmp/octave/$dir ] || continue
|
||||
echo "# roots: /tmp/octave/$dir"
|
||||
find /tmp/octave/$dir -name "*.cc" -o -name "*.h" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
done
|
||||
|
||||
# .m scripts
|
||||
for dir in scripts scripts/graph; do
|
||||
[ -d /tmp/octave/$dir ] || continue
|
||||
find /tmp/octave/$dir -name "*.m" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$M_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
23
tools/scans/kicad.sh
Executable file
23
tools/scans/kicad.sh
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — KiCad EDA (netlist, ratsnest, DRC connectivity graph)
|
||||
set -euo pipefail
|
||||
echo "# scan=kicad host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://gitlab.com/kicad/code/kicad kicad 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="topolog|cycle|dfs\b|scc\b|strongly.connected|reachab|ratsnest|connectivity|netlist|graph"
|
||||
C_MEM='std::find[(]|\.count[(].*==|find.*begin.*end|linear_search|vector.*find|std::list.*find|SEARCH_RESULT'
|
||||
|
||||
for dir in pcbnew/connectivity eeschema/netlist_exporters common; do
|
||||
[ -d /tmp/kicad/$dir ] || continue
|
||||
echo "# roots: /tmp/kicad/$dir"
|
||||
find /tmp/kicad/$dir -name "*.cpp" -o -name "*.h" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
20
tools/scans/memcached.sh
Executable file
20
tools/scans/memcached.sh
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — Memcached (connection/item graph, consistent hash ring)
|
||||
set -euo pipefail
|
||||
echo "# scan=memcached host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://github.com/memcached/memcached memcached 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="topolog|cycle|graph|reachab|consistent.hash|ring|node.*next|chain|slab.*chain"
|
||||
C_MEM='linear_search|find_item_locked|item_get_locked|STAILQ_FOREACH.*==|TAILQ_FOREACH.*==|for.*->next.*==.*->next'
|
||||
|
||||
echo "# roots: /tmp/memcached"
|
||||
find /tmp/memcached -name "*.c" -o -name "*.h" 2>/dev/null | grep -v t/ | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
echo "# scan complete"
|
||||
23
tools/scans/mysql.sh
Executable file
23
tools/scans/mysql.sh
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — MySQL Server (optimizer, graph, dependency resolution)
|
||||
set -euo pipefail
|
||||
echo "# scan=mysql host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://github.com/mysql/mysql-server mysql 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="topolog|cycle|dfs\b|scc\b|strongly.connected|reachab|dependency|graph|tarjan|postorder"
|
||||
C_MEM='std::find[(]|\.count[(]|list_search|find.*begin.*end|linear_search|List_iterator.*find|std::list.*find'
|
||||
|
||||
for dir in sql storage/innobase; do
|
||||
[ -d /tmp/mysql/$dir ] || continue
|
||||
echo "# roots: /tmp/mysql/$dir"
|
||||
find /tmp/mysql/$dir -name "*.cc" -o -name "*.h" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
22
tools/scans/networkx.sh
Executable file
22
tools/scans/networkx.sh
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — NetworkX (Python graph library)
|
||||
# Network mode: semitrusted
|
||||
set -euo pipefail
|
||||
echo "# scan=networkx host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
cd /tmp && git clone --depth 1 https://github.com/networkx/networkx networkx 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="tarjan|strongly.connected|dfs\b|scc\b|topolog|cycle|reachab|postorder|dominator|digraph|shortest.path"
|
||||
PY_MEM="[^a-z]in (path|stack|visited|seen|queue|ancestors)\b|not in (path|stack|visited)\b|path\.index\b|stack\.index\b"
|
||||
|
||||
echo "# roots: /tmp/networkx/networkx/algorithms"
|
||||
find /tmp/networkx/networkx/algorithms -name "*.py" | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$PY_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
echo "# scan complete"
|
||||
20
tools/scans/nginx.sh
Executable file
20
tools/scans/nginx.sh
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — nginx (resolver CNAME chains, upstream graph)
|
||||
set -euo pipefail
|
||||
echo "# scan=nginx host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://github.com/nginx/nginx nginx 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="cycle\b|reachab\|topolog\|cname.*chain\|chain.*cname\|upstream.*graph\|dependency\|dfs\b\|visited"
|
||||
C_MEM='ngx_array_push.*==\|for.*elts\|ngx_str_set.*find\|linear\|ngx_list_push.*==\b'
|
||||
|
||||
echo "# roots: /tmp/nginx/src"
|
||||
find /tmp/nginx/src -name "*.c" -o -name "*.h" | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
echo "# scan complete"
|
||||
25
tools/scans/onos.sh
Executable file
25
tools/scans/onos.sh
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — ONOS SDN Controller (topology, routing, link graph)
|
||||
set -euo pipefail
|
||||
echo "# scan=onos host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://github.com/opennetworkinglab/onos onos 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="topolog|cycle|dfs\b|scc\b|strongly.connected|reachab|dijkstra|shortest.path|spanning.tree|tarjan"
|
||||
JAVA_MEM='ArrayList.*contains|List.*contains|\.indexOf[(]|LinkedList.*contains|new ArrayList.*visited|new ArrayList.*stack|List<.*>.*stack'
|
||||
|
||||
for dir in core/api/src/main/java/org/onosproject/net \
|
||||
core/net/src/main/java/org/onosproject/net \
|
||||
apps/routing; do
|
||||
[ -d /tmp/onos/$dir ] || continue
|
||||
echo "# roots: /tmp/onos/$dir"
|
||||
find /tmp/onos/$dir -name "*.java" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$JAVA_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
24
tools/scans/opendaylight.sh
Executable file
24
tools/scans/opendaylight.sh
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — OpenDaylight MD-SAL (topology, graph, dependency)
|
||||
set -euo pipefail
|
||||
echo "# scan=opendaylight host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://github.com/opendaylight/mdsal mdsal 2>&1 | tail -1
|
||||
cd /tmp && git clone --depth 1 https://github.com/opendaylight/bgpcep bgpcep 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="topolog|cycle|dfs\b|scc\b|strongly.connected|reachab|dijkstra|shortest.path|tarjan|graph"
|
||||
JAVA_MEM='ArrayList.*contains|List.*contains|\.indexOf[(]|LinkedList.*contains|new ArrayList.*visited|new ArrayList.*stack|List<.*>.*stack'
|
||||
|
||||
for repo in mdsal bgpcep; do
|
||||
[ -d /tmp/$repo ] || continue
|
||||
echo "# roots: /tmp/$repo"
|
||||
find /tmp/$repo -name "*.java" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$JAVA_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
22
tools/scans/php-zend.sh
Executable file
22
tools/scans/php-zend.sh
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — PHP Zend Engine (CFG, DFG, SSA, OPcache optimizer)
|
||||
set -euo pipefail
|
||||
echo "# scan=php-zend host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://github.com/php/php-src php-src 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="cfg\b|dfg\b|ssa\b|dominator|liveness|reachab|topolog|cycle|dfs\b|scc\b|postorder|strongly.connected|basic.block|dataflow"
|
||||
C_MEM='std::find[(]|linear_search|zend_bitset_in\b|in_list\b|zend_llist_.*find|ZEND_HASH_FOREACH.*==|zend_linked_list'
|
||||
|
||||
for dir in Zend "ext/opcache/Optimizer"; do
|
||||
echo "# roots: /tmp/php-src/$dir"
|
||||
find /tmp/php-src/$dir -name "*.c" -o -name "*.h" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
41
tools/scans/postgresql.sh
Executable file
41
tools/scans/postgresql.sh
Executable file
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — PostgreSQL query planner and executor
|
||||
# PostgreSQL uses its own list API: list_member(), foreach()/lfirst(), lappend()
|
||||
# Strategy: lead with pg-specific O(n) membership calls, check ±20 lines for loop context.
|
||||
set -euo pipefail
|
||||
echo "# scan=postgresql host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
cd /tmp && git clone --depth 1 https://github.com/postgres/postgres postgres 2>&1 | tail -1
|
||||
|
||||
# O(n) membership patterns in PostgreSQL's list API
|
||||
PG_MEM='list_member\b|list_member_ptr\b|list_member_int\b|list_member_oid\b|list_member_xid\b'
|
||||
|
||||
# Loop constructs that would make the above O(n²)
|
||||
PG_LOOP='foreach\b|for\s*\(.*List\|while\s*\(.*List\|do\s*{.*List'
|
||||
|
||||
for dir in \
|
||||
src/backend/optimizer \
|
||||
src/backend/nodes \
|
||||
src/backend/rewrite \
|
||||
src/backend/executor \
|
||||
src/backend/parser \
|
||||
src/backend/planner; do
|
||||
[ -d /tmp/postgres/$dir ] || continue
|
||||
echo "# roots: /tmp/postgres/$dir"
|
||||
find /tmp/postgres/$dir -name "*.c" -o -name "*.h" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
# Find all list_member* call sites
|
||||
ml=$(grep -nE "$PG_MEM" "$f" 2>/dev/null | cut -d: -f1 || true)
|
||||
[ -z "$ml" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
ctx=$(sed -n "${s},${e}p" "$f" 2>/dev/null || true)
|
||||
# Emit candidate if a loop construct appears in the same ±20-line window
|
||||
loop_hit=$(echo "$ctx" | grep -iE "$PG_LOOP" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$loop_hit" ] && {
|
||||
mem_line=$(sed -n "${ln}p" "$f" | sed 's/^\s*//')
|
||||
echo "CANDIDATE ${f}:${ln} ${mem_line} [loop: ${loop_hit}]"
|
||||
}
|
||||
done <<< "$ml"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
20
tools/scans/redis.sh
Executable file
20
tools/scans/redis.sh
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — Redis (cluster topology, module graph)
|
||||
set -euo pipefail
|
||||
echo "# scan=redis host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://github.com/redis/redis redis 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="topolog|reachab|cluster.*path|path.*cluster|cycle|dfs\b|scc\b|strongly.connected|dependency|failover|slot.*migrat"
|
||||
C_MEM='listSearchKey\|listNodeValue\|listIndex\|listRotate\|for.*next\b.*->next\b|linear.*search\|listTypeGet'
|
||||
|
||||
echo "# roots: /tmp/redis/src"
|
||||
find /tmp/redis/src -name "*.c" -o -name "*.h" | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
echo "# scan complete"
|
||||
39
tools/scans/sbt.sh
Executable file
39
tools/scans/sbt.sh
Executable file
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — sbt (Scala Build Tool)
|
||||
# Scala/Java build tool; uses Ivy for dep resolution and has its own DAG execution
|
||||
# Strategy: Scala/Java membership patterns in graph/dep/task context
|
||||
set -euo pipefail
|
||||
echo "# scan=sbt host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
cd /tmp && git clone --depth 1 https://github.com/sbt/sbt sbt 2>&1 | tail -1
|
||||
|
||||
# O(n) membership patterns — Scala and Java
|
||||
SCALA_MEM='\.contains\s*\(|\.indexOf\s*\(|\.find\s*\(_\s*==|\.exists\s*\(_\s*==|\bcontains\b'
|
||||
|
||||
# Loop/traversal constructs
|
||||
SCALA_LOOP='for\s*\(|\.foreach\s*\(|\.foldLeft\s*\(|\.map\s*\(|while\s*\(|\.flatMap\s*\('
|
||||
|
||||
for dir in \
|
||||
main/src/main/scala \
|
||||
compile/src/main/scala \
|
||||
tasks/src/main/scala \
|
||||
librarymanagement; do
|
||||
[ -d /tmp/sbt/$dir ] || continue
|
||||
echo "# roots: /tmp/sbt/$dir"
|
||||
find /tmp/sbt/$dir -name "*.scala" -o -name "*.java" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
ml=$(grep -nE "$SCALA_MEM" "$f" 2>/dev/null | cut -d: -f1 || true)
|
||||
[ -z "$ml" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
ctx=$(sed -n "${s},${e}p" "$f" 2>/dev/null || true)
|
||||
graph_hit=$(echo "$ctx" | grep -iE 'graph|depend|topo|visit|cycle|dag|sort|stack|order|reachab|ancestor|transit|scc|task' | head -1 | sed 's/^\s*//' || true)
|
||||
[ -z "$graph_hit" ] && continue
|
||||
loop_hit=$(echo "$ctx" | grep -iE "$SCALA_LOOP" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$loop_hit" ] && {
|
||||
mem_line=$(sed -n "${ln}p" "$f" | sed 's/^\s*//')
|
||||
echo "CANDIDATE\t${f}:${ln}\t${mem_line} [loop: ${loop_hit}]"
|
||||
}
|
||||
done <<< "$ml"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
28
tools/scans/spidermonkey.sh
Executable file
28
tools/scans/spidermonkey.sh
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — SpiderMonkey JS engine (IonMonkey compiler, CFG, SCC)
|
||||
set -euo pipefail
|
||||
echo "# scan=spidermonkey host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
# Sparse clone of gecko-dev — only js/src
|
||||
cd /tmp
|
||||
git clone --depth 1 --filter=blob:none --sparse \
|
||||
https://github.com/mozilla/gecko-dev geckosrc 2>&1 | tail -1
|
||||
cd geckosrc
|
||||
git sparse-checkout set js/src 2>&1 | tail -1
|
||||
SMROOT=/tmp/geckosrc/js/src
|
||||
|
||||
GRAPH_KW="topolog|scc\b|strongly.connected|cycle|dfs\b|postorder|dominator|liveness|reachab|tarjan|register.alloc|ion\b"
|
||||
C_MEM='std::find[(]|\.Contains[(]|IsInVector\b|vector.*find\b|linear_search|Vector.*Contains|NodeVector.*find'
|
||||
|
||||
[ -d "$SMROOT" ] || { echo "# ERROR: SpiderMonkey source not found"; exit 0; }
|
||||
echo "# roots: $SMROOT"
|
||||
find "$SMROOT" -name "*.cpp" -o -name "*.h" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
echo "# scan complete"
|
||||
58
tools/scans/sqlite.sh
Executable file
58
tools/scans/sqlite.sh
Executable file
|
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — SQLite query planner and optimizer
|
||||
# SQLite uses array-backed list types: ExprList, SrcList, IdList
|
||||
# Membership via linear loops: for(i=0; i<pList->n; i++) + equality
|
||||
# Strategy: lead with known O(n) scan patterns, check ±20 lines for outer loop.
|
||||
set -euo pipefail
|
||||
echo "# scan=sqlite host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
cd /tmp && git clone --depth 1 https://github.com/sqlite/sqlite sqlite 2>&1 | tail -1
|
||||
|
||||
# O(n) membership patterns: linear scans over SQLite list types
|
||||
# - sqlite3ExprListFind: linear scan returning index
|
||||
# - loops over nExpr/nSrc/nId with equality/comparison inside
|
||||
SQ_MEM='sqlite3ExprListFind\b|sqlite3IdListIndex\b|for\s*\(.*->nExpr\b|for\s*\(.*->nSrc\b|for\s*\(.*->nId\b|while\s*\(.*->nExpr\b'
|
||||
|
||||
# Outer loop constructs that would make the above O(n²)
|
||||
# Include both for-loop over list fields and recursive traversal
|
||||
SQ_LOOP='for\s*\(.*pList\|for\s*\(.*pExpr\|for\s*\(.*pSrc\|for\s*\(.*->a\[|while\s*\(.*->a\[|sqlite3WalkExprList\b|sqlite3WalkSelectExpr\b'
|
||||
|
||||
for dir in \
|
||||
src \
|
||||
tool; do
|
||||
[ -d /tmp/sqlite/$dir ] || continue
|
||||
echo "# roots: /tmp/sqlite/$dir"
|
||||
find /tmp/sqlite/$dir -name "*.c" -o -name "*.h" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
ml=$(grep -nE "$SQ_MEM" "$f" 2>/dev/null | cut -d: -f1 || true)
|
||||
[ -z "$ml" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
ctx=$(sed -n "${s},${e}p" "$f" 2>/dev/null || true)
|
||||
loop_hit=$(echo "$ctx" | grep -iE "$SQ_LOOP" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$loop_hit" ] && {
|
||||
mem_line=$(sed -n "${ln}p" "$f" | sed 's/^\s*//')
|
||||
echo "CANDIDATE\t${f}:${ln}\t${mem_line} [loop: ${loop_hit}]"
|
||||
}
|
||||
done <<< "$ml"
|
||||
done
|
||||
done
|
||||
|
||||
# Also scan the amalgamation for patterns missed in src/
|
||||
# (some logic only exists in sqlite3.c after preprocessing)
|
||||
echo "# roots: /tmp/sqlite/sqlite3.c (amalgamation)"
|
||||
f=/tmp/sqlite/sqlite3.c
|
||||
if [ -f "$f" ]; then
|
||||
ml=$(grep -nE "$SQ_MEM" "$f" 2>/dev/null | cut -d: -f1 || true)
|
||||
while IFS= read -r ln; do
|
||||
[ -z "$ln" ] && continue
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
ctx=$(sed -n "${s},${e}p" "$f" 2>/dev/null || true)
|
||||
loop_hit=$(echo "$ctx" | grep -iE "$SQ_LOOP" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$loop_hit" ] && {
|
||||
mem_line=$(sed -n "${ln}p" "$f" | sed 's/^\s*//')
|
||||
echo "CANDIDATE\t${f}:${ln}\t${mem_line} [loop: ${loop_hit}]"
|
||||
}
|
||||
done <<< "$ml"
|
||||
fi
|
||||
|
||||
echo "# scan complete"
|
||||
17
tools/scans/triage-exabgp.sh
Executable file
17
tools/scans/triage-exabgp.sh
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd /tmp && git clone --depth 1 https://github.com/Exa-Networks/exabgp exabgp 2>/dev/null
|
||||
|
||||
echo "=== peer.py seen type ==="
|
||||
grep -n "seen\s*=" exabgp/src/exabgp/reactor/api/command/peer.py | head -5
|
||||
sed -n '95,110p' exabgp/src/exabgp/reactor/api/command/peer.py
|
||||
|
||||
echo "=== rib/cache.py index context ==="
|
||||
sed -n '10,35p' exabgp/src/exabgp/rib/cache.py
|
||||
|
||||
echo "=== AS-path loop detection ==="
|
||||
find exabgp/src -name "*.py" | xargs grep -l "loop\|as_path\|aspath" 2>/dev/null | head -5
|
||||
grep -rn "in self\.\|in path\|in visited\|in seen" exabgp/src/exabgp/bgp/ 2>/dev/null | grep -v "\.pyc" | head -15
|
||||
|
||||
echo "=== frr ti_lfa context ==="
|
||||
echo "needs separate submission"
|
||||
16
tools/scans/triage-verilator.sh
Executable file
16
tools/scans/triage-verilator.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd /tmp && git clone --depth 1 https://github.com/verilator/verilator verilator 2>/dev/null
|
||||
|
||||
echo "=== V3ExecGraph.cpp:945-965 — schedule.contains type ==="
|
||||
grep -n "schedule\b" verilator/src/V3ExecGraph.cpp | grep -v "//" | head -10
|
||||
sed -n '945,970p' verilator/src/V3ExecGraph.cpp
|
||||
|
||||
echo ""
|
||||
echo "=== V3Gate.cpp:710-730 — readVscps type ==="
|
||||
grep -n "readVscps\s*[;=]" verilator/src/V3Gate.cpp | head -5
|
||||
sed -n '710,735p' verilator/src/V3Gate.cpp
|
||||
|
||||
echo ""
|
||||
echo "=== V3GraphAlg.cpp — SCC implementation type check ==="
|
||||
grep -n "m_onStack\|m_visited\|m_seen\|pool<\|unordered_set\|std::set" verilator/src/V3GraphAlg.cpp 2>/dev/null | head -15
|
||||
15
tools/scans/triage-verilator2.sh
Executable file
15
tools/scans/triage-verilator2.sh
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd /tmp && git clone --depth 1 https://github.com/verilator/verilator verilator 2>/dev/null
|
||||
|
||||
echo "=== ThreadSchedule::contains implementation ==="
|
||||
grep -n "bool contains\|contains.*mtask\|contains.*ExecMTask" verilator/src/V3ExecGraph.cpp | head -10
|
||||
grep -n "struct ThreadSchedule\|class ThreadSchedule" verilator/src/V3ExecGraph.cpp | head -5
|
||||
|
||||
echo ""
|
||||
echo "=== ThreadSchedule struct ==="
|
||||
awk '/struct ThreadSchedule|class ThreadSchedule/{found=1} found{print NR": "$0} /^};/{if(found){found=0}}' verilator/src/V3ExecGraph.cpp | head -40
|
||||
|
||||
echo ""
|
||||
echo "=== V3Gate.cpp readVscps local type at line 722 ==="
|
||||
sed -n '695,730p' verilator/src/V3Gate.cpp
|
||||
5
tools/scans/triage-verilator3.sh
Executable file
5
tools/scans/triage-verilator3.sh
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd /tmp && git clone --depth 1 https://github.com/verilator/verilator verilator 2>/dev/null
|
||||
echo "=== V3Gate.cpp:695-735 ==="
|
||||
sed -n '695,735p' verilator/src/V3Gate.cpp
|
||||
18
tools/scans/triage-yosys.sh
Executable file
18
tools/scans/triage-yosys.sh
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd /tmp && git clone --depth 1 https://github.com/YosysHQ/yosys yosys 2>/dev/null
|
||||
|
||||
echo "=== scc.cc workQueue and cellLabels types ==="
|
||||
grep -n "workQueue\|cellLabels" yosys/passes/cmds/scc.cc | head -20
|
||||
|
||||
echo ""
|
||||
echo "=== scc.cc:40-100 ==="
|
||||
sed -n '40,100p' yosys/passes/cmds/scc.cc
|
||||
|
||||
echo ""
|
||||
echo "=== glift.cc:330-355 — ports vector + std::find context ==="
|
||||
sed -n '330,355p' yosys/passes/cmds/glift.cc
|
||||
|
||||
echo ""
|
||||
echo "=== does Yosys use pool<> (hash) vs std::set (tree)? ==="
|
||||
grep -n "pool<\|dict<\|std::set<\|std::map<\|std::unordered" yosys/passes/cmds/scc.cc | head -10
|
||||
23
tools/scans/v8.sh
Executable file
23
tools/scans/v8.sh
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — V8 JavaScript engine (compiler, CFG, register allocator)
|
||||
set -euo pipefail
|
||||
echo "# scan=v8 host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://chromium.googlesource.com/v8/v8 v8 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="topolog|scc\b|strongly.connected|cycle|dfs\b|postorder|dominator|liveness|reachab|tarjan|register.alloc|graph"
|
||||
C_MEM='std::find[(]|\.Contains[(]|IsInSet\b|vector.*find\b|linear_search|ZoneVector.*Contains|NodeVector.*find|std::count[(]'
|
||||
|
||||
for dir in src/compiler src/codegen src/interpreter; do
|
||||
[ -d /tmp/v8/$dir ] || continue
|
||||
echo "# roots: /tmp/v8/$dir"
|
||||
find /tmp/v8/$dir -name "*.cc" -o -name "*.h" 2>/dev/null | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
23
tools/scans/varnish.sh
Executable file
23
tools/scans/varnish.sh
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — Varnish Cache (VCL compiler, backend graph)
|
||||
set -euo pipefail
|
||||
echo "# scan=varnish host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
cd /tmp && git clone --depth 1 https://github.com/varnishcache/varnish-cache varnish 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="topolog|cycle|reachab|dfs\b|scc\b|dominator|postorder|dependency|vcl.*graph|graph.*vcl"
|
||||
C_MEM='VTAILQ_FOREACH.*==\|VSB_.*find\|for.*next.*next\b\|linear.*search\|vcc_.*find'
|
||||
|
||||
for dir in lib/libvcc bin/varnishd; do
|
||||
[ -d /tmp/varnish/$dir ] || continue
|
||||
echo "# roots: /tmp/varnish/$dir"
|
||||
find /tmp/varnish/$dir -name "*.c" -o -name "*.h" | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$C_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
done
|
||||
echo "# scan complete"
|
||||
22
tools/scans/verilator.sh
Executable file
22
tools/scans/verilator.sh
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — Verilator (RTL hardware simulator, V3Graph)
|
||||
# Network mode: semitrusted
|
||||
set -euo pipefail
|
||||
echo "# scan=verilator host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
cd /tmp && git clone --depth 1 https://github.com/verilator/verilator verilator 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="scc\b|tarjan|topolog|dfs\b|cycle|dominator|reachab|strongly.connected|liveness|postorder"
|
||||
CPP_MEM='std::find[(]|[.]count[(]|find.*begin.*end|is_contained|linear_search|\.contains[(]'
|
||||
|
||||
echo "# roots: /tmp/verilator/src"
|
||||
find /tmp/verilator/src -name "*.cpp" -o -name "*.h" | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$CPP_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
echo "# scan complete"
|
||||
22
tools/scans/yosys.sh
Executable file
22
tools/scans/yosys.sh
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env bash
|
||||
# CWE-407 scan — Yosys (open-source synthesis)
|
||||
# Network mode: semitrusted
|
||||
set -euo pipefail
|
||||
echo "# scan=yosys host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
cd /tmp && git clone --depth 1 https://github.com/YosysHQ/yosys yosys 2>&1 | tail -1
|
||||
|
||||
GRAPH_KW="scc\b|tarjan|topolog|dfs\b|cycle|dominator|reachab|strongly.connected|liveness|postorder"
|
||||
CPP_MEM='std::find[(]|[.]count[(]|find.*begin.*end|is_contained|linear_search|\.contains[(]'
|
||||
|
||||
echo "# roots: /tmp/yosys/kernel /tmp/yosys/passes"
|
||||
find /tmp/yosys/kernel /tmp/yosys/passes -name "*.cc" -o -name "*.h" | sort | while IFS= read -r f; do
|
||||
gl=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
||||
[ -z "$gl" ] && continue
|
||||
while IFS= read -r ln; do
|
||||
s=$(( ln > 20 ? ln - 20 : 1 )); e=$(( ln + 20 ))
|
||||
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$CPP_MEM" | head -1 | sed 's/^\s*//' || true)
|
||||
[ -n "$hit" ] && echo "CANDIDATE ${f}:${ln} ${hit}"
|
||||
done <<< "$gl"
|
||||
done
|
||||
echo "# scan complete"
|
||||
62
tools/tickets/defects/buildkit-0001.md
Normal file
62
tools/tickets/defects/buildkit-0001.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
id: buildkit-0001
|
||||
repo: moby/buildkit
|
||||
file: cache/remotecache/v1/cachestorage.go
|
||||
line: 244
|
||||
status: unpatched
|
||||
severity: MEDIUM
|
||||
complexity: O(K × L) — K cache keys imported, L links per key
|
||||
pattern: slices.Contains on []string links slice in HasLink(); in-memory backend uses map[string]struct{} (O(1)) but v1 disk importer uses []string (O(n))
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`cacheKeyStorage.HasLink()` in the v1 remote cache importer checks link existence with:
|
||||
|
||||
```go
|
||||
if slices.Contains(it.links[l], target) { // O(|links|)
|
||||
```
|
||||
|
||||
`it.links` is `map[nlink][]string` — links stored as string slices. The in-memory backend
|
||||
(`memorycachestorage.go:233`) correctly uses `map[string]struct{}` for O(1) lookup. The two
|
||||
backends are inconsistent.
|
||||
|
||||
## Call context
|
||||
|
||||
`HasLink` is called from `cachemanager.go:397` inside a loop over all cache keys for a result.
|
||||
For each key, it checks each link before adding it. For a remote cache import with K cache
|
||||
entries each having L links, the total cost is O(K × L) comparisons. For a large monorepo
|
||||
build with hundreds of cached layers, this is measurable.
|
||||
|
||||
## Activation
|
||||
|
||||
`docker buildx build --cache-from=registry://...` — the v1 remote cache import path. Every
|
||||
`--cache-from` invocation with a registry cache hits this code.
|
||||
|
||||
## Fix
|
||||
|
||||
Change `map[nlink][]string` to `map[nlink]map[string]struct{}` in `itemWithOutgoingLinks`,
|
||||
matching the in-memory backend exactly:
|
||||
|
||||
```go
|
||||
// Before
|
||||
type itemWithOutgoingLinks struct {
|
||||
item *item
|
||||
links map[nlink][]string
|
||||
}
|
||||
|
||||
// After
|
||||
type itemWithOutgoingLinks struct {
|
||||
item *item
|
||||
links map[nlink]map[string]struct{}
|
||||
}
|
||||
```
|
||||
|
||||
Update `addItemToStorage` to use `links[cl][id] = struct{}{}` instead of `append`, and
|
||||
`HasLink` to use `_, ok := it.links[l][target]` instead of `slices.Contains`.
|
||||
|
||||
## Work items
|
||||
|
||||
- [ ] patch
|
||||
- [ ] unit test (operation count: HasLink calls before/after on cache with L=100 links)
|
||||
- [ ] integration test (docker buildx build --cache-from with large registry cache)
|
||||
34
tools/tickets/defects/cargo-0001.md
Normal file
34
tools/tickets/defects/cargo-0001.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
id: cargo-0001
|
||||
repo: cargo
|
||||
severity: MEDIUM
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
patched: 2026-03-23
|
||||
patch: defects/cargo/patch/cargo-0001-print-stack-hashset.patch
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `src/cargo/ops/tree/mod.rs:343`
|
||||
**Pattern:** `Vec::contains` in `cargo tree` display output
|
||||
**Complexity:** `O(n) per node (display only)`
|
||||
**Language:** Rust
|
||||
|
||||
## Description
|
||||
|
||||
The `cargo tree` command tracks which packages have already been displayed using `Vec::contains` to avoid duplicate output. Each call scans the entire vector of previously-displayed packages linearly. While this is display-only code and does not affect build correctness, for large dependency trees the O(n) per-node check makes `cargo tree` noticeably slow, with total display cost growing as O(n²) in the number of packages.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `displayed.contains(&pkg_id)`
|
||||
**With:** `displayed_set.contains(&pkg_id)`
|
||||
**Data structure change:** `displayed: Vec<PackageId> → displayed_set: HashSet<PackageId>`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/cargo/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/cargo/unit/`)
|
||||
- [ ] Integration test (in `defects/cargo/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/cargo/bench/`)
|
||||
- [ ] White paper section
|
||||
34
tools/tickets/defects/cmake-0001.md
Normal file
34
tools/tickets/defects/cmake-0001.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
id: cmake-0001
|
||||
repo: cmake
|
||||
severity: HIGH
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
patched: 2026-03-23
|
||||
patch: defects/cmake/patch/cmake-0001-groupitems-unordered-set.patch
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `Source/cmComputeLinkDepends.cxx:1167,521,1363`
|
||||
**Pattern:** `std::find` on group vectors in link dependency computation
|
||||
**Complexity:** `O(n) per edge`
|
||||
**Language:** C++
|
||||
|
||||
## Description
|
||||
|
||||
CMake's link dependency computation uses `std::find` on `std::vector` to check membership in link groups at three separate call sites. Each `std::find` call scans the entire vector linearly to determine if an item is already present. During link dependency resolution for large projects, these checks are performed for every edge in the dependency graph, contributing O(n) cost per edge and O(n²) total across all edges.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `std::find(group.begin(), group.end(), item) != group.end()`
|
||||
**With:** `groupSet.count(item) > 0`
|
||||
**Data structure change:** `std::vector<T> group → std::unordered_set<T> groupSet`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/cmake/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/cmake/unit/`)
|
||||
- [ ] Integration test (in `defects/cmake/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/cmake/bench/`)
|
||||
- [ ] White paper section
|
||||
62
tools/tickets/defects/composer-0001.md
Normal file
62
tools/tickets/defects/composer-0001.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
id: composer-0001
|
||||
repo: composer/composer
|
||||
severity: MEDIUM
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `src/Composer/Repository/RepositoryUtils.php:46`
|
||||
**Pattern:** `!in_array($candidate, $bucket, true)` inside `foreach ($packages as $candidate)`
|
||||
**Complexity:** O(N²) per call + O(N³) with recursive transitive closure
|
||||
**Language:** PHP
|
||||
|
||||
## Description
|
||||
|
||||
`filterRequiredPackages()` computes the set of packages from `$packages` that are
|
||||
transitively required by `$requirer`. It does this by iterating over all candidates
|
||||
in an outer `foreach ($packages as $candidate)` loop and checking `!in_array($candidate, $bucket, true)`
|
||||
to avoid re-adding packages already in the result set.
|
||||
|
||||
`$bucket` is a PHP array (not a Set or hash map). `in_array()` on a PHP array is O(n)
|
||||
linear scan. As packages are found they are appended to `$bucket` with `$bucket[]`,
|
||||
so `$bucket` grows from 0 to N. The total cost of all membership checks in a single
|
||||
call is O(N²) in the number of installed packages.
|
||||
|
||||
The function is also called **recursively** for each transitive dependency:
|
||||
`$bucket = self::filterRequiredPackages($packages, $candidate, false, $bucket)`.
|
||||
In the worst case (long dependency chain), the total complexity is O(N³) where N
|
||||
is the package count.
|
||||
|
||||
Triggered by: `composer show`, `composer why`, `composer depends`, and any
|
||||
Composer command that computes transitive package sets for display. Not in the
|
||||
SAT/CDCL installation solver.
|
||||
|
||||
For a project with 200 packages (typical Symfony or Laravel application):
|
||||
O(200²) = 40,000 membership comparisons per `composer why` invocation.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `$bucket` as PHP array with membership via `in_array()`
|
||||
**With:** `$bucket` as PHP associative array (hash map) keyed on package name/identity;
|
||||
or use `SplObjectStorage` for object-identity lookup in O(1).
|
||||
|
||||
```php
|
||||
// Before
|
||||
if (!in_array($candidate, $bucket, true)) {
|
||||
$bucket[] = $candidate;
|
||||
// After
|
||||
if (!isset($bucketMap[spl_object_id($candidate)])) {
|
||||
$bucketMap[spl_object_id($candidate)] = true;
|
||||
$bucket[] = $candidate;
|
||||
```
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/composer/patch/`
|
||||
- [ ] Unit test — asserts operation counts before/after at N=50,100,200 packages (in `defects/composer/unit/`)
|
||||
- [ ] Integration test — `composer why` on project with N transitive deps (in `defects/composer/integration/`)
|
||||
- [ ] Benchmark — timing before/after (in `defects/composer/bench/`)
|
||||
- [ ] White paper section — `whitepaper/vectors/tool-harness/composer.rst`
|
||||
57
tools/tickets/defects/composer-0002.md
Normal file
57
tools/tickets/defects/composer-0002.md
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
id: composer-0002
|
||||
repo: composer/composer
|
||||
severity: MEDIUM
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `src/Composer/Repository/InstalledRepository.php:128,154,167,180`
|
||||
**Pattern:** `in_array($link->getTarget(), $packagesInTree)` / `in_array($link->getSource(), $packagesInTree)` inside nested foreach loops
|
||||
**Complexity:** O(|packages| × |links| × |packagesInTree|) per `getDependents()` call
|
||||
**Language:** PHP
|
||||
|
||||
## Description
|
||||
|
||||
`InstalledRepository::getDependents()` traverses the installed package dependency
|
||||
graph to find all packages that (directly or transitively) depend on a given package.
|
||||
It maintains `$packagesInTree` — an array that accumulates visited package names —
|
||||
and checks membership with `in_array()` (O(n) linear scan) before recursing.
|
||||
|
||||
The traversal has the following structure:
|
||||
```
|
||||
foreach ($this->getPackages() as $package) { // O(N) packages
|
||||
foreach ($links as $link) { // O(L) links per package
|
||||
foreach ($needles as $needle) { // O(K) needles
|
||||
if (in_array($source, $packagesInTree)) { // O(|tree|) — O(N) worst case
|
||||
```
|
||||
|
||||
In the worst case (deep dependency graph), this is O(N² × L × K) where N is
|
||||
installed package count, L is average links per package, K is the needle count.
|
||||
|
||||
`$packagesInTree` grows as packages are added: `$packagesInTree[] = $link->getSource()`.
|
||||
By the time N packages have been visited, each `in_array` call scans up to N entries.
|
||||
|
||||
This fires on `composer show --tree`, `composer why`, `composer depends --tree`, and
|
||||
the BSP server's dependency tree protocol response. For typical medium-size projects
|
||||
(100-200 packages), this produces 10,000–40,000 string comparisons per invocation.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `in_array($pkg, $packagesInTree)` array scan
|
||||
**With:** `$packagesInTreeSet[$pkg] = true` associative array; check `isset($packagesInTreeSet[$pkg])`
|
||||
|
||||
All four call sites (lines 128, 154, 167, 180) use the same `$packagesInTree` variable
|
||||
and can be fixed together in a single patch. The fix requires threading a `$packagesInTreeSet`
|
||||
hash alongside the existing `$packagesInTree` array (or replacing the array entirely with
|
||||
a keyed hash, using `array_values()` at the return boundary if caller expects a list).
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/composer/patch/`
|
||||
- [ ] Unit test — asserts operation counts before/after at N=50,100,200 packages (in `defects/composer/unit/`)
|
||||
- [ ] Integration test — `composer show --tree` on project with N transitive deps (in `defects/composer/integration/`)
|
||||
- [ ] Benchmark — timing before/after (in `defects/composer/bench/`)
|
||||
- [ ] White paper section — `whitepaper/vectors/tool-harness/composer.rst`
|
||||
32
tools/tickets/defects/cpython-0001.md
Normal file
32
tools/tickets/defects/cpython-0001.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
id: cpython-0001
|
||||
repo: cpython
|
||||
severity: HIGH
|
||||
status: patched
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `Tools/peg_generator/pegen/sccutils.py:73`
|
||||
**Pattern:** `node in path` where path is a list in DFS cycle detection
|
||||
**Complexity:** `O(V²)`
|
||||
**Language:** Python
|
||||
|
||||
## Description
|
||||
|
||||
The PEG generator's SCC utility performs DFS-based cycle detection and maintains the current DFS path as a Python list. At line 73, the check `node in path` tests whether a node has been visited on the current path, which requires scanning the entire list. Since this check is performed for every edge explored, and the path can be up to V nodes long, the algorithm degrades from O(V+E) to O(V²+VE).
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `node in path`
|
||||
**With:** `node in path_set`
|
||||
**Data structure change:** `path: list → path: list + path_set: set` (maintained in parallel)
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/cpython/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/cpython/unit/`)
|
||||
- [ ] Integration test (in `defects/cpython/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/cpython/bench/`)
|
||||
- [ ] White paper section
|
||||
85
tools/tickets/defects/create-0001.md
Normal file
85
tools/tickets/defects/create-0001.md
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
---
|
||||
id: create-0001
|
||||
repo: Creators-of-Create/Create
|
||||
file: src/main/java/com/simibubi/create/content/trains/graph/TrackGraph.java
|
||||
line: findDisconnectedGraphs method
|
||||
status: unpatched
|
||||
severity: MEDIUM
|
||||
complexity: O(V²) BFS — ArrayList.remove(0) is O(n) per iteration due to array shift
|
||||
pattern: ArrayList used as BFS queue; remove(0) shifts all elements left each iteration
|
||||
source: open source (GitHub), mc1.20.1/dev branch
|
||||
created: 2026-03-24
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `com/simibubi/create/content/trains/graph/TrackGraph.java`
|
||||
**Method:** `findDisconnectedGraphs()`
|
||||
**Pattern:** `ArrayList.remove(0)` in BFS frontier loop
|
||||
**Trigger:** Every time track is removed from a railroad network
|
||||
|
||||
## Description
|
||||
|
||||
`findDisconnectedGraphs()` detects whether removing a track segment splits the railroad
|
||||
network into disconnected components. It implements BFS using an `ArrayList` as the
|
||||
frontier queue:
|
||||
|
||||
```java
|
||||
List<TrackNodeLocation> frontier = new ArrayList<>();
|
||||
// ...
|
||||
while (!frontier.isEmpty()) {
|
||||
TrackNodeLocation current = frontier.remove(0); // O(n) — shifts all elements
|
||||
// ...
|
||||
frontier.add(connected.getLocation());
|
||||
}
|
||||
```
|
||||
|
||||
`ArrayList.remove(0)` is O(n) because Java arrays are contiguous — removing the first
|
||||
element requires shifting every remaining element one position left. For a BFS over a
|
||||
railroad graph with V nodes, each of the V iterations does an O(V) remove, yielding
|
||||
O(V²) total instead of O(V+E).
|
||||
|
||||
**Secondary inefficiency:** the outer loop picks the next unvisited start node with
|
||||
`vertices.stream().findFirst()` — O(V) per connected component, instead of O(1) with
|
||||
a pre-built iterator or queue seeded from unvisited nodes.
|
||||
|
||||
## Severity constraint
|
||||
|
||||
This fires only when **track topology changes** (player removes a track segment), not
|
||||
on every game tick. In small railroad networks the quadratic cost is unnoticeable. In
|
||||
large automated factory servers with extensive railroad infrastructure (common in Create
|
||||
megabuilds and ATM/Omnifactory modpacks), track removal can cause measurable lag spikes
|
||||
proportional to V² of the connected graph.
|
||||
|
||||
Create's train graph can span hundreds or thousands of nodes in active factory servers.
|
||||
At V=500, the difference is 500 operations (correct) vs 250,000 (actual). At V=2,000:
|
||||
2,000 vs 4,000,000.
|
||||
|
||||
## Fix
|
||||
|
||||
Replace `ArrayList` with `ArrayDeque` — a double-ended queue with O(1) amortized
|
||||
`addLast` and `removeFirst`:
|
||||
|
||||
```java
|
||||
// Before
|
||||
List<TrackNodeLocation> frontier = new ArrayList<>();
|
||||
TrackNodeLocation current = frontier.remove(0); // O(n)
|
||||
|
||||
// After
|
||||
Deque<TrackNodeLocation> frontier = new ArrayDeque<>();
|
||||
TrackNodeLocation current = frontier.removeFirst(); // O(1)
|
||||
```
|
||||
|
||||
No behavioral change. `ArrayDeque` implements `Deque` which is not a `List`, so the
|
||||
declaration type must change from `List<>` to `Deque<>` or `Queue<>`.
|
||||
|
||||
## Scan context
|
||||
|
||||
AE2 (`GridNode.java`) — CLEAN: uses `ArrayDeque` + object-identity visited counter (O(1))
|
||||
Mekanism (`TransmitterNetworkRegistry.java`) — CLEAN: uses `ObjectOpenHashSet` + `Deque`
|
||||
|
||||
## Work items
|
||||
|
||||
- [ ] Confirm against latest Create source (branch may have changed since mc1.20.1/dev)
|
||||
- [ ] Report to Creators-of-Create/Create GitHub issues
|
||||
- [ ] Note: trigger-bounded (track removal only), severity MEDIUM not HIGH
|
||||
32
tools/tickets/defects/debian-0001.md
Normal file
32
tools/tickets/defects/debian-0001.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
id: debian-0001
|
||||
repo: debian-perl-config
|
||||
severity: LOW
|
||||
status: NOT-WORTH-FIXING
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `DebianLinux.pm:140`
|
||||
**Pattern:** 6-item list membership in config parsing
|
||||
**Complexity:** `O(n)`
|
||||
**Language:** Perl
|
||||
|
||||
## Description
|
||||
|
||||
Debian's Perl configuration module checks membership in a hardcoded list of 6 architecture or platform names using a linear list search. Because the list is bounded at 6 elements, the effective complexity is O(1) in practice — the constant factor is negligible and the list never grows. This is a stylistic defect only; it follows the same CWE-407 pattern but poses no measurable performance risk given the fixed input size.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `grep { $_ eq $value } @six_item_list`
|
||||
**With:** `exists $six_item_hash{$value}`
|
||||
**Data structure change:** `@list: 6-element array → %hash: 6-element hash`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/debian/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/debian/unit/`)
|
||||
- [ ] Integration test (in `defects/debian/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/debian/bench/`)
|
||||
- [ ] White paper section
|
||||
33
tools/tickets/defects/distlib-0001.md
Normal file
33
tools/tickets/defects/distlib-0001.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
id: distlib-0001
|
||||
repo: distlib
|
||||
severity: MEDIUM
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `distlib/util.py:1180,1204`
|
||||
**Pattern:** `stack = []` then `successor in stack` in Tarjan SCC `strong_connections` property
|
||||
**Complexity:** `O(V²)`
|
||||
**Language:** Python
|
||||
|
||||
## Description
|
||||
|
||||
`distlib`'s `strong_connections` property implements Tarjan's SCC algorithm but uses a plain Python list as the DFS stack and tests membership with `successor in stack`. This linear membership test is performed for every edge explored during the SCC traversal. Since `distlib` is bundled with pip (version 0.3.8) and available standalone (0.4.0), this defect affects pip's dependency resolution in all current Python installations.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `successor in stack`
|
||||
**With:** `successor in on_stack`
|
||||
**Data structure change:** `stack: list → stack: list + on_stack: set`
|
||||
|
||||
## Work required
|
||||
|
||||
- [x] Patch in `defects/distlib/patch/distlib-0001-stack-set.patch`
|
||||
`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/distlib/unit/`)
|
||||
- [ ] Integration test (in `defects/distlib/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/distlib/bench/`)
|
||||
- [ ] White paper section
|
||||
32
tools/tickets/defects/erlang-0001.md
Normal file
32
tools/tickets/defects/erlang-0001.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
id: erlang-0001
|
||||
repo: otp
|
||||
severity: HIGH
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `lib/stdlib/src/digraph.erl:578`
|
||||
**Pattern:** `lists:member(V, Xs)` in `one_path/8` — used by `get_path`, `get_cycle`, `get_short_path`
|
||||
**Complexity:** `O(V²)`
|
||||
**Language:** Erlang
|
||||
|
||||
## Description
|
||||
|
||||
`one_path/8` in Erlang's stdlib digraph module tracks visited vertices using a plain list `Xs` and tests membership with `lists:member(V, Xs)`. This function is the underlying implementation for `get_path`, `get_cycle`, and `get_short_path`. For each vertex visited during path search, the full visited list is scanned linearly, resulting in O(V²) total work for paths of length V through the graph.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `lists:member(V, Xs)`
|
||||
**With:** `sets:is_element(V, XsSet)`
|
||||
**Data structure change:** `Xs: list() → XsSet: sets:set()`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/erlang/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/erlang/unit/`)
|
||||
- [ ] Integration test (in `defects/erlang/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/erlang/bench/`)
|
||||
- [ ] White paper section
|
||||
177
tools/tickets/defects/erlang-0002.md
Normal file
177
tools/tickets/defects/erlang-0002.md
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
---
|
||||
id: erlang-0002
|
||||
repo: erlang/otp
|
||||
file: lib/stdlib/src/digraph_utils.erl
|
||||
line: 495
|
||||
severity: MEDIUM
|
||||
status: FIXABLE-UPSTREAM
|
||||
created: 2026-03-23
|
||||
updated: 2026-03-24
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `lib/stdlib/src/digraph_utils.erl:495`
|
||||
**Pattern:** `lists:member(V, digraph:out_neighbours(G, V))` in `is_reflexive_vertex/2`
|
||||
**Complexity:** O(degree(V)) per vertex → O(V²) aggregate over full graph
|
||||
**Language:** Erlang
|
||||
|
||||
## Description
|
||||
|
||||
`is_reflexive_vertex/2` checks whether a vertex has a self-loop:
|
||||
|
||||
```erlang
|
||||
is_reflexive_vertex(V, G) ->
|
||||
lists:member(V, digraph:out_neighbours(G, V)).
|
||||
```
|
||||
|
||||
`digraph:out_neighbours/2` builds a complete neighbor list by joining two ETS tables:
|
||||
|
||||
```erlang
|
||||
out_neighbours(G, V) ->
|
||||
ET = G#digraph.etab,
|
||||
NT = G#digraph.ntab,
|
||||
[V2 || {{out, _}, E} <- ets:lookup(NT, {out, V}),
|
||||
{E, _, V2, _} <- ets:lookup(ET, E)].
|
||||
```
|
||||
|
||||
The ntab key is `{out, V}` — not `{out, V, Neighbor}`. There is no O(1) path to check
|
||||
"does V have a self-loop" from outside `digraph.erl`. You must build the full neighbor
|
||||
list and scan it.
|
||||
|
||||
`is_reflexive_vertex` is called from:
|
||||
- `digraph_utils:loop_vertices/1` (line 294) — iterates all V, calls once per vertex
|
||||
- `digraph_utils:is_simple/1` (line 485) — same pattern
|
||||
|
||||
Both call `is_reflexive_vertex` for every vertex in the graph → O(V²) total.
|
||||
|
||||
## Why the originally proposed fix is wrong
|
||||
|
||||
The ticket previously proposed:
|
||||
|
||||
```erlang
|
||||
sets:is_element(V, NeighbourSet)
|
||||
```
|
||||
|
||||
This does not help. You must first call `digraph:out_neighbours(G, V)` (which builds
|
||||
the list), then convert it with `sets:from_list/1` (O(degree(V))), then do the O(1)
|
||||
lookup. Net cost: still O(degree(V)) per vertex, O(V²) total. No improvement.
|
||||
|
||||
## Actual fix — add `sltab` to `digraph.erl` internals
|
||||
|
||||
`digraph.erl` uses three private ETS tables:
|
||||
|
||||
| Table | Key | Value | Purpose |
|
||||
|-------|-----|-------|---------|
|
||||
| `vtab` | `V` | `{V, Label}` | vertex storage |
|
||||
| `etab` | `E` | `{E, V1, V2, Label}` | edge storage |
|
||||
| `ntab` | `{out\|in, V}` | `{{out\|in, V}, E}` | neighbor index |
|
||||
|
||||
**Add a fourth table: `sltab` (self-loop table)**
|
||||
|
||||
`sltab` is a set storing `V` for every vertex that has at least one self-loop edge.
|
||||
Maintained entirely inside `digraph.erl`. No public API change required.
|
||||
|
||||
Changes to `digraph.erl`:
|
||||
|
||||
**1. Record:**
|
||||
```erlang
|
||||
-record(digraph, {vtab = notable :: ets:table(),
|
||||
etab = notable :: ets:table(),
|
||||
ntab = notable :: ets:table(),
|
||||
sltab = notable :: ets:table(), %% NEW: self-loop index
|
||||
cyclic = true :: boolean()}).
|
||||
```
|
||||
|
||||
**2. `new/1` — initialize sltab:**
|
||||
```erlang
|
||||
SL = ets:new(digraph_sltab, [set, public]),
|
||||
set_type(Ts, #digraph{vtab=V, etab=E, ntab=N, sltab=SL});
|
||||
```
|
||||
|
||||
**3. `delete/1` — destroy sltab:**
|
||||
```erlang
|
||||
ets:delete(G#digraph.sltab),
|
||||
```
|
||||
|
||||
**4. `do_insert_edge/5` — record self-loops:**
|
||||
```erlang
|
||||
do_insert_edge(E, V1, V2, Label, #digraph{ntab=NT, etab=ET, sltab=SL}) ->
|
||||
ets:insert(NT, [{{out, V1}, E}, {{in, V2}, E}]),
|
||||
ets:insert(ET, {E, V1, V2, Label}),
|
||||
case V1 =:= V2 of
|
||||
true -> ets:insert(SL, {V1});
|
||||
false -> ok
|
||||
end,
|
||||
E.
|
||||
```
|
||||
|
||||
**5. Edge deletion — remove self-loop record when last self-loop is deleted:**
|
||||
In `do_del_edge/2`, after deleting from ntab/etab, check if any self-loop remains:
|
||||
```erlang
|
||||
case {V1 =:= V2,
|
||||
ets:select(ET, [{{'_', V1, V1, '_'}, [], [true]}], 1)} of
|
||||
{true, '$end_of_table'} -> ets:delete(SL, V1);
|
||||
_ -> ok
|
||||
end,
|
||||
```
|
||||
|
||||
**6. Export `has_self_loop/2`:**
|
||||
```erlang
|
||||
-spec has_self_loop(G, V) -> boolean() when G :: graph(), V :: vertex().
|
||||
has_self_loop(G, V) ->
|
||||
ets:member(G#digraph.sltab, V).
|
||||
```
|
||||
|
||||
**7. `digraph_utils:is_reflexive_vertex/2` — call the new O(1) function:**
|
||||
```erlang
|
||||
%% Before — O(degree(V))
|
||||
is_reflexive_vertex(V, G) ->
|
||||
lists:member(V, digraph:out_neighbours(G, V)).
|
||||
|
||||
%% After — O(1)
|
||||
is_reflexive_vertex(V, G) ->
|
||||
digraph:has_self_loop(G, V).
|
||||
```
|
||||
|
||||
## Complexity after fix
|
||||
|
||||
| Operation | Before | After |
|
||||
|-----------|--------|-------|
|
||||
| `is_reflexive_vertex/2` | O(degree(V)) | O(1) |
|
||||
| `loop_vertices/1` | O(V²) | O(V) |
|
||||
| `is_simple/1` (reflexive check) | O(V²) | O(V) |
|
||||
| `add_edge` | O(1) | O(1) + 1 ETS insert |
|
||||
| `del_edge` | O(1) | O(1) + 1 ETS select + conditional delete |
|
||||
|
||||
## Why this is load-bearing
|
||||
|
||||
`digraph` and `digraph_utils` are OTP stdlib — used by:
|
||||
- **Erlang/OTP itself** — release dependency resolution, application boot ordering
|
||||
- **Rebar3** — build tool for all Erlang projects; dependency graph resolution
|
||||
- **Mix / Hex** — Elixir's build tool (calls into OTP digraph)
|
||||
- **ejabberd** — XMPP server used in production at scale; routing graph
|
||||
- **RabbitMQ** — message broker; exchange graph and routing topology
|
||||
- **Every Erlang application** that calls `digraph_utils:loop_vertices/1` or
|
||||
`is_simple/1` on a graph with self-loops
|
||||
|
||||
Any Erlang or Elixir application that checks graph reflexivity or simplicity on a
|
||||
non-trivial graph is running O(V²). For RabbitMQ or ejabberd routing graphs at scale,
|
||||
this is a live performance defect in production.
|
||||
|
||||
## Status rationale
|
||||
|
||||
Previous status: NOT-FIXABLE (incorrect — the reason given was "OTP ABI constraint"
|
||||
but no specific constraint was identified).
|
||||
|
||||
Actual status: FIXABLE-UPSTREAM. The fix requires patching `digraph.erl` inside OTP
|
||||
stdlib. This is not a local fix — it requires an upstream OTP PR. The public API of
|
||||
`digraph` and `digraph_utils` is unchanged. `has_self_loop/2` is a new addition.
|
||||
|
||||
## Work items
|
||||
|
||||
- [ ] Patch `lib/stdlib/src/digraph.erl` — add sltab, `has_self_loop/2`
|
||||
- [ ] Patch `lib/stdlib/src/digraph_utils.erl:495` — use `digraph:has_self_loop/2`
|
||||
- [ ] Unit test — `loop_vertices` op count: V=100,200,400 on complete graph with self-loops
|
||||
- [ ] Integration test — `is_simple/1`, `loop_vertices/1` correctness before/after
|
||||
- [ ] OTP upstream PR
|
||||
43
tools/tickets/defects/frrouting-0001.md
Normal file
43
tools/tickets/defects/frrouting-0001.md
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
id: frrouting-0001
|
||||
repo: FRRouting/frr
|
||||
severity: HIGH
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `ospfd/ospf_ti_lfa.c:72,114,227,278,285`
|
||||
**Pattern:** `listnode_lookup(q_space->pc_path, vertex)` — linear scan through post-convergence path list
|
||||
**Complexity:** `O(path_length²)` per protected element during TI-LFA backup computation
|
||||
**Language:** C
|
||||
|
||||
## Description
|
||||
|
||||
FRRouting's TI-LFA (Topology Independent Loop-Free Alternates) implementation uses
|
||||
`listnode_lookup()` — a linear scan through a doubly-linked list — to locate vertices in
|
||||
the post-convergence path (`pc_path`) during backup tunnel construction. The function is
|
||||
called 5 times in the same file. For each protected link or node, TI-LFA must find the
|
||||
P-node and Q-node positions within the post-convergence path, performing O(path_length)
|
||||
work per lookup. On a network with N routers and P protected elements, total TI-LFA
|
||||
computation is O(P × path_length), where both P and path_length grow with N.
|
||||
|
||||
Note: The main OSPF SPF implementation (`ospf_spf.c`) is **clean** — it uses the
|
||||
`LSA_SPF_IN_SPFTREE` pointer flag (O(1) membership) and a skip-list priority queue.
|
||||
Only the TI-LFA extension has the defect.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `listnode_lookup(pc_path, vertex)` — O(n) linked-list scan
|
||||
**With:** vertex index stored in the vertex struct, or a companion hash map `vertex → listnode*`
|
||||
**Data structure change:** add `struct listnode *pc_path_node` to `struct vertex` so
|
||||
lookup is O(1) via `vertex->pc_path_node` — set when path is built, nulled on cleanup.
|
||||
|
||||
## Work required
|
||||
|
||||
- [x] Patch in `defects/frrouting/patch/frrouting-0001-pc-path-index.patch`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/frrouting/unit/`)
|
||||
- [ ] Integration test (in `defects/frrouting/integration/`)
|
||||
- [ ] Benchmark — before/after on network with V=50,100,200,400 routers with full mesh protection (in `defects/frrouting/bench/`)
|
||||
- [ ] White paper section — `whitepaper/vectors/networking/frrouting.rst`
|
||||
89
tools/tickets/defects/frrouting-0002.md
Normal file
89
tools/tickets/defects/frrouting-0002.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
---
|
||||
id: frrouting-0002
|
||||
repo: FRRouting/frr
|
||||
file: ospfd/ospf_spf.c
|
||||
line: 275
|
||||
status: unpatched
|
||||
severity: HIGH
|
||||
complexity: O(V²) worst case — V = vertices in OSPF area; triggered on every topology change
|
||||
pattern: listnode_lookup on children list inside Dijkstra main loop
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`ospf_vertex_add_parent()` is called for every vertex added to the SPF tree (inside
|
||||
the Dijkstra main loop at `ospf_spf_calculate:1760`). For each vertex `v`, it checks
|
||||
whether `v` is already in its parent's children list before adding it:
|
||||
|
||||
```c
|
||||
/* ospf_spf.c:264 */
|
||||
static void ospf_vertex_add_parent(struct vertex *v)
|
||||
{
|
||||
for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) {
|
||||
/* No need to add two links from the same parent. */
|
||||
if (listnode_lookup(vp->parent->children, v) == NULL) // O(|children|)
|
||||
listnode_add(vp->parent->children, v);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`listnode_lookup()` is a linear scan over a singly-linked list (`lib/linklist.c`).
|
||||
`vp->parent->children` grows as the SPF tree is built; for the root vertex it
|
||||
reaches size = number of directly connected neighbors.
|
||||
|
||||
The Dijkstra loop (`ospf_spf_calculate:1748–1772`) processes V vertices. For each:
|
||||
- P ECMP parents (typically 1, max ~64)
|
||||
- Per parent: `listnode_lookup` over `parent->children` — O(|children| at that moment)
|
||||
|
||||
Worst case (star/hub-and-spoke topology, V routers all connected to one hub):
|
||||
- The hub's children list grows to size V
|
||||
- Each of V vertices calls `listnode_lookup` on that list
|
||||
- Total: O(V²)
|
||||
|
||||
## Call context
|
||||
|
||||
`ospf_spf_calculate()` is called on **every OSPF topology change** (LSA received,
|
||||
neighbor state change, interface up/down). The scheduling is at
|
||||
`ospf_spf_calculate_schedule()` with configurable throttle timers
|
||||
(`ospf_spf_calculate_schedule_worker:1844`), but during convergence storms a large
|
||||
flat area will run this O(V²) loop repeatedly.
|
||||
|
||||
A flat enterprise OSPF area with 500 routers (common in large campus/DC deployments)
|
||||
has ~125,000 comparisons per SPF run vs. ~500 for the O(V) fix.
|
||||
|
||||
## Fix
|
||||
|
||||
Replace `struct list *children` in `struct vertex` with a hash set for O(1) membership.
|
||||
FRRouting's `lib/hash.h` provides a hash table. Alternative: since OSPF vertex IDs
|
||||
are IPv4 addresses (4 bytes), a bitset indexed by some stable ID would give O(1)
|
||||
in O(V/64) space.
|
||||
|
||||
Minimal fix: parallel `struct hash *children_set` alongside the list (for compatibility
|
||||
with code that iterates `children` as a list), used only for the duplicate check:
|
||||
|
||||
```c
|
||||
/* Before */
|
||||
if (listnode_lookup(vp->parent->children, v) == NULL)
|
||||
listnode_add(vp->parent->children, v);
|
||||
|
||||
/* After — O(1) duplicate check */
|
||||
if (!hash_lookup(vp->parent->children_set, v)) {
|
||||
hash_get(vp->parent->children_set, v, hash_alloc_intern);
|
||||
listnode_add(vp->parent->children, v);
|
||||
}
|
||||
```
|
||||
|
||||
Or simpler: use `SET_FLAG` on the vertex's `flags` field to mark "already added as
|
||||
child of this parent" since each vertex is processed exactly once in Dijkstra.
|
||||
|
||||
## Relationship to frrouting-0001
|
||||
|
||||
`frrouting-0001` (already patched) fixed `listnode_lookup` × 5 in `ospf_ti_lfa.c`
|
||||
(the TI-LFA post-convergence fast-reroute calculator). This defect is in the primary
|
||||
SPF Dijkstra core — more fundamental, higher blast radius.
|
||||
|
||||
## Work items
|
||||
|
||||
- [ ] patch
|
||||
- [ ] unit test (SPF ops count: V=100, V=200, V=400 on hub-spoke topology)
|
||||
- [ ] integration test (OSPF convergence time before/after on large lab topology)
|
||||
34
tools/tickets/defects/gcc-0001.md
Normal file
34
tools/tickets/defects/gcc-0001.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
id: gcc-0001
|
||||
repo: gcc
|
||||
severity: MEDIUM
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
patched: 2026-03-23
|
||||
patch: defects/gcc/patch/gcc-0001-gcov-blocked-map.patch
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `gcc/gcov.cc:980`
|
||||
**Pattern:** `std::find(vector.begin,end,w)` in Johnson's algorithm for coverage analysis
|
||||
**Complexity:** `O(V²)`
|
||||
**Language:** C++
|
||||
|
||||
## Description
|
||||
|
||||
GCC's coverage analysis (`gcov`) uses Johnson's algorithm to find all simple cycles in the control flow graph. At line 980, the algorithm checks whether a vertex is blocked using `std::find` over a `std::vector`. This linear membership check is performed for every vertex examined during the cycle-finding DFS, causing the blocked-set lookup to dominate runtime and degrading the algorithm from near-linear to O(V²) for dense CFGs.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `std::find(blocked.begin(), blocked.end(), w) != blocked.end()`
|
||||
**With:** `blockedSet.count(w) > 0`
|
||||
**Data structure change:** `std::vector<vertex_t> blocked → std::unordered_set<vertex_t> blockedSet`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/gcc/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/gcc/unit/`)
|
||||
- [ ] Integration test (in `defects/gcc/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/gcc/bench/`)
|
||||
- [ ] White paper section
|
||||
34
tools/tickets/defects/ghc-0001.md
Normal file
34
tools/tickets/defects/ghc-0001.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
id: ghc-0001
|
||||
repo: ghc
|
||||
severity: HIGH
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
patched: 2026-03-23
|
||||
patch: defects/ghc/patch/ghc-cwe407-set-membership.patch
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `compiler/GHC/Data/Graph/Directed/Internal.hs:78`
|
||||
**Pattern:** `` v `elem` adjacency_list `` in SCC decode
|
||||
**Complexity:** `O(V×degree)`
|
||||
**Language:** Haskell
|
||||
|
||||
## Description
|
||||
|
||||
During SCC decoding, GHC checks edge membership using `elem` on an adjacency list represented as a plain Haskell list. For each vertex V being decoded, every neighbor lookup scans up to `degree` entries linearly. With V vertices each having up to `degree` neighbors, the aggregate cost across the full SCC decode is O(V×degree), which degrades to O(V²) for dense graphs.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `` v `elem` adjacency_list ``
|
||||
**With:** `` v `S.member` adjacency_set ``
|
||||
**Data structure change:** `adjacency_list: [Vertex] → adjacency_set: Set Vertex`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/ghc/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/ghc/unit/`)
|
||||
- [ ] Integration test (in `defects/ghc/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/ghc/bench/`)
|
||||
- [ ] White paper section
|
||||
34
tools/tickets/defects/ghc-0002.md
Normal file
34
tools/tickets/defects/ghc-0002.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
id: ghc-0002
|
||||
repo: ghc
|
||||
severity: HIGH
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
patched: 2026-03-23
|
||||
patch: defects/ghc/patch/ghc-cwe407-set-membership.patch
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `compiler/GHC/Data/Graph/Inductive/Graph.hs:489-501`
|
||||
**Pattern:** `elem` x4 edge-existence checks in codegen
|
||||
**Complexity:** `O(degree) per query`
|
||||
**Language:** Haskell
|
||||
|
||||
## Description
|
||||
|
||||
Four separate `elem` calls are used to check edge existence in the inductive graph representation used during code generation. Each `elem` call scans a list of adjacency entries linearly. Although each individual check is O(degree), these checks are performed repeatedly during code generation traversals, and the pattern compounds across all queries made on the graph during a compilation pass.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `e `elem` edges`
|
||||
**With:** `e `S.member` edgeSet`
|
||||
**Data structure change:** `edge lists → Set-backed adjacency structure`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/ghc/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/ghc/unit/`)
|
||||
- [ ] Integration test (in `defects/ghc/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/ghc/bench/`)
|
||||
- [ ] White paper section
|
||||
32
tools/tickets/defects/ghc-0003.md
Normal file
32
tools/tickets/defects/ghc-0003.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
id: ghc-0003
|
||||
repo: ghc
|
||||
severity: HIGH
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `compiler/GHC/Data/Graph/Ops.hs:637`
|
||||
**Pattern:** `` elem color neighbourColors `` in register allocator graph coloring
|
||||
**Complexity:** `O(deg²) per function`
|
||||
**Language:** Haskell
|
||||
|
||||
## Description
|
||||
|
||||
GHC's register allocator uses graph coloring to assign registers to virtual registers. At line 637, the coloring algorithm checks whether a candidate color is already used by a neighbor via `elem color neighbourColors`, scanning a list. Since this check is performed for each color candidate for each neighbor of each node, the cost per function is O(deg²) where deg is the average node degree in the interference graph.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `` elem color neighbourColors ``
|
||||
**With:** `` color `S.member` neighbourColorSet ``
|
||||
**Data structure change:** `neighbourColors: [Color] → neighbourColorSet: Set Color`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/ghc/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/ghc/unit/`)
|
||||
- [ ] Integration test (in `defects/ghc/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/ghc/bench/`)
|
||||
- [ ] White paper section
|
||||
34
tools/tickets/defects/ghc-0004.md
Normal file
34
tools/tickets/defects/ghc-0004.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
id: ghc-0004
|
||||
repo: ghc
|
||||
severity: MEDIUM
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
patched: 2026-03-23
|
||||
patch: defects/ghc/patch/ghc-cwe407-set-membership.patch
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `compiler/GHC/Tc/TyCl/Utils.hs:973`
|
||||
**Pattern:** `elem` in constructor list during type-class checking
|
||||
**Complexity:** `O(n) per check`
|
||||
**Language:** Haskell
|
||||
|
||||
## Description
|
||||
|
||||
During type-class checking, GHC tests whether a data constructor is in a list using `elem`, which performs a linear scan. This check is applied per-constructor during the verification of derived instances and type-class obligations. For data types with many constructors, or when checks are repeated across multiple class instances, the O(n) per-check cost accumulates into noticeable compilation slowdown.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `` con `elem` conList ``
|
||||
**With:** `` con `S.member` conSet ``
|
||||
**Data structure change:** `conList: [DataCon] → conSet: Set DataCon`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/ghc/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/ghc/unit/`)
|
||||
- [ ] Integration test (in `defects/ghc/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/ghc/bench/`)
|
||||
- [ ] White paper section
|
||||
33
tools/tickets/defects/gyp-0001.md
Normal file
33
tools/tickets/defects/gyp-0001.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
id: gyp-0001
|
||||
repo: gyp
|
||||
severity: MEDIUM
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `pylib/gyp/input.py:1604`
|
||||
**Pattern:** `child in path` list membership + `.index()` in DFS cycle detection
|
||||
**Complexity:** `O(V²)`
|
||||
**Language:** Python
|
||||
|
||||
## Description
|
||||
|
||||
GYP's DFS-based cycle detection maintains the current path as a Python list and checks for back-edges using `child in path` (a linear scan). When a cycle is found, `.index()` is called on the same list to find the cycle start, which is another linear scan. Both operations are O(path length), and since they are performed for every edge in the dependency graph, the total cost is O(V²) in the number of targets.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `child in path` and `path.index(child)`
|
||||
**With:** `child in path_set` and `path_index[child]`
|
||||
**Data structure change:** `path: list → path: list + path_set: set + path_index: dict`
|
||||
|
||||
## Work required
|
||||
|
||||
- [x] Patch in `defects/gyp/patch/gyp-0001-path-set.patch`
|
||||
`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/gyp/unit/`)
|
||||
- [ ] Integration test (in `defects/gyp/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/gyp/bench/`)
|
||||
- [ ] White paper section
|
||||
32
tools/tickets/defects/javac-0001.md
Normal file
32
tools/tickets/defects/javac-0001.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
id: javac-0001
|
||||
repo: openjdk
|
||||
severity: HIGH
|
||||
status: patched
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `src/jdk.compiler/.../javac/comp/GraphUtils.java:186`
|
||||
**Pattern:** `stack.contains(n)` in Tarjan SCC
|
||||
**Complexity:** `O(V²)`
|
||||
**Language:** Java
|
||||
|
||||
## Description
|
||||
|
||||
Tarjan's strongly connected components algorithm maintains a stack of nodes currently under exploration. At line 186, the implementation tests stack membership using `stack.contains(n)` on a `List`, requiring a linear scan of the stack for every node visited. Since this check is performed for every edge in the graph, the overall algorithm degrades from O(V+E) to O(V²+VE) for dense graphs.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `stack.contains(n)`
|
||||
**With:** `onStack.contains(n)`
|
||||
**Data structure change:** `List<Node> stack → HashSet<Node> onStack + Deque<Node> stack`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/javac/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/javac/unit/`)
|
||||
- [ ] Integration test (in `defects/javac/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/javac/bench/`)
|
||||
- [ ] White paper section
|
||||
32
tools/tickets/defects/javac-0002a.md
Normal file
32
tools/tickets/defects/javac-0002a.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
id: javac-0002a
|
||||
repo: openjdk
|
||||
severity: HIGH
|
||||
status: patched
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `src/jdk.compiler/.../javac/comp/Infer.java:1850`
|
||||
**Pattern:** `ArrayList.contains` in `findNode`
|
||||
**Complexity:** `O(N²)`
|
||||
**Language:** Java
|
||||
|
||||
## Description
|
||||
|
||||
`findNode` is called during type inference graph construction to check whether a node is already present in the node list. The check is performed using `ArrayList.contains`, which performs a full linear scan. Because `findNode` is called once per inference variable during graph construction, and each call scans up to N existing nodes, the total cost of node lookup is O(N²) in the number of inference variables.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `nodes.contains(node)`
|
||||
**With:** `nodeSet.contains(node)`
|
||||
**Data structure change:** `ArrayList<Node> nodes → HashSet<Node> nodeSet + ArrayList<Node> nodes`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/javac/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/javac/unit/`)
|
||||
- [ ] Integration test (in `defects/javac/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/javac/bench/`)
|
||||
- [ ] White paper section
|
||||
32
tools/tickets/defects/javac-0002b.md
Normal file
32
tools/tickets/defects/javac-0002b.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
id: javac-0002b
|
||||
repo: openjdk
|
||||
severity: HIGH
|
||||
status: patched
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `src/jdk.compiler/.../javac/comp/Infer.java:1747`
|
||||
**Pattern:** uncached closure DFS
|
||||
**Complexity:** `O(K·V)`
|
||||
**Language:** Java
|
||||
|
||||
## Description
|
||||
|
||||
At line 1747, the inference engine performs a DFS to compute the transitive closure of inference variable dependencies, but the result is not cached between calls. Each query for reachability retraverses the full dependency subgraph, costing O(V) per call. With K such queries per inference round, the total cost becomes O(K·V) where both K and V grow with program complexity.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** uncached DFS closure traversal
|
||||
**With:** precomputed and cached transitive closure map
|
||||
**Data structure change:** `(none — add Map<InferenceVar, Set<InferenceVar>> closureCache)`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/javac/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/javac/unit/`)
|
||||
- [ ] Integration test (in `defects/javac/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/javac/bench/`)
|
||||
- [ ] White paper section
|
||||
34
tools/tickets/defects/javac-0003.md
Normal file
34
tools/tickets/defects/javac-0003.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
id: javac-0003
|
||||
repo: openjdk
|
||||
severity: MEDIUM
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
patched: 2026-03-23
|
||||
patch: defects/javac/patch/javac-0003-modulehasher-stackset.patch
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `src/jdk.compiler/.../javac/comp/ModuleHashesBuilder.java`
|
||||
**Pattern:** `Deque.contains()` in module dependency traversal
|
||||
**Complexity:** `O(M²)`
|
||||
**Language:** Java
|
||||
|
||||
## Description
|
||||
|
||||
`ModuleHashesBuilder` traverses the module dependency graph to compute hashes for modules. During traversal, it uses `Deque.contains()` to check whether a module has already been visited. `Deque.contains()` performs a linear scan of all elements in the deque. With M modules, each requiring a membership check against up to M already-visited modules, the total traversal cost is O(M²).
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `visited.contains(module)`
|
||||
**With:** `visitedSet.contains(module)`
|
||||
**Data structure change:** `Deque<ModuleSymbol> visited → HashSet<ModuleSymbol> visitedSet + Deque<ModuleSymbol> visitedQueue`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/javac/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/javac/unit/`)
|
||||
- [ ] Integration test (in `defects/javac/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/javac/bench/`)
|
||||
- [ ] White paper section
|
||||
32
tools/tickets/defects/javac-0004.md
Normal file
32
tools/tickets/defects/javac-0004.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
id: javac-0004
|
||||
repo: openjdk
|
||||
severity: HIGH
|
||||
status: patched
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `src/jdk.compiler/.../javac/comp/Dependencies.java:197`
|
||||
**Pattern:** `List.contains+add` in dependency tracking
|
||||
**Complexity:** `O(M²)`
|
||||
**Language:** Java
|
||||
|
||||
## Description
|
||||
|
||||
The dependency tracker maintains a list of recorded dependencies and guards against duplicates using a `List.contains` check before each `add`. This pattern requires a linear scan of the existing dependency list for every new dependency recorded. With M total dependency recording operations, the cumulative cost of all membership checks is O(M²).
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `if (!deps.contains(dep)) deps.add(dep)`
|
||||
**With:** `if (depSet.add(dep)) depList.add(dep)`
|
||||
**Data structure change:** `List<Dependency> deps → LinkedHashSet<Dependency> deps`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/javac/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/javac/unit/`)
|
||||
- [ ] Integration test (in `defects/javac/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/javac/bench/`)
|
||||
- [ ] White paper section
|
||||
32
tools/tickets/defects/javac-0005.md
Normal file
32
tools/tickets/defects/javac-0005.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
id: javac-0005
|
||||
repo: openjdk
|
||||
severity: HIGH
|
||||
status: patched
|
||||
created: 2026-03-23
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `src/jdk.compiler/.../javac/comp/InferenceContext.java:506`
|
||||
**Pattern:** `List.containsAll()` in inference context
|
||||
**Complexity:** `O(B²)`
|
||||
**Language:** Java
|
||||
|
||||
## Description
|
||||
|
||||
`InferenceContext` uses `List.containsAll()` to check whether one set of inference variables is a subset of another. `containsAll` on a `List` performs a linear scan for each element being tested, making the overall check O(B²) where B is the size of the bounds sets. This check is performed during bounds propagation, which is called repeatedly throughout inference.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `list.containsAll(otherList)`
|
||||
**With:** `set.containsAll(otherCollection)`
|
||||
**Data structure change:** `List<Type> freeVars → LinkedHashSet<Type> freeVars`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/javac/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/javac/unit/`)
|
||||
- [ ] Integration test (in `defects/javac/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/javac/bench/`)
|
||||
- [ ] White paper section
|
||||
34
tools/tickets/defects/kotlin-0001.md
Normal file
34
tools/tickets/defects/kotlin-0001.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
id: kotlin-0001
|
||||
repo: kotlin
|
||||
severity: HIGH
|
||||
status: PATCHED
|
||||
created: 2026-03-23
|
||||
patched: 2026-03-23
|
||||
patch: defects/kotlin/patch/kotlin-0001-collectreachable-hashset.patch
|
||||
---
|
||||
|
||||
## Defect
|
||||
|
||||
**File:** `compiler/frontend/src/org/jetbrains/kotlin/resolve/NonExpansiveInheritanceRestrictionChecker.kt:150`
|
||||
**Pattern:** `in List` after DFS
|
||||
**Complexity:** `O(E×V)`
|
||||
**Language:** Kotlin
|
||||
|
||||
## Description
|
||||
|
||||
The non-expansive inheritance restriction checker performs a DFS and then tests membership in a result list using the `in` operator, which triggers a linear scan. This post-DFS membership check is applied for each edge E during verification, and each check scans up to V entries, yielding O(E×V) total cost. For deeply nested inheritance hierarchies this becomes a significant performance bottleneck.
|
||||
|
||||
## Fix
|
||||
|
||||
**Replace:** `node in visitedList`
|
||||
**With:** `node in visitedSet`
|
||||
**Data structure change:** `visitedList: MutableList<TypeParameterDescriptor> → visitedSet: MutableSet<TypeParameterDescriptor>`
|
||||
|
||||
## Work required
|
||||
|
||||
- [ ] Patch in `defects/kotlin/patch/`
|
||||
- [ ] Unit test — asserts exact operation counts before/after (in `defects/kotlin/unit/`)
|
||||
- [ ] Integration test (in `defects/kotlin/integration/`)
|
||||
- [ ] Benchmark — before/after on V=100,200,400,800 (in `defects/kotlin/bench/`)
|
||||
- [ ] White paper section
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue