Create --debug_depset_depth debug mode
This debug mode will throw an exception on Starlark invocations to the depset constructor when the constructed depset would exceed the application depth limit (set by `--nested_set_depth_limit`). This mode effectively flattens each depset on creation, which is overall a *very* expensive operation, and should thus be done only for debugging purposes.
RELNOTES: None.
PiperOrigin-RevId: 281354629
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StarlarkSemanticsOptions.java b/src/main/java/com/google/devtools/build/lib/packages/StarlarkSemanticsOptions.java
index b0e2dc2..5f35aed 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/StarlarkSemanticsOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/StarlarkSemanticsOptions.java
@@ -64,6 +64,19 @@
// <== Add new options here in alphabetic order ==>
@Option(
+ name = "debug_depset_depth",
+ defaultValue = "false",
+ documentationCategory = OptionDocumentationCategory.STARLARK_SEMANTICS,
+ effectTags = {OptionEffectTag.BUILD_FILE_SEMANTICS},
+ metadataTags = {},
+ help =
+ "Enables an expensive additional check that causes depset construction to fail fast if "
+ + "the depset's depth would exceed the limit specified by "
+ + "`--nested_set_depth_limit`. Ordinarily this failure occurs only when the depset "
+ + "is flattened, which may be far from its point of creation.")
+ public boolean debugDepsetDepth;
+
+ @Option(
name = "experimental_action_args",
defaultValue = "false",
documentationCategory = OptionDocumentationCategory.STARLARK_SEMANTICS,
@@ -621,6 +634,7 @@
StarlarkSemantics semantics =
StarlarkSemantics.builder()
// <== Add new options here in alphabetic order ==>
+ .debugDepsetDepth(debugDepsetDepth)
.experimentalActionArgs(experimentalActionArgs)
.experimentalAllowIncrementalRepositoryUpdates(
experimentalAllowIncrementalRepositoryUpdates)
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
index e0b267d..b8f4332 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
@@ -1011,6 +1011,7 @@
StarlarkSemantics semantics)
throws EvalException {
Order order;
+ SkylarkNestedSet result;
try {
order = Order.parse(orderString);
} catch (IllegalArgumentException ex) {
@@ -1025,7 +1026,7 @@
}
direct = x;
}
- return depsetConstructor(direct, order, transitive, loc);
+ result = depsetConstructor(direct, order, transitive, loc);
} else {
if (x != Starlark.NONE) {
if (!isEmptySkylarkList(items)) {
@@ -1034,8 +1035,21 @@
}
items = x;
}
- return legacyDepsetConstructor(items, order, direct, transitive, loc);
+ result = legacyDepsetConstructor(items, order, direct, transitive, loc);
}
+
+ if (semantics.debugDepsetDepth()) {
+ // Flatten the underlying nested set. If the set exceeds the depth limit, then this will
+ // throw a NestedSetDepthException.
+ // This is an extremely inefficient check and should be only done in the
+ // "--debug_depset_depth" mode.
+ try {
+ result.getSet().toList();
+ } catch (NestedSetDepthException ex) {
+ throw new EvalException(null, "depset exceeded maximum depth " + ex.getDepthLimit());
+ }
+ }
+ return result;
}
private static SkylarkNestedSet depsetConstructor(
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkSemantics.java b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkSemantics.java
index 81ab452..7395bfc 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkSemantics.java
@@ -131,6 +131,8 @@
AutoValue_StarlarkSemantics.class;
// <== Add new options here in alphabetic order ==>
+ public abstract boolean debugDepsetDepth();
+
public abstract boolean experimentalActionArgs();
public abstract boolean experimentalAllowIncrementalRepositoryUpdates();
@@ -246,6 +248,7 @@
public static final StarlarkSemantics DEFAULT_SEMANTICS =
builder()
// <== Add new options here in alphabetic order ==>
+ .debugDepsetDepth(false)
.experimentalActionArgs(false)
.experimentalAllowTagsPropagation(false)
.experimentalAspectOutputPropagation(false)
@@ -295,6 +298,8 @@
public abstract static class Builder {
// <== Add new options here in alphabetic order ==>
+ public abstract Builder debugDepsetDepth(boolean value);
+
public abstract Builder experimentalActionArgs(boolean value);
public abstract Builder experimentalAllowIncrementalRepositoryUpdates(boolean value);
diff --git a/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java b/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
index 63ad8c8..11f9814 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
@@ -118,6 +118,7 @@
private static StarlarkSemanticsOptions buildRandomOptions(Random rand) throws Exception {
return parseOptions(
// <== Add new options here in alphabetic order ==>
+ "--debug_depset_depth=" + rand.nextBoolean(),
"--experimental_action_args=" + rand.nextBoolean(),
"--experimental_allow_incremental_repository_updates=" + rand.nextBoolean(),
"--experimental_aspect_output_propagation=" + rand.nextBoolean(),
@@ -171,6 +172,7 @@
private static StarlarkSemantics buildRandomSemantics(Random rand) {
return StarlarkSemantics.builder()
// <== Add new options here in alphabetic order ==>
+ .debugDepsetDepth(rand.nextBoolean())
.experimentalActionArgs(rand.nextBoolean())
.experimentalAllowIncrementalRepositoryUpdates(rand.nextBoolean())
.experimentalAspectOutputPropagation(rand.nextBoolean())
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java b/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java
index b289aa1..04cd324 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java
@@ -806,4 +806,18 @@
.testIfErrorContains("depset exceeded maximum depth 2000", "str(too_deep_depset)")
.testIfErrorContains("depset exceeded maximum depth 2000", "too_deep_depset.to_list()");
}
+
+ @Test
+ public void testDepsetDebugDepth() throws Exception {
+ NestedSet.setApplicationDepthLimit(2000);
+ new SkylarkTest("--debug_depset_depth=true")
+ .setUp(
+ "def create_depset(depth):",
+ " x = depset([0])",
+ " for i in range(1, depth):",
+ " x = depset([i], transitive = [x])",
+ " return x")
+ .testEval("str(create_depset(900))[0:6]", "'depset'")
+ .testIfErrorContains("depset exceeded maximum depth 2000", "create_depset(3000)");
+ }
}