whitepaper: re-add 10 missing entries + 11 new defects this session, count 578→590; rebuild PDF

This commit is contained in:
russell@unturf.com 2026-03-27 22:18:31 -04:00
parent e4ee168b1e
commit 2e4f7807d5
401 changed files with 3914 additions and 114 deletions

View file

@ -1,3 +1,4 @@
# UNDF: UNDF-2026-000000117
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/GraphUtils.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/GraphUtils.java
index 8620caf3..8c99c9ed 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/GraphUtils.java

View file

@ -1,3 +1,4 @@
# UNDF: UNDF-2026-000000118
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java
index f5e9bfcd..f4bb9a54 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java

View file

@ -1,3 +1,4 @@
# UNDF: UNDF-2026-000000119
diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java b/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java
index cebca6fb..5514eb20 100644
--- a/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java

View file

@ -1,3 +1,4 @@
# UNDF: UNDF-2026-000000120
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java
index 48f29c2a..841b18d1 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java

View file

@ -1,3 +1,4 @@
# UNDF: UNDF-2026-000000121
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java
index 8fc316c8..66a8e35a 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java

View file

@ -0,0 +1,54 @@
# UNDF: UNDF-2026-000000122
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
@@ -3231,11 +3231,13 @@ public List<MethodSymbol> interfaceCandidates(Type site, MethodSymbol ms) {
CandidatesCache.Entry e = candidatesCache.new Entry(site, ms);
List<MethodSymbol> candidates = candidatesCache.get(e);
if (candidates == null) {
Predicate<Symbol> filter = new MethodFilter(ms, site);
- List<MethodSymbol> candidates2 = List.nil();
+ LinkedHashSet<MethodSymbol> seen = new LinkedHashSet<>();
+ List<MethodSymbol> candidates2 = List.nil();
for (Symbol s : membersClosure(site, false).getSymbols(filter)) {
if (!site.tsym.isInterface() && !s.owner.isInterface()) {
return List.of((MethodSymbol)s);
- } else if (!candidates2.contains(s)) {
- candidates2 = candidates2.prepend((MethodSymbol)s);
+ } else if (seen.add((MethodSymbol)s)) {
+ candidates2 = candidates2.prepend((MethodSymbol)s);
}
}
candidates = prune(candidates2);
# Also requires import:
# import java.util.LinkedHashSet; (already present in Types.java via java.util.*)
# CWE-407: O(S²) → O(S)
# Types.java line 3240 — interfaceCandidates
#
# DEFECTIVE:
# List<MethodSymbol> candidates2 = List.nil();
# for (Symbol s : membersClosure(...).getSymbols(filter)) {
# ...
# } else if (!candidates2.contains(s)) { // O(S) linear scan on javac List
# candidates2 = candidates2.prepend(...);
# }
#
# candidates2 is a singly-linked javac List<MethodSymbol>.
# List.contains() is O(S) — it walks every node.
# As symbols accumulate, the S-th symbol triggers a scan of S-1 elements.
# Total work: 1+2+...+S = O(S²).
#
# TRIGGER: deep diamond interface hierarchies — e.g., a class implementing
# two interfaces both extending a common generic interface with many method
# overloads. Each unique (site, method) pair is computed once (then cached),
# but with N classes × M methods the first-pass cost is O(N × M × S²).
#
# FIX: maintain a parallel LinkedHashSet<MethodSymbol> for O(1) duplicate
# detection. candidates2 is still built as a List (prepend) to preserve the
# existing ordering contract; seen handles the dedup guard.
#
# Complexity:
# Defective: O(S²) per (site, method) pair
# Fixed: O(S) per (site, method) pair

View file

@ -0,0 +1,45 @@
# UNDF: UNDF-2026-000000123
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java
@@ -290,9 +290,10 @@ void notifyChange(List<Type> inferredVars) {
InferenceException thrownEx = null;
+ List<Type> remainingVars = inferencevars.diff(inferredVars);
for (Map.Entry<FreeTypeListener, List<Type>> entry :
new LinkedHashMap<>(freeTypeListeners).entrySet()) {
- if (!Type.containsAny(entry.getValue(), inferencevars.diff(inferredVars))) {
+ if (!Type.containsAny(entry.getValue(), remainingVars)) {
try {
entry.getKey().typesInferred(this);
freeTypeListeners.remove(entry.getKey());
# CWE-407: O(L × N × M) → O(N×M + L×V) where V = entry.getValue() size
# InferenceContext.java line 294 — notifyChange
#
# DEFECTIVE:
# void notifyChange(List<Type> inferredVars) {
# for (Map.Entry<FreeTypeListener, List<Type>> entry : ...) {
# if (!Type.containsAny(entry.getValue(),
# inferencevars.diff(inferredVars))) { // ← O(N*M) per listener
#
# inferencevars.diff(inferredVars) calls List.diff() which iterates every element
# of inferredVars (M items) and for each does a linear scan of the current list
# (up to N items) — cost O(N × M). This is recomputed from scratch on EVERY
# iteration of the freeTypeListeners loop (L iterations).
# Total: O(L × N × M).
#
# N = inferencevars count (type variables in scope — can be 10100 in complex
# generic method calls with nested lambdas / multi-level bounded wildcards).
# M = inferredVars count (newly resolved variables — often ≈ N in final round).
# L = freeTypeListeners count (listeners registered per inference variable —
# can be O(N) during complex overload resolution in generic API chains).
#
# This hits hard on codebases like Spring / Guava / RxJava where deeply nested
# generic method calls stack up many inference contexts.
#
# FIX: hoist diff() out of the loop. The result does not change between
# iterations (neither inferencevars nor inferredVars mutate during the loop).
#
# Complexity:
# Defective: O(L × N × M) per notifyChange call
# Fixed: O(N×M + L×V) per notifyChange call (V = avg entry.getValue() size)