Fix `RemoteExternalOverlayFileSystem#resolveSymbolicLinks`
Ensures that the returned `Path` is still in the overlay file system.
Also make the error message emitted by `Path#checkSameFileSystem` more informative. This is motivated by and helped discover the above as the fix for the following crash observed when using the remote repo contents cache with an explicit `--sandbox_base`:
```
Caused by: java.lang.IllegalArgumentException: Files are on different filesystems: /dev/shm/bazel-sandbox.b10976335efa519b0184f3091ac8e21f7beefb92142303f9ab2c3341f45a2f28/linux-sandbox/18/execroot/_main/external/c-ares+/configs/ares_build.h (on com.google.devtools.build.lib.unix.UnixFileSystem@5e0a8154), /home/ubuntu/.cache/bazel/_bazel_ubuntu/123/execroot/_main/external/c-ares+/configs/ares_build.h (on com.google.devtools.build.lib.remote.RemoteExternalOverlayFileSystem@6cd9bfda)
at com.google.devtools.build.lib.vfs.Path.checkSameFileSystem(Path.java:964)
at com.google.devtools.build.lib.vfs.Path.createSymbolicLink(Path.java:523)
at com.google.devtools.build.lib.vfs.Path.createSymbolicLink(Path.java:535)
at com.google.devtools.build.lib.sandbox.SymlinkedSandboxedSpawn.copyFile(SymlinkedSandboxedSpawn.java:129)
```
Alternative to https://github.com/bazelbuild/bazel/pull/27721
Closes #27802.
PiperOrigin-RevId: 837832265
Change-Id: I3b73167496b011aef66954d59ca3804b4b64996f
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteExternalOverlayFileSystem.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteExternalOverlayFileSystem.java
index 99204b8..55bbc76 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteExternalOverlayFileSystem.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteExternalOverlayFileSystem.java
@@ -542,7 +542,8 @@
@Override
public Path resolveSymbolicLinks(PathFragment path) throws IOException {
- return fsForPath(path).resolveSymbolicLinks(path);
+ // Ensure that the return value doesn't leave the overlay file system.
+ return getPath(fsForPath(path).resolveSymbolicLinks(path).asFragment());
}
@Nullable
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/Path.java b/src/main/java/com/google/devtools/build/lib/vfs/Path.java
index 03a078d..d6f8f8f 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/Path.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/Path.java
@@ -895,7 +895,8 @@
private void checkSameFileSystem(Path that) {
if (this.fileSystem != that.fileSystem) {
throw new IllegalArgumentException(
- "Files are on different filesystems: " + this + ", " + that);
+ "Files are on different filesystems: %s (on %s), %s (on %s)"
+ .formatted(this, this.fileSystem, that, that.fileSystem));
}
}
}
diff --git a/src/test/py/bazel/bzlmod/remote_repo_contents_cache_test.py b/src/test/py/bazel/bzlmod/remote_repo_contents_cache_test.py
index 12bf9e2..c901e9b 100644
--- a/src/test/py/bazel/bzlmod/remote_repo_contents_cache_test.py
+++ b/src/test/py/bazel/bzlmod/remote_repo_contents_cache_test.py
@@ -482,7 +482,11 @@
with open(self.Path('bazel-bin/main/out.txt')) as f:
self.assertEqual(f.read(), 'hello')
- def testUseRepoFileInBuildRule_actionDoesNotUseCache(self):
+ def do_testUseRepoFileInBuildRule_actionDoesNotUseCache(
+ self, extra_flags=None
+ ):
+ if extra_flags is None:
+ extra_flags = []
self.ScratchFile(
'MODULE.bazel',
[
@@ -518,7 +522,7 @@
repo_dir = self.RepoDir('my_repo')
# First fetch: not cached
- _, _, stderr = self.RunBazel(['build', '//main:use_data'])
+ _, _, stderr = self.RunBazel(['build', '//main:use_data'] + extra_flags)
self.assertIn('JUST FETCHED', '\n'.join(stderr))
self.assertTrue(os.path.exists(os.path.join(repo_dir, 'BUILD')))
self.assertTrue(os.path.exists(os.path.join(repo_dir, 'data.txt')))
@@ -528,7 +532,7 @@
# After expunging: repo and build action cached
self.RunBazel(['clean', '--expunge'])
- _, _, stderr = self.RunBazel(['build', '//main:use_data'])
+ _, _, stderr = self.RunBazel(['build', '//main:use_data'] + extra_flags)
self.assertNotIn('JUST FETCHED', '\n'.join(stderr))
self.assertFalse(os.path.exists(os.path.join(repo_dir, 'BUILD')))
self.assertTrue(os.path.exists(os.path.join(repo_dir, 'data.txt')))
@@ -536,6 +540,17 @@
with open(self.Path('bazel-bin/main/out.txt')) as f:
self.assertEqual(f.read(), 'hello')
+ def testUseRepoFileInBuildRule_actionDoesNotUseCache(self):
+ self.do_testUseRepoFileInBuildRule_actionDoesNotUseCache()
+
+ def testUseRepoFileInBuildRule_actionDoesNotUseCache_withExplicitSandboxBase(
+ self,
+ ):
+ tmpdir = self.ScratchDir('sandbox_base')
+ self.do_testUseRepoFileInBuildRule_actionDoesNotUseCache(
+ extra_flags=['--sandbox_base=' + tmpdir]
+ )
+
def testLostRemoteFile_build(self):
# Create a repo with two BUILD files (one in a subpackage), build a target
# from one to cause it to be cached, then build that target again after