Fold BazelCrashUtils.java into BugReport.java. There's no need to have both of these.
This was very tedious and a lot of care had to be done in order to avoid build-time cycles -- this is mostly due to the combination of (a) the serialization codebase's usage of BugReport and (b) the proliferation of '@AutoCodec' annotations.
Also, while I'm here, slightly improve readability of BugReport.java.
RELNOTES: None
PiperOrigin-RevId: 231241644
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index f3b2f13..74f885f 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -116,10 +116,21 @@
)
# I/O utilities.
+
+OUT_ERR_SRCS = [
+ "util/io/OutErr.java",
+ "util/io/LinePrefixingOutputStream.java",
+ "util/io/LineFlushingOutputStream.java",
+]
+
java_library(
name = "io",
- srcs = glob(["util/io/*.java"]),
+ srcs = glob(
+ ["util/io/*.java"],
+ exclude = OUT_ERR_SRCS,
+ ),
deps = [
+ ":out-err",
"//src/main/java/com/google/devtools/build/lib/clock",
"//src/main/java/com/google/devtools/build/lib/concurrent",
"//src/main/java/com/google/devtools/build/lib/profiler",
@@ -129,6 +140,11 @@
],
)
+java_library(
+ name = "out-err",
+ srcs = OUT_ERR_SRCS,
+)
+
# General utilities.
java_library(
name = "os_util",
@@ -210,6 +226,7 @@
"util/StringCanonicalizer.java",
"util/StringTrie.java",
"util/StringUtil.java",
+ "util/StringUtilities.java",
"util/VarInt.java",
],
),
@@ -271,6 +288,7 @@
srcs = [
"util/StringCanonicalizer.java",
"util/StringUtil.java",
+ "util/StringUtilities.java",
],
deps = [
"//src/main/java/com/google/devtools/build/lib/concurrent",
@@ -289,14 +307,10 @@
)
java_library(
- name = "crash-utils",
- srcs = [
- "util/BazelCrashUtils.java",
- "util/CustomExitCodePublisher.java",
- ],
+ name = "custom-exit-code-publisher",
+ srcs = ["util/CustomExitCodePublisher.java"],
deps = [
":exitcode-external",
- "//third_party:guava",
"//third_party:jsr305",
],
)
@@ -307,6 +321,7 @@
srcs = glob(["events/*.java"]),
deps = [
":io",
+ ":out-err",
"//src/main/java/com/google/devtools/build/lib/concurrent",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec",
"//src/main/java/com/google/devtools/build/lib/vfs",
@@ -609,6 +624,7 @@
],
exclude = [
"analysis/BuildInfo.java",
+ "analysis/BuildVersionInfo.java",
"analysis/ProviderCollection.java",
"analysis/TransitiveInfoProvider.java",
"analysis/config/BuildConfigurationOptionDetails.java",
@@ -629,6 +645,7 @@
":io",
":keep-going-option",
":os_util",
+ ":out-err",
":packages-internal",
":process_util",
":provider-collection",
@@ -903,10 +920,12 @@
":events",
":io",
":maven-connector",
+ ":out-err",
":packages-internal",
":runtime",
":skylark_semantics",
":skylarkinterface",
+ ":string_util",
":util",
"//src/java_tools/singlejar/java/com/google/devtools/build/zip",
"//src/main/java/com/google/devtools/build/lib/actions",
@@ -1174,7 +1193,9 @@
":exitcode-external",
":io",
":os_util",
+ ":out-err",
":runtime",
+ ":string_util",
":unix",
":util",
"//src/main/java/com/google/devtools/build/lib/clock",
@@ -1194,6 +1215,29 @@
)
java_library(
+ name = "bug-report",
+ srcs = ["bugreport/BugReport.java"],
+ deps = [
+ ":blaze-version-info",
+ ":custom-exit-code-publisher",
+ ":exitcode-external",
+ ":logging-util",
+ ":out-err",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ ],
+)
+
+java_library(
+ name = "logging-util",
+ srcs = ["util/LoggingUtil.java"],
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib/concurrent",
+ "//third_party:guava",
+ ],
+)
+
+java_library(
name = "runtime",
srcs = glob(
[
@@ -1213,14 +1257,17 @@
"server/signal/InterruptSignalHandler.java",
],
deps = [
+ ":bug-report",
":build-base",
":build-request-options",
":command-utils",
+ ":custom-exit-code-publisher",
":events",
":exitcode-external",
":io",
":keep-going-option",
":loading-phase-threads-option",
+ ":out-err",
":packages-internal",
":process_util",
":shared-base-rules",
@@ -1272,6 +1319,17 @@
],
)
+java_library(
+ name = "blaze-version-info",
+ srcs = [
+ "analysis/BlazeVersionInfo.java",
+ ],
+ deps = [
+ ":string_util",
+ "//third_party:guava",
+ ],
+)
+
merge_licenses(
name = "merge_licenses",
srcs = [
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/platform/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/platform/BUILD
index 3c2a22c..74c5adf 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/platform/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/platform/BUILD
@@ -21,6 +21,7 @@
deps = [
"//src/main/java/com/google/devtools/build/lib:packages",
"//src/main/java/com/google/devtools/build/lib:skylarkinterface",
+ "//src/main/java/com/google/devtools/build/lib:string_util",
"//src/main/java/com/google/devtools/build/lib:transitive-info-provider",
"//src/main/java/com/google/devtools/build/lib/concurrent",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization",
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BugReport.java b/src/main/java/com/google/devtools/build/lib/bugreport/BugReport.java
similarity index 62%
rename from src/main/java/com/google/devtools/build/lib/runtime/BugReport.java
rename to src/main/java/com/google/devtools/build/lib/bugreport/BugReport.java
index eb6c0a6..44fba2b 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BugReport.java
+++ b/src/main/java/com/google/devtools/build/lib/bugreport/BugReport.java
@@ -11,7 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.devtools.build.lib.runtime;
+package com.google.devtools.build.lib.bugreport;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
@@ -25,15 +25,16 @@
import java.io.PrintStream;
import java.util.Arrays;
import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.annotation.Nullable;
/**
- * Utility methods for sending bug reports.
+ * Utility methods for handling crashes: we log the crash, optionally send a bug report, and then
+ * terminate the jvm.
*
- * <p> Note, code in this class must be extremely robust. There's nothing
- * worse than a crash-handler that itself crashes!
+ * <p> Note, code in this class must be extremely robust. There's nothing worse than a crash-handler
+ * that itself crashes!
*/
public abstract class BugReport {
@@ -43,15 +44,27 @@
private static BlazeVersionInfo versionInfo = BlazeVersionInfo.instance();
- private static BlazeRuntime runtime = null;
+ private static BlazeRuntimeInterface runtime = null;
- private static AtomicBoolean alreadyHandlingCrash = new AtomicBoolean(false);
+ @Nullable private static volatile Throwable unprocessedThrowableInTest = null;
+ private static final Object LOCK = new Object();
- private static final boolean IN_TEST =
- System.getenv("TEST_TMPDIR") != null
- && System.getenv("ENABLE_BUG_REPORT_LOGGING_IN_TEST") == null;
+ private static final boolean IN_TEST = System.getenv("TEST_TMPDIR") != null;
- public static void setRuntime(BlazeRuntime newRuntime) {
+ private static final boolean SHOULD_NOT_SEND_BUG_REPORT_BECAUSE_IN_TEST =
+ System.getenv("ENABLE_BUG_REPORT_LOGGING_IN_TEST") == null;
+
+ /**
+ * This is a narrow interface for {@link BugReport}'s usage of BlazeRuntime. It lives in this
+ * file, for the sake of avoiding a build-time cycle.
+ */
+ public interface BlazeRuntimeInterface {
+ String getProductName();
+ void notifyCommandComplete(int exitCode);
+ void shutdownOnCrash();
+ }
+
+ public static void setRuntime(BlazeRuntimeInterface newRuntime) {
Preconditions.checkNotNull(newRuntime);
Preconditions.checkState(runtime == null, "runtime already set: %s, %s", runtime, newRuntime);
runtime = newRuntime;
@@ -62,6 +75,24 @@
}
/**
+ * In tests, Runtime#halt is disabled. Thus, the main thread should call this method whenever it
+ * is about to block on thread completion that might hang because of a failed halt below.
+ */
+ public static void maybePropagateUnprocessedThrowableIfInTest() {
+ if (IN_TEST) {
+ // Instead of the jvm having been halted, we might have a saved Throwable.
+ synchronized (LOCK) {
+ Throwable lastUnprocessedThrowableInTest = unprocessedThrowableInTest;
+ unprocessedThrowableInTest = null;
+ if (lastUnprocessedThrowableInTest != null) {
+ Throwables.throwIfUnchecked(lastUnprocessedThrowableInTest);
+ throw new RuntimeException(lastUnprocessedThrowableInTest);
+ }
+ }
+ }
+ }
+
+ /**
* Logs the unhandled exception with a special prefix signifying that this was a crash.
*
* @param exception the unhandled exception to display.
@@ -69,7 +100,7 @@
* @param values Additional string values to clarify the exception.
*/
public static void sendBugReport(Throwable exception, List<String> args, String... values) {
- if (IN_TEST) {
+ if (SHOULD_NOT_SEND_BUG_REPORT_BECAUSE_IN_TEST) {
Throwables.throwIfUnchecked(exception);
throw new IllegalStateException(
"Bug reports in tests should crash: " + args + ", " + Arrays.toString(values), exception);
@@ -82,48 +113,80 @@
logException(exception, filterClientEnv(args), values);
}
- private static void logCrash(Throwable throwable, String... args) {
+ private static void logCrash(Throwable throwable, boolean sendBugReport, String... args) {
logger.severe("Crash: " + Throwables.getStackTraceAsString(throwable));
- BugReport.sendBugReport(throwable, Arrays.asList(args));
+ if (sendBugReport) {
+ BugReport.sendBugReport(throwable, Arrays.asList(args));
+ }
BugReport.printBug(OutErr.SYSTEM_OUT_ERR, throwable);
System.err.println("ERROR: " + getProductName() + " crash in async thread:");
throwable.printStackTrace();
}
/**
- * Print and send a bug report, and exit with the proper Blaze code. Does not exit if called a
- * second time. This method tries hard to catch any throwables thrown during its execution and
- * halts the runtime in that case.
+ * Print, log, send a bug report, and then cause the current Blaze command to fail with the
+ * specified exit code, and then cause the jvm to terminate.
+ *
+ * <p>Has no effect if another crash has already been handled by {@link BugReport}.
+ */
+ public static void handleCrashWithoutSendingBugReport(
+ Throwable throwable, int exitCode, String... args) {
+ handleCrash(throwable, /*sendBugReport=*/ false, Integer.valueOf(exitCode), args);
+ }
+
+ /**
+ * Print, log, send a bug report, and then cause the current Blaze command to fail with the
+ * specified exit code, and then cause the jvm to terminate.
+ *
+ * <p>Has no effect if another crash has already been handled by {@link BugReport}.
+ */
+ public static void handleCrash(Throwable throwable, int exitCode, String... args) {
+ handleCrash(throwable, /*sendBugReport=*/ true, Integer.valueOf(exitCode), args);
+ }
+
+ /**
+ * Print, log, and send a bug report, and then cause the current Blaze command to fail with an
+ * exit code inferred from the given {@link Throwable}, and then cause the jvm to terminate.
+ *
+ * <p>Has no effect if another crash has already been handled by {@link BugReport}.
*/
public static void handleCrash(Throwable throwable, String... args) {
- int exitCode = getExitCodeForThrowable(throwable).getNumericExitCode();
+ handleCrash(throwable, /*sendBugReport=*/ true, /*exitCode=*/ null, args);
+ }
+
+ private static void handleCrash(
+ Throwable throwable, boolean sendBugReport, @Nullable Integer exitCode, String... args) {
+ int exitCodeToUse = exitCode == null
+ ? getExitCodeForThrowable(throwable).getNumericExitCode()
+ : exitCode.intValue();
try {
- if (alreadyHandlingCrash.compareAndSet(false, true)) {
+ synchronized (LOCK) {
+ if (IN_TEST) {
+ unprocessedThrowableInTest = throwable;
+ }
+ logCrash(throwable, sendBugReport, args);
try {
- logCrash(throwable, args);
if (runtime != null) {
- runtime.notifyCommandComplete(exitCode);
+ runtime.notifyCommandComplete(exitCodeToUse);
// We don't call runtime#shutDown() here because all it does is shut down the modules,
// and who knows if they can be trusted. Instead, we call runtime#shutdownOnCrash()
// which attempts to cleanly shutdown those modules that might have something pending
// to do as a best-effort operation.
runtime.shutdownOnCrash();
}
- CustomExitCodePublisher.maybeWriteExitStatusFile(exitCode);
+ CustomExitCodePublisher.maybeWriteExitStatusFile(exitCodeToUse);
} finally {
// Avoid shutdown deadlock issues: If an application shutdown hook crashes, it will
// trigger our Blaze crash handler (this method). Calling System#exit() here, would
// therefore induce a deadlock. This call would block on the shutdown sequence completing,
// but the shutdown sequence would in turn be blocked on this thread finishing. Instead,
// exit fast via halt().
- Runtime.getRuntime().halt(exitCode);
+ Runtime.getRuntime().halt(exitCodeToUse);
}
- } else {
- logCrash(throwable, args);
}
} catch (Throwable t) {
System.err.println(
- "ERROR: An crash occurred while "
+ "ERROR: A crash occurred while "
+ getProductName()
+ " was trying to handle a crash! Please file a bug against "
+ getProductName()
@@ -135,7 +198,7 @@
System.err.println("Exception encountered during BugReport#handleCrash:");
t.printStackTrace(System.err);
- Runtime.getRuntime().halt(exitCode);
+ Runtime.getRuntime().halt(exitCodeToUse);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventservice/BUILD b/src/main/java/com/google/devtools/build/lib/buildeventservice/BUILD
index 5b00d29..523daf3 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventservice/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/buildeventservice/BUILD
@@ -27,6 +27,7 @@
":buildeventservice-options",
"//src/main/java/com/google/devtools/build/lib:events",
"//src/main/java/com/google/devtools/build/lib:io",
+ "//src/main/java/com/google/devtools/build/lib:out-err",
"//src/main/java/com/google/devtools/build/lib:runtime",
"//src/main/java/com/google/devtools/build/lib:util",
"//src/main/java/com/google/devtools/build/lib/authandtls",
diff --git a/src/main/java/com/google/devtools/build/lib/collect/nestedset/BUILD b/src/main/java/com/google/devtools/build/lib/collect/nestedset/BUILD
index a3d7752..d15b0bd 100644
--- a/src/main/java/com/google/devtools/build/lib/collect/nestedset/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/collect/nestedset/BUILD
@@ -19,7 +19,7 @@
"Order.java",
],
deps = [
- "//src/main/java/com/google/devtools/build/lib:crash-utils",
+ "//src/main/java/com/google/devtools/build/lib:bug-report",
"//src/main/java/com/google/devtools/build/lib:exitcode-external",
"//src/main/java/com/google/devtools/build/lib/collect/compacthashset",
"//src/main/java/com/google/devtools/build/lib/concurrent",
diff --git a/src/main/java/com/google/devtools/build/lib/collect/nestedset/NestedSet.java b/src/main/java/com/google/devtools/build/lib/collect/nestedset/NestedSet.java
index bb4abdd..e0516fe 100644
--- a/src/main/java/com/google/devtools/build/lib/collect/nestedset/NestedSet.java
+++ b/src/main/java/com/google/devtools/build/lib/collect/nestedset/NestedSet.java
@@ -22,10 +22,10 @@
import com.google.common.flogger.GoogleLogger;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.build.lib.collect.compacthashset.CompactHashSet;
import com.google.devtools.build.lib.concurrent.MoreFutures;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
-import com.google.devtools.build.lib.util.BazelCrashUtils;
import com.google.devtools.build.lib.util.ExitCode;
import com.google.protobuf.ByteString;
import java.util.AbstractCollection;
@@ -201,7 +201,7 @@
System.err.println(
"An interrupted exception occurred during nested set deserialization, "
+ "exiting abruptly.");
- BazelCrashUtils.halt(e, ExitCode.INTERRUPTED.getNumericExitCode());
+ BugReport.handleCrash(e, ExitCode.INTERRUPTED.getNumericExitCode());
throw new IllegalStateException("Server should have shut down.", e);
}
} else {
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
index fb5ebf2..52b8c17 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
@@ -24,6 +24,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Flushables;
import com.google.common.util.concurrent.UncheckedExecutionException;
+import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.build.lib.buildtool.buildevent.ProfilerStartedEvent;
import com.google.devtools.build.lib.clock.BlazeClock;
import com.google.devtools.build.lib.events.Event;
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
index 84af24a..5990bac 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
@@ -31,6 +31,7 @@
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory;
import com.google.devtools.build.lib.analysis.test.CoverageReportActionFactory;
+import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.build.lib.clock.BlazeClock;
import com.google.devtools.build.lib.clock.Clock;
import com.google.devtools.build.lib.events.Event;
@@ -125,7 +126,7 @@
*
* <p>The parts specific to the current command are stored in {@link CommandEnvironment}.
*/
-public final class BlazeRuntime {
+public final class BlazeRuntime implements BugReport.BlazeRuntimeInterface {
private static final Pattern suppressFromLog =
Pattern.compile("--client_env=([^=]*(?:auth|pass|cookie)[^=]*)=", Pattern.CASE_INSENSITIVE);
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java b/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java
index 0ae63e4..e9d33a3 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java
@@ -24,6 +24,7 @@
import com.google.devtools.build.lib.actions.ActionStatusMessage;
import com.google.devtools.build.lib.analysis.AnalysisPhaseCompleteEvent;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.build.lib.buildeventstream.AnnounceBuildEventTransportsEvent;
import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
import com.google.devtools.build.lib.buildeventstream.BuildEventTransportClosedEvent;
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/RetainedHeapLimiter.java b/src/main/java/com/google/devtools/build/lib/runtime/RetainedHeapLimiter.java
index 14490d7..4f288d3 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/RetainedHeapLimiter.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/RetainedHeapLimiter.java
@@ -15,6 +15,7 @@
package com.google.devtools.build.lib.runtime;
import com.google.common.base.Preconditions;
+import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.common.options.OptionsParsingException;
import com.sun.management.GarbageCollectionNotificationInfo;
import java.lang.management.GarbageCollectorMXBean;
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/BUILD b/src/main/java/com/google/devtools/build/lib/sandbox/BUILD
index bdbfc9a..935a8de 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/BUILD
@@ -20,6 +20,7 @@
"//src/main/java/com/google/devtools/build/lib:command-utils",
"//src/main/java/com/google/devtools/build/lib:events",
"//src/main/java/com/google/devtools/build/lib:io",
+ "//src/main/java/com/google/devtools/build/lib:out-err",
"//src/main/java/com/google/devtools/build/lib:process_util",
"//src/main/java/com/google/devtools/build/lib:runtime",
"//src/main/java/com/google/devtools/build/lib:util",
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/BUILD
index 1a01b9b..c327a73 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/BUILD
@@ -15,7 +15,7 @@
exclude = ["SerializationConstants.java"],
),
deps = [
- "//src/main/java/com/google/devtools/build/lib:crash-utils",
+ "//src/main/java/com/google/devtools/build/lib:bug-report",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec:registered-singleton",
"//src/main/java/com/google/devtools/build/lib/unsafe:string",
"//src/main/java/com/google/devtools/build/lib/unsafe:unsafe-provider",
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/SerializationContext.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/SerializationContext.java
index 9a89d6f..0ea80cd 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/SerializationContext.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/SerializationContext.java
@@ -22,9 +22,9 @@
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
+import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.build.lib.skyframe.serialization.Memoizer.Serializer;
import com.google.devtools.build.lib.skyframe.serialization.SerializationException.NoCodecException;
-import com.google.devtools.build.lib.util.BazelCrashUtils;
import com.google.protobuf.CodedOutputStream;
import java.io.IOException;
import java.util.ArrayList;
@@ -164,7 +164,7 @@
@Override
public void onFailure(Throwable t) {
- throw BazelCrashUtils.halt(t);
+ BugReport.handleCrash(t);
}
};
diff --git a/src/main/java/com/google/devtools/build/lib/util/BazelCrashUtils.java b/src/main/java/com/google/devtools/build/lib/util/BazelCrashUtils.java
deleted file mode 100644
index 6a7bfa9..0000000
--- a/src/main/java/com/google/devtools/build/lib/util/BazelCrashUtils.java
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2018 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.lib.util;
-
-import com.google.common.base.Throwables;
-import java.util.logging.Logger;
-import javax.annotation.Nullable;
-
-/** Utilities for crashing the jvm. */
-public class BazelCrashUtils {
- private static final Logger logger = Logger.getLogger(BazelCrashUtils.class.getName());
-
- private static final Object HALT_LOCK = new Object();
-
- @Nullable private static volatile Throwable unprocessedThrowableInTest = null;
-
- private BazelCrashUtils() {}
-
- /**
- * In tests, System.exit is disabled. Thus, the main thread should call this method whenever it is
- * about to block on thread completion that might hang because of a failed halt below.
- */
- public static void maybePropagateUnprocessedThrowableIfInTest() {
- synchronized (HALT_LOCK) {
- Throwable lastUnprocessedThrowableInTest = unprocessedThrowableInTest;
- unprocessedThrowableInTest = null;
- if (lastUnprocessedThrowableInTest != null) {
- Throwables.throwIfUnchecked(lastUnprocessedThrowableInTest);
- throw new RuntimeException(lastUnprocessedThrowableInTest);
- }
- }
- }
-
- /** Terminates the jvm with the exit code {@link ExitCode#BLAZE_INTERNAL_ERROR}. */
- public static RuntimeException halt(Throwable cause) {
- return halt(cause, ExitCode.BLAZE_INTERNAL_ERROR.getNumericExitCode());
- }
-
- /**
- * Terminates the jvm with the given {@code exitCode}. Note that, in server mode, the jvm's exit
- * code has nothing to do with the exit code picked by the blaze client, except as communicated by
- * the 'custom_exit_code_on_abrupt_exit' behavior. If this fails, the exit code picked by the
- * client will default to INTERNAL_ERROR.
- */
- public static RuntimeException halt(Throwable crash, int exitCode) {
- synchronized (HALT_LOCK) {
- try {
- logCrashDetails(crash);
- unprocessedThrowableInTest = crash;
- CustomExitCodePublisher.maybeWriteExitStatusFile(exitCode);
- } catch (OutOfMemoryError oom) {
- // In case we tried to halt with a non-OOM, but OOMed during the lead up to the halt.
- Runtime.getRuntime().halt(exitCode);
- } finally {
- doDie(crash, exitCode);
- }
- throw new IllegalStateException("impossible");
- }
- }
-
- private static void logCrashDetails(Throwable crash) {
- logger.severe(
- "About to call System#exit. Halt requested due to crash. See stderr for details ("
- + crash.getMessage()
- + ")");
- System.err.println("About to call System#exit. Halt requested due to crash");
- crash.printStackTrace();
- System.err.println("... called from");
- new Exception().printStackTrace();
- }
-
- private static void doDie(Throwable crash, int exitCode) {
- try {
- // Bypass shutdown hooks if we encountered an OOM, they're likely to take way too long to be
- // sensible to run in such a hostile environment.
- Throwable cause = crash;
- while (cause != null) {
- if (cause instanceof OutOfMemoryError) {
- Runtime.getRuntime().halt(exitCode);
- }
- cause = cause.getCause();
- }
- } finally {
- System.exit(exitCode);
- }
- }
-}