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:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
109
tests/support/BoundSetAlgorithm.java
Normal file
109
tests/support/BoundSetAlgorithm.java
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
package support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Reference implementations of InferenceContext.isEquiv() — defective and fixed.
|
||||
*
|
||||
* DEFECT 0005 (jdk.compiler, InferenceContext.java:506):
|
||||
* isEquiv() uses List.containsAll() for set-equality comparison of bound lists.
|
||||
* Called twice (mutual containment): !b1.containsAll(b2) || !b2.containsAll(b1).
|
||||
* com.sun.tools.javac.util.List is a linked list — contains() is O(N).
|
||||
*
|
||||
* Fix: convert to LinkedHashSet and use Set.equals() — O(B) total.
|
||||
*
|
||||
* Exact comparison counts for equal sets of size B (forward vs reversed order):
|
||||
* defective: B*(B+1) (two containsAll calls, each = B*(B+1)/2)
|
||||
* fixed: B (one Set.equals check = B membership tests)
|
||||
*
|
||||
* Derivation of defective count:
|
||||
* b1 = [0, 1, ..., B-1], b2 = [B-1, B-2, ..., 0] (reversed — worst order).
|
||||
* b1.containsAll(b2): for each element x in b2, scan b1 until x found:
|
||||
* x=B-1: scan to index B-1 → B comparisons
|
||||
* x=B-2: scan to index B-2 → B-1 comparisons
|
||||
* ...
|
||||
* x=0: scan to index 0 → 1 comparison
|
||||
* Total: B + (B-1) + ... + 1 = B*(B+1)/2.
|
||||
* b2.containsAll(b1): symmetric = B*(B+1)/2.
|
||||
* Both calls complete because the sets are equal (|| short-circuits only on false).
|
||||
* Grand total: B*(B+1).
|
||||
*
|
||||
* Growth when B doubles: defective ≈4x (quadratic), fixed ≈2x (linear).
|
||||
*/
|
||||
public class BoundSetAlgorithm {
|
||||
|
||||
public static class Result {
|
||||
public final boolean equivalent;
|
||||
public final long comparisons;
|
||||
Result(boolean equivalent, long comparisons) {
|
||||
this.equivalent = equivalent;
|
||||
this.comparisons = comparisons;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── DEFECTIVE: List.containsAll() — O(B²) ───────────────────────────────
|
||||
// Mirrors InferenceContext.isEquiv():506 — two mutual containsAll() checks.
|
||||
|
||||
public static Result isEquivDefective(List<Integer> b1, List<Integer> b2) {
|
||||
long[] comparisons = {0};
|
||||
if (!listContainsAll(b1, b2, comparisons)) return new Result(false, comparisons[0]);
|
||||
if (!listContainsAll(b2, b1, comparisons)) return new Result(false, comparisons[0]);
|
||||
return new Result(true, comparisons[0]);
|
||||
}
|
||||
|
||||
private static boolean listContainsAll(List<Integer> haystack,
|
||||
List<Integer> needles,
|
||||
long[] comparisons) {
|
||||
for (Integer needle : needles) {
|
||||
boolean found = false;
|
||||
for (Integer h : haystack) {
|
||||
comparisons[0]++;
|
||||
if (h.equals(needle)) { found = true; break; }
|
||||
}
|
||||
if (!found) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ─── FIXED: Set.equals() — O(B) ─────────────────────────────────────────
|
||||
// Convert both lists to LinkedHashSet; use Set.equals() for comparison.
|
||||
// Set.equals() iterates one set and calls contains() on the other: O(B) total.
|
||||
|
||||
public static Result isEquivFixed(List<Integer> b1, List<Integer> b2) {
|
||||
Set<Integer> set1 = new LinkedHashSet<>(b1);
|
||||
Set<Integer> set2 = new LinkedHashSet<>(b2);
|
||||
long comparisons = 0;
|
||||
if (set1.size() != set2.size()) return new Result(false, comparisons);
|
||||
for (Integer x : set1) {
|
||||
comparisons++; // one O(1) HashSet.contains()
|
||||
if (!set2.contains(x)) return new Result(false, comparisons);
|
||||
}
|
||||
return new Result(true, comparisons);
|
||||
}
|
||||
|
||||
// ─── Factories ───────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Forward list: [0, 1, 2, ..., B-1].
|
||||
* Use as b1 — b2 reversed produces worst-case containsAll scan order.
|
||||
*/
|
||||
public static List<Integer> buildForwardList(int b) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
for (int i = 0; i < b; i++) list.add(i);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reversed list: [B-1, B-2, ..., 0].
|
||||
* Use as b2 — each element found at the far end of the forward b1 list.
|
||||
* This maximises the scan depth for each containsAll() lookup.
|
||||
*/
|
||||
public static List<Integer> buildReversedList(int b) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
for (int i = b - 1; i >= 0; i--) list.add(i);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue