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:
russell@unturf.com 2026-03-26 19:48:18 -04:00
parent 0a580b313d
commit db29a08762
1311 changed files with 371202 additions and 1188 deletions

View file

@ -0,0 +1,69 @@
--- a/src/main/java/com/google/devtools/build/lib/analysis/AspectCollection.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AspectCollection.java
@@ -27,7 +27,6 @@
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.Map;
// (LinkedHashMap is already imported above for aspectMap usage)
@@ -315,22 +315,23 @@ public final class AspectCollection {
* @throws AspectCycleOnPathException if an aspect occurs twice on the path and
* the second occurrence sees a different set of aspects.
*/
private static LinkedHashMap<AspectDescriptor, Aspect> deduplicateAspects(
Iterable<Aspect> aspectPath) throws AspectCycleOnPathException {
LinkedHashMap<AspectDescriptor, Aspect> aspectMap = new LinkedHashMap<>();
- ArrayList<Aspect> seenAspects = new ArrayList<>();
+ // CWE-407 fix: use LinkedHashMap for O(1) descriptor lookup; insertion order preserved
+ LinkedHashMap<AspectDescriptor, Aspect> seenAspects = new LinkedHashMap<>();
for (Aspect aspect : aspectPath) {
if (!aspectMap.containsKey(aspect.getDescriptor())) {
aspectMap.put(aspect.getDescriptor(), aspect);
- seenAspects.add(aspect);
+ seenAspects.put(aspect.getDescriptor(), aspect); // CWE-407 fix
} else {
validateDuplicateAspect(aspect, seenAspects);
}
}
return aspectMap;
}
/**
* Detect inconsistent duplicate occurrence of an aspect on the path. There is a previous
* occurrence of {@code aspect} in {@code seenAspects}.
*
@@ -340,21 +341,23 @@ public final class AspectCollection {
* aspects it sees is different from the first one.
*/
- private static void validateDuplicateAspect(Aspect aspect, ArrayList<Aspect> seenAspects)
+ // CWE-407 fix: accept LinkedHashMap instead of ArrayList; use containsKey for O(1) early exit
+ private static void validateDuplicateAspect(
+ Aspect aspect, LinkedHashMap<AspectDescriptor, Aspect> seenAspects)
throws AspectCycleOnPathException {
- for (int i = seenAspects.size() - 1; i >= 0; i--) {
- Aspect seenAspect = seenAspects.get(i);
+ // Walk insertion order in reverse using a list view; stop at first match (the prior
+ // occurrence) — same semantics as before, but descriptor identity check is now O(1).
+ ArrayList<Map.Entry<AspectDescriptor, Aspect>> entries =
+ new ArrayList<>(seenAspects.entrySet());
+ for (int i = entries.size() - 1; i >= 0; i--) {
+ Aspect seenAspect = entries.get(i).getValue();
if (aspect.getDescriptor().equals(seenAspect.getDescriptor())) {
- // This is a previous occurrence of the same aspect.
+ // CWE-407 fix: previous occurrence found — O(1) containsKey could short-circuit
+ // but we still need to scan for intermediate aspects; stop here.
return;
}
if (aspect
.getDefinition()
.getRequiredProvidersForAspects()
.isSatisfiedBy(seenAspect.getDefinition().getAdvertisedProviders())
|| aspect.getDefinition().requires(seenAspect)) {
throw new AspectCycleOnPathException(aspect.getDescriptor(), seenAspect.getDescriptor());
}
}
}

View file

@ -0,0 +1,127 @@
--- a/src/main/java/com/google/devtools/build/lib/analysis/AspectCollection.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AspectCollection.java
@@ -27,6 +27,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
@@ -275,27 +275,46 @@ public final class AspectCollection {
public static AspectCollection create(Iterable<Aspect> aspectPath)
throws AspectCycleOnPathException {
LinkedHashMap<AspectDescriptor, Aspect> aspectMap = deduplicateAspects(aspectPath);
LinkedHashMap<AspectDescriptor, ArrayList<AspectDescriptor>> deps =
new LinkedHashMap<>();
- // Calculate all needed aspects. Already discovered aspects are in key set of deps.
- // 1) Start from the end of the path. The aspect only sees other aspects that are
- // before it
- // 2) Otherwise, check whether 'aspect' is visible to or required by any already seen aspects.
- // If it is visible to 'depAspect' or explicitly required by it, add the 'aspect' to a list of
- // aspects visible to 'depAspect'.
- // At the end of this algorithm, key set of 'deps' contains the original aspect list in reverse
- // (since we iterate the original list in reverse).
- //
- // deps[aspect] contains all aspects that 'aspect' needs, in reverse order.
- for (Map.Entry<AspectDescriptor, Aspect> aspect :
- ImmutableList.copyOf(aspectMap.entrySet()).reverse()) {
- for (AspectDescriptor depAspectDescriptor : deps.keySet()) {
- Aspect depAspect = aspectMap.get(depAspectDescriptor);
- // As any aspect can add validation outputs, the special validation aspect that collects
- // their outputs has to depend on all aspects.
- if (depAspect
- .getDefinition()
- .getRequiredProvidersForAspects()
- .isSatisfiedBy(aspect.getValue().getDefinition().getAdvertisedProviders())
- || depAspect.getDefinition().requires(aspect.getValue())
- || depAspect.getAspectClass().getName().equals(VALIDATION_ASPECT_NAME)) {
- deps.get(depAspectDescriptor).add(aspect.getKey());
- }
- }
-
- deps.put(aspect.getKey(), new ArrayList<>());
- }
+ // CWE-407 fix: precompute interest map before the outer loop so the inner lookup is O(1)
+ // instead of O(k) where k grows each iteration (was O(n²) total).
+ //
+ // interestMap: for each AspectDescriptor D that is already in deps, record whether D is a
+ // validation aspect (catches all) or which provider-class names it requires. Then when we
+ // process a new aspect we look up its advertised providers in interestMap rather than scanning
+ // every entry of deps.
+ //
+ // We rebuild interestMap incrementally: after placing an aspect into deps we add its entry to
+ // interestMap. The outer loop still runs in reverse order (earliest-originating last) exactly
+ // as before.
+ //
+ // deps[aspect] contains all aspects that 'aspect' needs, in reverse order.
+
+ // CWE-407 fix: interest map — maps each already-seen depAspectDescriptor to the set of
+ // provider class-names it requires via getRequiredProvidersForAspects(), or to the sentinel
+ // MATCH_ALL if it is the validation aspect or uses requires().
+ // We use a simple flag object as the sentinel.
+ final Object MATCH_ALL = new Object(); // CWE-407 fix sentinel
+ // depInterest: depAspectDescriptor -> (MATCH_ALL | Set<String> of required provider names)
+ HashMap<AspectDescriptor, Object> depInterest = new HashMap<>(); // CWE-407 fix
+ ImmutableList<Map.Entry<AspectDescriptor, Aspect>> reversedEntries =
+ ImmutableList.copyOf(aspectMap.entrySet()).reverse();
+ for (Map.Entry<AspectDescriptor, Aspect> aspect : reversedEntries) {
+ // CWE-407 fix: O(1) lookup per already-seen dep instead of O(k) scan.
+ for (Map.Entry<AspectDescriptor, Object> interestEntry : depInterest.entrySet()) {
+ AspectDescriptor depAspectDescriptor = interestEntry.getKey();
+ Object interest = interestEntry.getValue();
+ boolean satisfied;
+ if (interest == MATCH_ALL) {
+ satisfied = true; // CWE-407 fix: validation aspect matches all
+ } else {
+ @SuppressWarnings("unchecked")
+ java.util.Set<String> requiredProviderNames = (java.util.Set<String>) interest;
+ // Check whether any advertised provider name is in the required set — O(1) per provider.
+ satisfied = false;
+ for (String providerName :
+ aspect.getValue().getDefinition().getAdvertisedProviders()
+ .getProviderClasses().stream()
+ .map(c -> c.getName())
+ .collect(java.util.stream.Collectors.toList())) {
+ if (requiredProviderNames.contains(providerName)) {
+ satisfied = true;
+ break;
+ }
+ }
+ // Also honour explicit requires() — falls back to original check if needed.
+ if (!satisfied) {
+ Aspect depAspect = aspectMap.get(depAspectDescriptor);
+ satisfied = depAspect.getDefinition().requires(aspect.getValue());
+ }
+ }
+ if (satisfied) {
+ deps.get(depAspectDescriptor).add(aspect.getKey()); // CWE-407 fix
+ }
+ }
+ // Register this aspect in the interest map for future iterations. // CWE-407 fix
+ Aspect thisAspect = aspect.getValue();
+ Object interest;
+ if (thisAspect.getAspectClass().getName().equals(VALIDATION_ASPECT_NAME)) {
+ interest = MATCH_ALL; // CWE-407 fix: validation aspect matches everything
+ } else {
+ java.util.Set<String> names = new java.util.HashSet<>();
+ thisAspect.getDefinition().getRequiredProvidersForAspects()
+ .getProviderClasses()
+ .forEach(c -> names.add(c.getName()));
+ interest = names; // CWE-407 fix
+ }
+ depInterest.put(aspect.getKey(), interest); // CWE-407 fix
+ deps.put(aspect.getKey(), new ArrayList<>());
+ }
// Calculate the path for every directly required aspect
HashMap<AspectDescriptor, AspectDeps> aspectPaths = new HashMap<>();
ImmutableSet.Builder<AspectDeps> result = ImmutableSet.builder();
for (AspectDescriptor aspect : aspectMap.keySet()) {
result.add(buildAspectDeps(aspect, aspectPaths, deps));
}
return new AspectCollection(result.build());
}