Fix CommandLine class initialization deadlock.
https://github.com/bazelbuild/bazel/issues/21566#issuecomment-1983242695 shows a deadlock when initializing static variable `CommandLine.EMPTY` and another thread is initializing `CommandLine`'s subclass `AbstractCommandLine` because `CommandLine.EMPTY` is an instance of `AbstractCommandLine`.
Fixes https://github.com/bazelbuild/bazel/issues/21566.
Closes #21608.
PiperOrigin-RevId: 613736999
Change-Id: Iadb738b0a89f34cee9a03bc92b385fa7ab58c98f
diff --git a/src/main/java/com/google/devtools/build/lib/actions/CommandLine.java b/src/main/java/com/google/devtools/build/lib/actions/CommandLine.java
index 22e0f8a..6db5b04 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/CommandLine.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/CommandLine.java
@@ -25,11 +25,13 @@
/** A representation of a list of arguments. */
public abstract class CommandLine {
- public static final CommandLine EMPTY = new EmptyCommandLine();
+ public static CommandLine empty() {
+ return EmptyCommandLine.INSTANCE;
+ }
/** Returns a {@link CommandLine} backed by the given list of arguments. */
public static CommandLine of(ImmutableList<String> arguments) {
- return arguments.isEmpty() ? CommandLine.EMPTY : new SimpleCommandLine(arguments);
+ return arguments.isEmpty() ? empty() : new SimpleCommandLine(arguments);
}
/**
@@ -40,7 +42,7 @@
if (args.isEmpty()) {
return commandLine;
}
- if (commandLine == EMPTY) {
+ if (commandLine == EmptyCommandLine.INSTANCE) {
return CommandLine.of(args);
}
return new SuffixedCommandLine(args, commandLine);
@@ -126,6 +128,8 @@
throws CommandLineExpansionException, InterruptedException;
private static final class EmptyCommandLine extends AbstractCommandLine {
+ private static final EmptyCommandLine INSTANCE = new EmptyCommandLine();
+
@Override
public ImmutableList<String> arguments() {
return ImmutableList.of();
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java b/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java
index dca5aea..58fbae4 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java
@@ -526,10 +526,10 @@
if (!ruleContext.getRule().isAttrDefined("args", Type.STRING_LIST)) {
// Some non-_binary rules create RunfilesSupport instances; it is fine to not have an args
// attribute here.
- return CommandLine.EMPTY;
+ return CommandLine.empty();
}
ImmutableList<String> args = ruleContext.getExpander().withDataLocations().tokenized("args");
- return args.isEmpty() ? CommandLine.EMPTY : CommandLine.of(args);
+ return args.isEmpty() ? CommandLine.empty() : CommandLine.of(args);
}
private static ActionEnvironment computeActionEnvironment(RuleContext ruleContext)
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkCustomCommandLine.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkCustomCommandLine.java
index 335df8c..11e23a3 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkCustomCommandLine.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkCustomCommandLine.java
@@ -664,7 +664,7 @@
CommandLine build(boolean flagPerLine) {
if (arguments.isEmpty()) {
- return CommandLine.EMPTY;
+ return CommandLine.empty();
}
Object[] args = arguments.toArray();
return flagPerLine