Skip to content

Commit 607bd0a

Browse files
committed
fix(zipapp): store _solib shared libraries as files, not absolute symlinks
Since #4165, the zipper keeps a symlink for an input whose original source is a symlink, looking through the absolute symlink the Bazel sandbox exposes the input as. For the `_solib` entries Bazel creates for shared libraries, the original source is itself an absolute symlink into the build machine's output base, so the zipapp stored entries like runfiles/_main/_solib_x86_64/libST-..._Slibgrpc.so -> /home/<user>/.cache/bazel/<hash>/execroot/_main/bazel-out/.../libgrpc.so which dangle on any other machine. Any zipapp whose Python code loads a shared library from `_solib` (a C extension that links a `cc_library` dynamically, or `libpython` for an extension that links it) fails to load it outside the machine that built it. Before #4165 these files were copied. To fix, only keep the looked-through target when it is relative, e.g. `libpython3.10.so -> libpython3.10.so.1.0` inside the runtime, which is what the size optimization in #4165 is for. Otherwise the file is stored. * Adds a zipper test with the `_solib` shape: a sandbox symlink to an absolute symlink to the library. It fails without the fix ("should NOT be a symlink but is").
1 parent fc7dc41 commit 607bd0a

3 files changed

Lines changed: 40 additions & 1 deletion

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
(zipapp) Shared libraries that a {obj}`py_zipapp_binary` reaches through
2+
Bazel's `_solib` symlinks are stored as files again, instead of as symlinks to
3+
absolute paths in the build machine's output base that dangle wherever the
4+
zipapp runs.

‎tests/tools/zipapp/zipper_test.py‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,36 @@ def test_create_zip_with_sandboxed_source_symlink(tmp_path):
174174
assert_zip_file_content(zf, "runfiles/my_ws/bin/python3.14", content="python")
175175

176176

177+
def test_create_zip_with_sandboxed_absolute_source_symlink(tmp_path):
178+
# Bazel's _solib entries are absolute symlinks into the output base. Their
179+
# target only exists on the build machine, so the file must be stored.
180+
manifest_path = tmp_path / "manifest.txt"
181+
output_zip = tmp_path / "output.zip"
182+
183+
library_dir = tmp_path / "external"
184+
library_dir.mkdir()
185+
library = library_dir / "libfoo.so"
186+
library.write_text("library")
187+
188+
solib_dir = tmp_path / "solib"
189+
solib_dir.mkdir()
190+
solib_link = solib_dir / "libfoo.so"
191+
solib_link.symlink_to(library)
192+
193+
sandbox_dir = tmp_path / "sandbox"
194+
sandbox_dir.mkdir()
195+
sandbox_link = sandbox_dir / "libfoo.so"
196+
sandbox_link.symlink_to(solib_link)
197+
manifest_path.write_text(f"rf-file|0|_solib/libfoo.so|{sandbox_link}")
198+
199+
create_zip(manifest_path, output_zip)
200+
201+
with zipfile.ZipFile(output_zip, "r") as zf:
202+
assert_zip_file_content(
203+
zf, "runfiles/my_ws/_solib/libfoo.so", content="library"
204+
)
205+
206+
177207
def test_pathsep_normalization(tmp_path):
178208
manifest_path = tmp_path / "manifest.txt"
179209
output_zip = tmp_path / "output.zip"

‎tools/zipapp/zipper.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,13 @@ def _source_symlink_target(content_path, is_symlink_str):
130130

131131
# Bazel sandboxes expose regular inputs as absolute symlinks. Look through
132132
# that indirection to detect whether the original source is also a symlink.
133+
# Only a relative link can be kept: an absolute one points into this
134+
# machine's Bazel output base (e.g. the _solib links Bazel creates for shared
135+
# libraries) and would dangle wherever the zipapp runs, so store the file.
133136
if os.path.islink(target):
134-
return os.readlink(target)
137+
source_target = os.readlink(target)
138+
if not os.path.isabs(source_target):
139+
return source_target
135140
return None
136141

137142

0 commit comments

Comments
 (0)