Fix crash on graph cycle in configuration loading
PiperOrigin-RevId: 153473961
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index f572c26..fe5b1d4 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -1048,10 +1048,15 @@
EvaluationResult<ConfigurationCollectionValue> result =
buildDriver.evaluate(Arrays.asList(skyKey), keepGoing, DEFAULT_THREAD_COUNT, eventHandler);
if (result.hasError()) {
- Throwable e = result.getError(skyKey).getException();
+ ErrorInfo error = result.getError(skyKey);
+ Throwable e = error.getException();
// Wrap loading failed exceptions
if (e instanceof NoSuchThingException) {
e = new InvalidConfigurationException(e);
+ } else if (e == null && !Iterables.isEmpty(error.getCycleInfo())) {
+ getCyclesReporter().reportCycles(error.getCycleInfo(), skyKey, eventHandler);
+ e = new InvalidConfigurationException(
+ "cannot load build configuration because of this cycle");
}
Throwables.propagateIfInstanceOf(e, InvalidConfigurationException.class);
throw new IllegalStateException(
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationTest.java b/src/test/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationTest.java
index d273f8c..fe17b47 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationTest.java
@@ -26,6 +26,8 @@
import com.google.devtools.build.lib.analysis.util.ConfigurationTestCase;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.RepositoryName;
+import com.google.devtools.build.lib.packages.NoSuchPackageException;
+import com.google.devtools.build.lib.packages.NoSuchTargetException;
import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
import com.google.devtools.build.lib.rules.java.JavaConfiguration;
import com.google.devtools.build.lib.rules.objc.J2ObjcConfiguration;
@@ -372,4 +374,60 @@
BuildConfiguration cfg = createHost("--define=foo=bar");
assertThat(cfg.getCommandLineBuildVariables().get("foo")).isEqualTo("bar");
}
+
+ /**
+ * Returns a mock config fragment that loads the given label and does nothing else.
+ */
+ private static ConfigurationFragmentFactory createMockFragmentWithLabelDep(final String label) {
+ return new ConfigurationFragmentFactory() {
+ @Override
+ public Fragment create(ConfigurationEnvironment env, BuildOptions buildOptions)
+ throws InvalidConfigurationException, InterruptedException {
+ try {
+ env.getTarget(Label.parseAbsoluteUnchecked(label));
+ } catch (NoSuchPackageException e) {
+ fail("cannot load mock fragment's dep label " + label + ": " + e.getMessage());
+ } catch (NoSuchTargetException e) {
+ fail("cannot load mock fragment's dep label " + label + ": " + e.getMessage());
+ }
+ return new Fragment() {};
+ }
+
+ @Override
+ public Class<? extends Fragment> creates() {
+ return CppConfiguration.class;
+ }
+
+ @Override
+ public ImmutableSet<Class<? extends FragmentOptions>> requiredOptions() {
+ return ImmutableSet.<Class<? extends FragmentOptions>>of();
+ }
+ };
+ }
+
+ @Test
+ public void depLabelCycleOnConfigurationLoading() throws Exception {
+ configurationFactory =
+ new ConfigurationFactory(
+ analysisMock.createConfigurationCollectionFactory(),
+ createMockFragmentWithLabelDep("//foo"));
+ getScratch().file("foo/BUILD",
+ "load('//skylark:one.bzl', 'one')",
+ "cc_library(name = 'foo')");
+ getScratch().file("skylark/BUILD");
+ getScratch().file("skylark/one.bzl",
+ "load('//skylark:two.bzl', 'two')",
+ "def one():",
+ " pass");
+ getScratch().file("skylark/two.bzl",
+ "load('//skylark:one.bzl', 'one')",
+ "def two():",
+ " pass");
+ checkError(String.join("\n",
+ "ERROR <no location>: cycle detected in extension files: ",
+ " foo/BUILD",
+ ".-> //skylark:one.bzl",
+ "| //skylark:two.bzl",
+ "`-- //skylark:one.bzl"));
+ }
}