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:
parent
0a580b313d
commit
db29a08762
1311 changed files with 371202 additions and 1188 deletions
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue