Check if `treeDeleter` is actually async before casting it. Fixes #13240.
This code assumed that `registerSpawnStrategies` would be always be called before `afterCommand`, but that's not the case if the build was interrupted or failed before the execution phase.
RELNOTES: None.
PiperOrigin-RevId: 379937925
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java
index d64ebcd..4058f4b 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java
@@ -607,14 +607,17 @@
SandboxOptions options = env.getOptions().getOptions(SandboxOptions.class);
int asyncTreeDeleteThreads = options != null ? options.asyncTreeDeleteIdleThreads : 0;
- if (treeDeleter != null && asyncTreeDeleteThreads > 0) {
- // If asynchronous deletions were requested, they may still be ongoing so let them be: trying
- // to delete the base tree synchronously could fail as we can race with those other deletions,
- // and scheduling an asynchronous deletion could race with future builds.
- AsynchronousTreeDeleter treeDeleter =
- (AsynchronousTreeDeleter) checkNotNull(this.treeDeleter);
+
+ // If asynchronous deletions were requested, they may still be ongoing so let them be: trying
+ // to delete the base tree synchronously could fail as we can race with those other deletions,
+ // and scheduling an asynchronous deletion could race with future builds.
+ if (asyncTreeDeleteThreads > 0 && treeDeleter instanceof AsynchronousTreeDeleter) {
+ AsynchronousTreeDeleter treeDeleter = (AsynchronousTreeDeleter) this.treeDeleter;
treeDeleter.setThreads(asyncTreeDeleteThreads);
}
+ // `treeDeleter` might not be an AsynchronousTreeDeleter if the user changed the option but
+ // then interrupted the build before the start of the execution phase. But that's OK, there
+ // will be nothing new to delete. See #13240.
if (shouldCleanupSandboxBase) {
try {