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,327 @@
package unit;
import java.util.*;
/**
* Unit test for presto-0001/0002/0003/0004: CWE-407 O(D×V) contains() defects
* in PushDownDereferences and PayloadJoinOptimizer.
*
* Defects:
* presto-0001 (PushDownDereferences.ExtractFromJoin, line 206):
* joinNode.getLeft().getOutputVariables().contains(baseVariable)
* called inside a for-each over D dereferences. ImmutableList.contains() is O(V).
* Total: O(D × V).
*
* presto-0002 (PushDownDereferences.PushDownDereferenceThroughJoin, line 369):
* Same pattern joinNode.getLeft().getOutputVariables().contains(baseVariable)
* inside dereference loop. O(D × V).
*
* presto-0003 (PushDownDereferences.PushDownDereferenceThroughSemiJoin, line 414):
* semiJoinNode.getFilteringSource().getOutputVariables().contains(baseVariable)
* inside dereference loop. O(D × V).
*
* presto-0004 (PayloadJoinOptimizer.visitJoin, line 208):
* inputJoinKeys.stream().filter(key -> rightNode.getOutputVariables().contains(key))
* ImmutableList.contains() called per join key. O(K × V).
*
* Fix for all: snapshot getOutputVariables() to ImmutableSet.copyOf() before the
* loop/stream. VariableReferenceExpression has correct equals()/hashCode().
* ImmutableSet.contains() is O(1) average.
*
* This test models the defective and fixed strategies using instrumented
* List/Set membership, counts element-level comparisons, and proves:
* - Defective: O(D × V) comparisons
* - Fixed: O(D + V) V to build set, D × O(1) lookups
* - Ratio > 10x at scale (D=100, V=100)
*/
public class PrestoDerefPushdownTest {
// Minimal VariableReferenceExpression stub
static class VarRef {
final String name;
VarRef(String name) { this.name = name; }
@Override
public boolean equals(Object o) {
return o instanceof VarRef && ((VarRef) o).name.equals(name);
}
@Override
public int hashCode() { return name.hashCode(); }
@Override
public String toString() { return "Var(" + name + ")"; }
}
// Instrumented membership containers
/**
* Wraps an ArrayList<VarRef> and counts every element-level equality check
* performed during contains(). Models the defective ImmutableList.contains().
*/
static class InstrumentedList {
final List<VarRef> backing;
long comparisons;
InstrumentedList(List<VarRef> vars) {
this.backing = new ArrayList<>(vars);
this.comparisons = 0;
}
boolean contains(VarRef target) {
for (VarRef v : backing) {
comparisons++;
if (v.equals(target)) return true;
}
return false;
}
}
/**
* Wraps a HashSet<VarRef> and counts each contains() call as 1 operation
* (O(1) hash lookup). Models the fixed ImmutableSet.copyOf().contains().
*/
static class InstrumentedSet {
final Set<VarRef> backing;
long comparisons;
InstrumentedSet(List<VarRef> vars) {
this.backing = new HashSet<>(vars);
// Building the set costs V insertions counted separately as buildCost
this.comparisons = 0;
}
boolean contains(VarRef target) {
comparisons++; // O(1) hash lookup counts as 1
return backing.contains(target);
}
}
// Test fixture builders
/** Build V output variables for a plan node side. */
static List<VarRef> outputVars(int v, String prefix) {
List<VarRef> list = new ArrayList<>();
for (int i = 0; i < v; i++) list.add(new VarRef(prefix + i));
return list;
}
/**
* Build D dereference base-variables. Half are drawn from leftVars (will be
* found), half are novel (will not be found). This exercises both the
* early-exit and the full-scan branches.
*/
static List<VarRef> derefBases(int d, List<VarRef> leftVars) {
List<VarRef> bases = new ArrayList<>();
for (int i = 0; i < d; i++) {
if (i % 2 == 0 && i / 2 < leftVars.size()) {
bases.add(leftVars.get(i / 2)); // found in left
} else {
bases.add(new VarRef("right_base_" + i)); // not found in left
}
}
return bases;
}
// Defective simulation: O(D × V)
static class DefectiveResult {
final long comparisons;
final List<VarRef> leftMatched;
DefectiveResult(long c, List<VarRef> m) { comparisons = c; leftMatched = m; }
}
/**
* Models presto-0001/0002/0003: loop over D dereference bases, call
* list.contains() (O(V)) for each total O(D × V).
*/
static DefectiveResult runDefective(List<VarRef> derefBases, List<VarRef> leftOutputVars) {
InstrumentedList leftList = new InstrumentedList(leftOutputVars);
List<VarRef> leftMatched = new ArrayList<>();
for (VarRef base : derefBases) {
if (leftList.contains(base)) {
leftMatched.add(base);
// (else goes to rightSideDereferences not relevant to comparison count)
}
}
return new DefectiveResult(leftList.comparisons, leftMatched);
}
/**
* Models presto-0004: stream over K join keys, call list.contains() (O(V))
* for each total O(K × V).
*/
static DefectiveResult runDefectiveStream(List<VarRef> joinKeys, List<VarRef> rightOutputVars) {
InstrumentedList rightList = new InstrumentedList(rightOutputVars);
List<VarRef> rightMatched = new ArrayList<>();
for (VarRef key : joinKeys) {
if (rightList.contains(key)) {
rightMatched.add(key);
}
}
return new DefectiveResult(rightList.comparisons, rightMatched);
}
// Fixed simulation: O(D + V)
static class FixedResult {
final long buildCost; // V hash insertions to build the set
final long lookupCost; // D × O(1) lookups
final List<VarRef> leftMatched;
FixedResult(long build, long lookup, List<VarRef> m) {
buildCost = build;
lookupCost = lookup;
leftMatched = m;
}
long totalCost() { return buildCost + lookupCost; }
}
/**
* Models the fix for presto-0001/0002/0003: snapshot to ImmutableSet before
* the loop, then O(1) contains() per dereference.
*/
static FixedResult runFixed(List<VarRef> derefBases, List<VarRef> leftOutputVars) {
long buildCost = leftOutputVars.size(); // V insertions into HashSet
InstrumentedSet leftSet = new InstrumentedSet(leftOutputVars);
List<VarRef> leftMatched = new ArrayList<>();
for (VarRef base : derefBases) {
if (leftSet.contains(base)) {
leftMatched.add(base);
}
}
return new FixedResult(buildCost, leftSet.comparisons, leftMatched);
}
/**
* Models the fix for presto-0004: snapshot rightNode.getOutputVariables()
* to ImmutableSet before the stream, then O(1) contains() per key.
*/
static FixedResult runFixedStream(List<VarRef> joinKeys, List<VarRef> rightOutputVars) {
long buildCost = rightOutputVars.size();
InstrumentedSet rightSet = new InstrumentedSet(rightOutputVars);
List<VarRef> rightMatched = new ArrayList<>();
for (VarRef key : joinKeys) {
if (rightSet.contains(key)) {
rightMatched.add(key);
}
}
return new FixedResult(buildCost, rightSet.comparisons, rightMatched);
}
// Tests
/**
* Test 1: correctness defective and fixed must identify the same
* left-side dereference bases. Models presto-0001/0002/0003.
*/
static void testCorrectnessPushdown() {
List<VarRef> leftVars = outputVars(20, "lv");
List<VarRef> bases = derefBases(30, leftVars);
DefectiveResult def = runDefective(bases, leftVars);
FixedResult fix = runFixed(bases, leftVars);
assert new HashSet<>(def.leftMatched).equals(new HashSet<>(fix.leftMatched))
: "defective and fixed must classify the same dereference bases as left-side";
System.out.println("PASS testCorrectnessPushdown");
}
/**
* Test 2: correctness defective and fixed must identify the same
* right-join-key matches. Models presto-0004.
*/
static void testCorrectnessPayloadJoin() {
List<VarRef> rightVars = outputVars(20, "rv");
// Half of join keys are in rightVars
List<VarRef> joinKeys = new ArrayList<>();
for (int i = 0; i < 20; i++) {
joinKeys.add(i % 2 == 0 ? rightVars.get(i / 2) : new VarRef("lk_" + i));
}
DefectiveResult def = runDefectiveStream(joinKeys, rightVars);
FixedResult fix = runFixedStream(joinKeys, rightVars);
assert new HashSet<>(def.leftMatched).equals(new HashSet<>(fix.leftMatched))
: "defective and fixed must find the same right-side join keys";
System.out.println("PASS testCorrectnessPayloadJoin");
}
/**
* Test 3: defective grows quadratically doubling D and V together should
* increase comparisons by > 3x (approaching 4x). Models presto-0001/0002/0003.
*/
static void testDefectiveGrowsQuadratically() {
long prev = -1;
for (int n : new int[]{20, 40, 80}) {
List<VarRef> leftVars = outputVars(n, "lv");
List<VarRef> bases = derefBases(n, leftVars);
long c = runDefective(bases, leftVars).comparisons;
if (prev > 0) {
double ratio = (double) c / prev;
assert ratio > 3.0
: "defective comparisons should grow >3x when D and V double; got " + ratio + " at n=" + n;
}
prev = c;
}
System.out.println("PASS testDefectiveGrowsQuadratically");
}
/**
* Test 4: ratio at scale at D=V=100, the fixed strategy (including set
* build cost) must be >10x fewer operations than the defective strategy.
* Covers all four defects.
*/
static void testRatioAtScaleExceedsTenX() {
int d = 100, v = 100;
// presto-0001/0002/0003 shape
List<VarRef> leftVars = outputVars(v, "lv");
List<VarRef> bases = derefBases(d, leftVars);
long defComparisons = runDefective(bases, leftVars).comparisons;
FixedResult fixResult = runFixed(bases, leftVars);
long fixTotal = fixResult.totalCost(); // build + lookup
double ratio = (double) defComparisons / fixTotal;
assert ratio > 10.0
: "at D=V=100, defective should be >10x worse than fixed (incl. build cost); ratio=" + ratio;
System.out.printf(
"PASS testRatioAtScaleExceedsTenX [presto-0001/0002/0003] "
+ "defective=%d, fixed_total=%d (build=%d + lookup=%d), ratio=%.1fx%n",
defComparisons, fixTotal, fixResult.buildCost, fixResult.lookupCost, ratio);
// presto-0004 shape (K join keys, V right output vars)
int k = 100;
List<VarRef> rightVars = outputVars(v, "rv");
List<VarRef> joinKeys = new ArrayList<>();
for (int i = 0; i < k; i++) {
joinKeys.add(i % 2 == 0 && i / 2 < rightVars.size()
? rightVars.get(i / 2) : new VarRef("lk_" + i));
}
long defStream = runDefectiveStream(joinKeys, rightVars).comparisons;
FixedResult fixStream = runFixedStream(joinKeys, rightVars);
long fixStreamTotal = fixStream.totalCost();
double ratio4 = (double) defStream / fixStreamTotal;
assert ratio4 > 10.0
: "at K=V=100, defective presto-0004 should be >10x worse; ratio=" + ratio4;
System.out.printf(
"PASS testRatioAtScaleExceedsTenX [presto-0004] "
+ "defective=%d, fixed_total=%d (build=%d + lookup=%d), ratio=%.1fx%n",
defStream, fixStreamTotal, fixStream.buildCost, fixStream.lookupCost, ratio4);
}
// Entry point
public static void main(String[] args) {
testCorrectnessPushdown();
testCorrectnessPayloadJoin();
testDefectiveGrowsQuadratically();
testRatioAtScaleExceedsTenX();
System.out.println("All presto-0001/0002/0003/0004 tests passed.");
}
}