bazel query --output=xml: avoid iterating over all possible values for
attr = select({"a": LABEL_LIST, "b": LABEL_LIST, ...}). This can be
exponential (w.r.t. the # of select conditions) and produce OOMs.
--
MOS_MIGRATED_REVID=137200979
diff --git a/src/main/java/com/google/devtools/build/lib/packages/AggregatingAttributeMapper.java b/src/main/java/com/google/devtools/build/lib/packages/AggregatingAttributeMapper.java
index ae48fc4..2d9e4d4 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/AggregatingAttributeMapper.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/AggregatingAttributeMapper.java
@@ -153,14 +153,13 @@
}
/**
- * Returns all labels reachable via the given attribute. If a label is listed multiple times, each
- * instance appears in the returned list.
+ * Returns all labels reachable via the given attribute, with duplicate instances removed.
*
* @param includeSelectKeys whether to include config_setting keys for configurable attributes
*/
- public List<Label> getReachableLabels(String attributeName, boolean includeSelectKeys)
+ public Set<Label> getReachableLabels(String attributeName, boolean includeSelectKeys)
throws InterruptedException {
- final ImmutableList.Builder<Label> builder = ImmutableList.builder();
+ final ImmutableSet.Builder<Label> builder = ImmutableSet.<Label>builder();
visitLabels(getAttributeDefinition(attributeName), includeSelectKeys,
new AcceptsLabelAttribute() {
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/query2/output/XmlOutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/output/XmlOutputFormatter.java
index 2d7348f..fe1b706 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/output/XmlOutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/output/XmlOutputFormatter.java
@@ -16,6 +16,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.EnvironmentGroup;
@@ -131,8 +132,26 @@
elem = doc.createElement("rule");
elem.setAttribute("class", rule.getRuleClass());
for (Attribute attr : rule.getAttributes()) {
- Pair<Iterable<Object>, AttributeValueSource> values =
- getPossibleAttributeValuesAndSources(rule, attr);
+ Pair<Iterable<Object>, AttributeValueSource> values;
+ if (attr.getType().equals(BuildType.LABEL_LIST)) {
+ // Avoid iterating over all possible values for a configurable label list, since all we
+ // care about are the raw labels. This avoids potential memory overruns. For example,
+ // given select({":c": ["//a:one", "//a:two"], ":d": ["//a:two"]]}), all we really need is
+ // ["//a:one", "//a:two"]. We don't care how exactly what combination of labels gets
+ // selected.
+
+ // TODO(gregce): Expand this to all collection types (we don't do this for scalars because
+ // there's currently no syntax for expressing multiple scalar values). This unfortunately
+ // isn't trivial because Bazel's label visitation logic includes special methods built
+ // directly into Type.
+ values = Pair.<Iterable<Object>, AttributeValueSource>of(
+ ImmutableList.<Object>of(
+ AggregatingAttributeMapper.of(rule)
+ .getReachableLabels(attr.getName(), /*includeSelectKeys=*/false)),
+ AttributeValueSource.RULE);
+ } else {
+ values = getPossibleAttributeValuesAndSources(rule, attr);
+ }
if (values.second == AttributeValueSource.RULE || options.xmlShowDefaultValues) {
Element attrElem = createValueElement(doc, attr.getType(), values.first);
attrElem.setAttribute("name", attr.getName());