Make sure runtime shuts down on exception in uncaught exception handler

RELNOTES:

--
MOS_MIGRATED_REVID=103869828
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 e714708..cf1d37e 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
@@ -35,6 +35,7 @@
 import com.google.common.eventbus.SubscriberExceptionHandler;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.Uninterruptibles;
+import com.google.devtools.build.lib.Constants;
 import com.google.devtools.build.lib.actions.cache.ActionCache;
 import com.google.devtools.build.lib.actions.cache.CompactPersistentActionCache;
 import com.google.devtools.build.lib.actions.cache.NullActionCache;
@@ -1407,7 +1408,20 @@
     Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
       @Override
       public void uncaughtException(Thread thread, Throwable throwable) {
-        BugReport.handleCrash(throwable, args);
+        try {
+          BugReport.handleCrash(throwable, args);
+        } catch (Throwable t) {
+          System.err.println("An exception was caught in " + Constants.PRODUCT_NAME + "'s "
+              + "UncaughtExceptionHandler, a bug report may not have been filed.");
+
+          System.err.println("Original uncaught exception:");
+          throwable.printStackTrace(System.err);
+
+          System.err.println("Exception encountered during UncaughtExceptionHandler:");
+          t.printStackTrace(System.err);
+
+          Runtime.getRuntime().halt(BugReport.getExitCodeForThrowable(throwable));
+        }
       }
     });
   }
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BugReport.java b/src/main/java/com/google/devtools/build/lib/runtime/BugReport.java
index 9c67eef..730e396 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BugReport.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BugReport.java
@@ -73,9 +73,7 @@
     BugReport.printBug(OutErr.SYSTEM_OUT_ERR, throwable);
     System.err.println("Blaze crash in async thread:");
     throwable.printStackTrace();
-    int exitCode =
-        (throwable instanceof OutOfMemoryError) ? ExitCode.OOM_ERROR.getNumericExitCode()
-            : ExitCode.BLAZE_INTERNAL_ERROR.getNumericExitCode();
+    int exitCode = getExitCodeForThrowable(throwable);
     if (runtime != null) {
       runtime.notifyCommandComplete(exitCode);
       // We don't call runtime#shutDown() here because all it does is shut down the modules, and who
@@ -88,6 +86,13 @@
     Runtime.getRuntime().halt(exitCode);
   }
 
+  /** Get exit code corresponding to throwable. */
+  public static int getExitCodeForThrowable(Throwable throwable) {
+    return (throwable instanceof OutOfMemoryError)
+        ? ExitCode.OOM_ERROR.getNumericExitCode()
+        : ExitCode.BLAZE_INTERNAL_ERROR.getNumericExitCode();
+  }
+
   private static void printThrowableTo(OutErr outErr, Throwable e) {
     PrintStream err = new PrintStream(outErr.getErrorStream());
     e.printStackTrace(err);