Make the Linux sandbox work with ActionInputs with absolute "exec paths".
Progress towards #3236.
RELNOTES: None.
PiperOrigin-RevId: 493542957
Change-Id: Iff396e77d7624bdb033b198068aa137397495db0
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
index 60cae3a..3da85cc 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
@@ -232,7 +232,11 @@
SandboxInputs inputs =
helpers.processInputFiles(
- context.getInputMapping(PathFragment.EMPTY_FRAGMENT), execRoot, execRoot, null);
+ context.getInputMapping(PathFragment.EMPTY_FRAGMENT),
+ execRoot,
+ execRoot,
+ ImmutableList.of(),
+ null);
SandboxOutputs outputs = helpers.getOutputs(spawn);
final Path sandboxConfigPath = sandboxPath.getRelative("sandbox.sb");
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/DockerSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/DockerSandboxedSpawnRunner.java
index dbd5679..de253b0 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/DockerSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/DockerSandboxedSpawnRunner.java
@@ -222,7 +222,11 @@
SandboxInputs inputs =
helpers.processInputFiles(
- context.getInputMapping(PathFragment.EMPTY_FRAGMENT), execRoot, execRoot, null);
+ context.getInputMapping(PathFragment.EMPTY_FRAGMENT),
+ execRoot,
+ execRoot,
+ ImmutableList.of(),
+ null);
SandboxOutputs outputs = helpers.getOutputs(spawn);
Duration timeout = context.getTimeout();
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java
index 7f95327..9c41e4f 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java
@@ -48,6 +48,7 @@
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.vfs.Root;
import com.google.devtools.build.lib.vfs.Symlinks;
import java.io.File;
import java.io.IOException;
@@ -128,6 +129,7 @@
private final boolean sandboxfsMapSymlinkTargets;
private final TreeDeleter treeDeleter;
private final Reporter reporter;
+ private final ImmutableList<Root> packageRoots;
/**
* Creates a sandboxed spawn runner that uses the {@code linux-sandbox} tool.
@@ -168,6 +170,7 @@
this.localEnvProvider = new PosixLocalEnvProvider(cmdEnv.getClientEnv());
this.treeDeleter = treeDeleter;
this.reporter = cmdEnv.getReporter();
+ this.packageRoots = cmdEnv.getPackageLocator().getPathEntries();
}
@Override
@@ -219,7 +222,11 @@
SandboxInputs inputs =
helpers.processInputFiles(
- context.getInputMapping(PathFragment.EMPTY_FRAGMENT), execRoot, execRoot, null);
+ context.getInputMapping(PathFragment.EMPTY_FRAGMENT),
+ execRoot,
+ execRoot,
+ packageRoots,
+ null);
SandboxOutputs outputs = helpers.getOutputs(spawn);
Duration timeout = context.getTimeout();
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java
index 42c46dc..21f8225 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.sandbox;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.ForbiddenActionInputException;
@@ -111,7 +112,11 @@
SandboxInputs inputs =
helpers.processInputFiles(
- context.getInputMapping(PathFragment.EMPTY_FRAGMENT), execRoot, execRoot, null);
+ context.getInputMapping(PathFragment.EMPTY_FRAGMENT),
+ execRoot,
+ execRoot,
+ ImmutableList.of(),
+ null);
SandboxOutputs outputs = helpers.getOutputs(spawn);
if (sandboxfsProcess != null) {
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java
index 67aa543..b8ae7e3 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java
@@ -20,6 +20,7 @@
import com.google.auto.value.AutoValue;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@@ -462,15 +463,49 @@
}
/**
+ * Returns the appropriate {@link RootedPath} for a Fileset symlink.
+ *
+ * <p>Filesets are weird because sometimes exec paths of the {@link ActionInput}s in them are not
+ * relative, as exec paths should be, but absolute and point to under one of the package roots. In
+ * order to handle this, if we find such an absolute exec path, we iterate over the package path
+ * entries to turn it into a {@link RootedPath}.
+ *
+ * <p>The inputs to this function should be symlinks that are contained within Filesets; in
+ * particular, this is different from "unresolved symlinks" in that Fileset contents are regular
+ * files (but implemented by symlinks in the output tree) whose contents matter and unresolved
+ * symlinks are symlinks for which the important content is the result of {@code readlink()}
+ */
+ private static RootedPath processFilesetSymlink(
+ PathFragment symlink, ImmutableList<Root> packageRoots) {
+ for (Root packageRoot : packageRoots) {
+ if (packageRoot.contains(symlink)) {
+ return RootedPath.toRootedPath(packageRoot, packageRoot.relativize(symlink));
+ }
+ }
+
+ throw new IllegalStateException(
+ String.format(
+ "absolute action input path '%s' not found under package roots",
+ symlink.getPathString()));
+ }
+
+ /**
* Returns the inputs of a Spawn as a map of PathFragments relative to an execRoot to paths in the
* host filesystem where the input files can be found.
*
+ * @param inputMap the map of action inputs and where they should be visible in the action
+ * @param execRootPath the exec root from the point of view of the Bazel server
+ * @param withinSandboxExecRootPath the exec root from within the sandbox (different from {@code
+ * execRootPath} because the sandbox does magic with fiile system namespaces)
+ * @param packageRoots the package path entries during this build
+ * @param sandboxSourceRoots the directory where source roots are mapped within the sandbox
* @throws IOException if processing symlinks fails
*/
public SandboxInputs processInputFiles(
Map<PathFragment, ActionInput> inputMap,
Path execRootPath,
Path withinSandboxExecRootPath,
+ ImmutableList<Root> packageRoots,
Path sandboxSourceRoots)
throws IOException {
Root withinSandboxExecRoot = Root.fromPath(withinSandboxExecRootPath);
@@ -503,7 +538,14 @@
if (actionInput instanceof EmptyActionInput) {
inputPath = null;
} else {
- inputPath = RootedPath.toRootedPath(execRoot, actionInput.getExecPath());
+ PathFragment execPath = actionInput.getExecPath();
+ if (execPath.isAbsolute()) {
+ // This happens for ActionInputs that are part of Filesets (see the Javadoc on
+ // processFilesetSymlink())
+ inputPath = processFilesetSymlink(actionInput.getExecPath(), packageRoots);
+ } else {
+ inputPath = RootedPath.toRootedPath(execRoot, actionInput.getExecPath());
+ }
}
inputFiles.put(pathFragment, inputPath);
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/WindowsSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/WindowsSandboxedSpawnRunner.java
index 2ccb7de..b3b2fac 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/WindowsSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/WindowsSandboxedSpawnRunner.java
@@ -15,6 +15,7 @@
package com.google.devtools.build.lib.sandbox;
import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.ActionInput;
@@ -71,7 +72,11 @@
SandboxInputs readablePaths =
helpers.processInputFiles(
- context.getInputMapping(PathFragment.EMPTY_FRAGMENT), execRoot, execRoot, null);
+ context.getInputMapping(PathFragment.EMPTY_FRAGMENT),
+ execRoot,
+ execRoot,
+ ImmutableList.of(),
+ null);
ImmutableSet.Builder<Path> writablePaths = ImmutableSet.builder();
writablePaths.addAll(getWritableDirs(execRoot, environment));
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
index fd65a37..2599bf0 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
@@ -19,6 +19,7 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.hash.HashCode;
import com.google.devtools.build.lib.actions.ActionExecutionMetadata;
@@ -187,7 +188,11 @@
Profiler.instance().profile(ProfilerTask.WORKER_SETUP, "Setting up inputs")) {
inputFiles =
helpers.processInputFiles(
- context.getInputMapping(PathFragment.EMPTY_FRAGMENT), execRoot, execRoot, null);
+ context.getInputMapping(PathFragment.EMPTY_FRAGMENT),
+ execRoot,
+ execRoot,
+ ImmutableList.of(),
+ null);
}
SandboxOutputs outputs = helpers.getOutputs(spawn);
diff --git a/src/test/java/com/google/devtools/build/lib/sandbox/SandboxHelpersTest.java b/src/test/java/com/google/devtools/build/lib/sandbox/SandboxHelpersTest.java
index eb5e370..dc81f1d 100644
--- a/src/test/java/com/google/devtools/build/lib/sandbox/SandboxHelpersTest.java
+++ b/src/test/java/com/google/devtools/build/lib/sandbox/SandboxHelpersTest.java
@@ -101,7 +101,8 @@
UTF_8);
SandboxInputs inputs =
- sandboxHelpers.processInputFiles(inputMap(paramFile), execRootPath, execRootPath, null);
+ sandboxHelpers.processInputFiles(
+ inputMap(paramFile), execRootPath, execRootPath, ImmutableList.of(), null);
assertThat(inputs.getFiles())
.containsExactly(PathFragment.create("paramFile"), execRootedPath("paramFile"));
@@ -121,7 +122,8 @@
PathFragment.create("_bin/say_hello"));
SandboxInputs inputs =
- sandboxHelpers.processInputFiles(inputMap(tool), execRootPath, execRootPath, null);
+ sandboxHelpers.processInputFiles(
+ inputMap(tool), execRootPath, execRootPath, ImmutableList.of(), null);
assertThat(inputs.getFiles())
.containsExactly(PathFragment.create("_bin/say_hello"), execRootedPath("_bin/say_hello"));
@@ -167,14 +169,15 @@
try {
var unused =
sandboxHelpers.processInputFiles(
- inputMap(input), customExecRoot, customExecRoot, null);
+ inputMap(input), customExecRoot, customExecRoot, ImmutableList.of(), null);
finishProcessingSemaphore.release();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
});
var unused =
- sandboxHelpers.processInputFiles(inputMap(input), customExecRoot, customExecRoot, null);
+ sandboxHelpers.processInputFiles(
+ inputMap(input), customExecRoot, customExecRoot, ImmutableList.of(), null);
finishProcessingSemaphore.release();
future.get();