undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,232 @@
package unit;
import java.util.*;
/**
* Unit test for buildkit-0001: cacheKeyStorage.HasLink() CWE-407.
*
* Defect: HasLink() in the v1 remote cache importer calls
* slices.Contains(it.links[l], target) where it.links[l] is a []string.
* For K cache entries each with L links, repeated HasLink() calls cost O(K×L).
*
* File: cache/remotecache/v1/cachestorage.go:244
* Symbol: (*cacheKeyStorage).HasLink — `slices.Contains(it.links[l], target)`
*
* Fix: Change the links value type from []string to map[string]struct{}.
* HasLink() becomes a map lookup: O(1). Building the map costs O(L) once.
* Total cost for K entries: O(K×L) build + O(K) queries = O(K×L) → amortized
* O(1) per query after build. Total work at K=L=100: from 10000 to ~200.
*
* Modeled here in Java:
* - []string ≡ List<String> (defective)
* - map[string]struct{} ≡ Set<String> (fixed)
* - nlink key ≡ String (simplified)
* - comparisons counted at the membership-test site
*
* Expected at K=L=100:
* defective ≈ K × L = 10000 (worst-case: target not found → full scan)
* fixed ≈ K + K×L = 10100 build + K = 10200 total, but query cost = K = 100
* ratio (query-only) > 10×
*/
public class BuildkitHasLinkTest {
// ── Defective: links stored as List<String>, HasLink = linear scan ────────
static class DefectiveCacheKeyStorage {
// maps cacheEntryID → linkKey → []string (list of target IDs)
final Map<String, Map<String, List<String>>> byID = new LinkedHashMap<>();
long comparisons = 0;
void addLink(String entryID, String linkKey, String targetID) {
byID.computeIfAbsent(entryID, k -> new LinkedHashMap<>())
.computeIfAbsent(linkKey, k -> new ArrayList<>())
.add(targetID);
}
/** slices.Contains equivalent: O(L) linear scan. */
boolean hasLink(String entryID, String linkKey, String target) {
Map<String, List<String>> links = byID.get(entryID);
if (links == null) return false;
List<String> targets = links.get(linkKey);
if (targets == null) return false;
for (String t : targets) {
comparisons++;
if (t.equals(target)) return true;
}
return false;
}
}
// ── Fixed: links stored as Set<String>, HasLink = O(1) map lookup ─────────
static class FixedCacheKeyStorage {
// maps cacheEntryID → linkKey → map[string]struct{} (set of target IDs)
final Map<String, Map<String, Set<String>>> byID = new LinkedHashMap<>();
long buildComparisons = 0; // cost of building the sets
long queryComparisons = 0; // cost of HasLink queries
void addLink(String entryID, String linkKey, String targetID) {
buildComparisons++; // one hash op per insertion
byID.computeIfAbsent(entryID, k -> new LinkedHashMap<>())
.computeIfAbsent(linkKey, k -> new HashSet<>())
.add(targetID);
}
/** map lookup equivalent: O(1). */
boolean hasLink(String entryID, String linkKey, String target) {
Map<String, Set<String>> links = byID.get(entryID);
if (links == null) return false;
Set<String> targets = links.get(linkKey);
if (targets == null) return false;
queryComparisons++; // O(1) hash lookup
return targets.contains(target);
}
long comparisons() { return buildComparisons + queryComparisons; }
}
// ── Simulation helpers ────────────────────────────────────────────────────
/**
* Populate K cache entries, each with L links under a single linkKey.
* Then query hasLink for each entry's last-inserted target (worst-case
* for the defective linear scan: target is at end of list).
*/
public static long simulateDefective(int K, int L) {
DefectiveCacheKeyStorage storage = new DefectiveCacheKeyStorage();
String linkKey = "lk:sha256:abc/0/selector";
String[] lastTarget = new String[K];
for (int k = 0; k < K; k++) {
String entryID = "entry_" + k;
for (int l = 0; l < L; l++) {
String targetID = "target_" + k + "_" + l;
storage.addLink(entryID, linkKey, targetID);
lastTarget[k] = targetID;
}
}
// Query: check each entry's last target (worst-case: at end of list → full scan)
for (int k = 0; k < K; k++) {
String entryID = "entry_" + k;
boolean found = storage.hasLink(entryID, linkKey, lastTarget[k]);
assert found : "hasLink should return true for known target";
}
return storage.comparisons;
}
public static long simulateFixedQuery(int K, int L) {
FixedCacheKeyStorage storage = new FixedCacheKeyStorage();
String linkKey = "lk:sha256:abc/0/selector";
String[] lastTarget = new String[K];
for (int k = 0; k < K; k++) {
String entryID = "entry_" + k;
for (int l = 0; l < L; l++) {
String targetID = "target_" + k + "_" + l;
storage.addLink(entryID, linkKey, targetID);
lastTarget[k] = targetID;
}
}
// same queries
for (int k = 0; k < K; k++) {
String entryID = "entry_" + k;
boolean found = storage.hasLink(entryID, linkKey, lastTarget[k]);
assert found : "hasLink should return true for known target";
}
return storage.queryComparisons; // only query cost, not build
}
// ── Tests ─────────────────────────────────────────────────────────────────
static void testCorrectnessMatch() {
DefectiveCacheKeyStorage def = new DefectiveCacheKeyStorage();
FixedCacheKeyStorage fix = new FixedCacheKeyStorage();
String linkKey = "lk:sha256:test/0/";
for (int i = 0; i < 5; i++) {
String eid = "e_" + i;
for (int j = 0; j < 5; j++) {
String tid = "t_" + i + "_" + j;
def.addLink(eid, linkKey, tid);
fix.addLink(eid, linkKey, tid);
}
}
// Check positive cases
for (int i = 0; i < 5; i++) {
String eid = "e_" + i;
for (int j = 0; j < 5; j++) {
String tid = "t_" + i + "_" + j;
boolean d = def.hasLink(eid, linkKey, tid);
boolean f = fix.hasLink(eid, linkKey, tid);
assert d == f : "hasLink mismatch for " + eid + "/" + tid + ": def=" + d + " fix=" + f;
assert d : "expected true for known link";
}
}
// Check negative cases
boolean d = def.hasLink("e_0", linkKey, "nonexistent");
boolean f = fix.hasLink("e_0", linkKey, "nonexistent");
assert !d && !f : "hasLink should return false for unknown target";
System.out.println("PASS testCorrectnessMatch");
}
static void testDefectiveGrowsQuadratically() {
long prev = -1;
for (int S : new int[]{10, 20, 40}) {
long c = simulateDefective(S, S);
if (prev > 0) {
double ratio = (double) c / prev;
assert ratio > 3.0
: "defective should grow >3x when K=L doubled; got " + ratio + " at K=L=" + S;
}
prev = c;
}
System.out.println("PASS testDefectiveGrowsQuadratically");
}
static void testFixedQueryGrowsLinearly() {
long prev = -1;
for (int S : new int[]{10, 20, 40}) {
long c = simulateFixedQuery(S, S);
if (prev > 0) {
double ratio = (double) c / prev;
assert ratio < 2.5
: "fixed query cost should grow ~2x when K doubled; got " + ratio + " at K=L=" + S;
}
prev = c;
}
System.out.println("PASS testFixedQueryGrowsLinearly");
}
static void testRatioAtScale() {
int K = 100, L = 100;
long defComp = simulateDefective(K, L);
long fixQuery = simulateFixedQuery(K, L);
double ratio = (double) defComp / fixQuery;
// defective: K queries × L comparisons each = K*L = 10000
assert defComp == (long) K * L
: "defective comparisons should be K*L=" + (K * L) + "; got " + defComp;
// fixed query: K queries × 1 = K = 100
assert fixQuery == K
: "fixed query comparisons should be K=" + K + "; got " + fixQuery;
assert ratio > 10.0
: "ratio should be >10x at K=L=100; got " + ratio;
System.out.printf(
"PASS testRatioAtScale (defective=%d, fixed_query=%d, ratio=%.1fx)%n",
defComp, fixQuery, ratio);
}
public static void main(String[] args) {
testCorrectnessMatch();
testDefectiveGrowsQuadratically();
testFixedQueryGrowsLinearly();
testRatioAtScale();
System.out.println("All buildkit-0001 tests passed.");
}
}