java-topology/defects/bazel/patch/bazel-0003-feature-selection-hashset.md

58 lines
2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UNDF: UNDF-2026-000000581
# bazel-0003: FeatureSelection ImmutableList.contains O(P×S×L) → O(P×S) with HashSet
## Classification
| Field | Value |
|-------------|-------|
| CWE | CWE-407 Inefficient Algorithmic Complexity |
| Severity | MEDIUM |
| Component | `src/main/java/com/google/devtools/build/lib/rules/cpp/FeatureSelection.java:159` |
| Function | `FeatureSelection.run()` — provides-conflict check |
| Hot path | Once per action type per C++ target in `computeFeatureConfiguration()` |
| Status | PATCHED (unit test PASS) |
## Defect
`FeatureSelection.run()` iterates over `provides.keys()` (P unique provide-strings) and
for each iterates `provides.get(provided)` (S selectables), calling
`enabledActivatablesInOrder.contains(...)` — an O(L) scan of an `ImmutableList`:
```java
// FeatureSelection.java:159
ImmutableList<CrosstoolSelectable> enabledActivatablesInOrder = ...; // L entries
for (String provided : provides.keys()) { // P provide-strings
for (CrosstoolSelectable selectable : provides.get(provided)) { // S selectables
if (enabledActivatablesInOrder.contains( // O(L) linear scan
selectableProvidingString)) {
...
}
}
}
```
`ImmutableList.contains()` is O(L) — walks every element. With P=7, S=6, L=80:
**~3,360 comparisons per call** vs ~42 with a HashSet (80×).
`computeFeatureConfiguration()` is called once per action type per target in C++ builds.
Large monorepo builds with thousands of C++ targets hit this path repeatedly.
## Fix
Build a `HashSet<CrosstoolSelectable>` from `enabledActivatablesInOrder` once before the
outer loop:
```java
Set<CrosstoolSelectable> enabledSet = new HashSet<>(enabledActivatablesInOrder);
for (String provided : provides.keys()) {
for (CrosstoolSelectable selectable : provides.get(provided)) {
if (enabledSet.contains(selectableProvidingString)) { // O(1)
...
}
}
}
```
Speedup: ~80× at realistic scale (L=80, P=7, S=6).