58 lines
2 KiB
Markdown
58 lines
2 KiB
Markdown
# 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).
|