Skip to content

Commit 7f6c54d

Browse files
committed
dont bother checking undefined symbols for macho
1 parent 112c505 commit 7f6c54d

File tree

1 file changed

+50
-57
lines changed

1 file changed

+50
-57
lines changed

tests/venv_site_packages_libs/shared_lib_loading_test.py

Lines changed: 50 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,16 @@
44

55
from elftools.elf.elffile import ELFFile
66
from macholib import mach_o
7-
from macholib import SymbolTable
87
from macholib.MachO import MachO
98

9+
ELF_MAGIC = b"\x7fELF"
10+
MACHO_MAGICS = (
11+
b"\xce\xfa\xed\xfe", # 32-bit big-endian
12+
b"\xcf\xfa\xed\xfe", # 64-bit big-endian
13+
b"\xfe\xed\xfa\xce", # 32-bit little-endian
14+
b"\xfe\xed\xfa\xcf", # 64-bit little-endian
15+
)
16+
1017

1118
class SharedLibLoadingTest(unittest.TestCase):
1219
def test_shared_library_linking(self):
@@ -18,6 +25,8 @@ def test_shared_library_linking(self):
1825
self.fail(f"Import failed and could not find module spec: {e}")
1926

2027
info = self._get_linking_info(spec.origin)
28+
29+
# Give a useful error message for debugging.
2130
self.fail(
2231
f"Failed to import adder extension.\n"
2332
f"Original error: {e}\n"
@@ -34,9 +43,9 @@ def test_shared_library_linking(self):
3443
with open(adder_path, "rb") as f:
3544
magic_bytes = f.read(4)
3645

37-
if magic_bytes == b"\x7fELF":
46+
if magic_bytes == ELF_MAGIC:
3847
self._assert_elf_linking(adder_path)
39-
elif magic_bytes in (b"\xce\xfa\xed\xfe", b"\xcf\xfa\xed\xfe", b"\xfe\xed\xfa\xce", b"\xfe\xed\xfa\xcf"):
48+
elif magic_bytes in MACHO_MAGICS:
4049
self._assert_macho_linking(adder_path)
4150
else:
4251
self.fail(f"Unsupported file format for adder: magic bytes {magic_bytes!r}")
@@ -46,76 +55,60 @@ def test_shared_library_linking(self):
4655

4756
def _get_linking_info(self, path):
4857
"""Parses a shared library and returns its rpaths and dependencies."""
49-
info = {"rpaths": [], "needed": []}
5058
path = os.path.realpath(path)
5159
with open(path, "rb") as f:
5260
magic_bytes = f.read(4)
5361

54-
if magic_bytes == b"\x7fELF":
55-
with open(path, "rb") as f:
56-
elf = ELFFile(f)
57-
dynamic = elf.get_section_by_name(".dynamic")
58-
if not dynamic:
59-
return info
62+
if magic_bytes == ELF_MAGIC:
63+
return self._get_elf_info(path)
64+
elif magic_bytes in MACHO_MAGICS:
65+
return self._get_macho_info(path)
66+
return {}
67+
68+
def _get_elf_info(self, path):
69+
"""Extracts linking information from an ELF file."""
70+
info = {"rpaths": [], "needed": [], "undefined_symbols": []}
71+
with open(path, "rb") as f:
72+
elf = ELFFile(f)
73+
dynamic = elf.get_section_by_name(".dynamic")
74+
if dynamic:
6075
for tag in dynamic.iter_tags():
6176
if tag.entry.d_tag == "DT_NEEDED":
6277
info["needed"].append(tag.needed)
6378
elif tag.entry.d_tag in ("DT_RPATH", "DT_RUNPATH"):
6479
info["rpaths"].append(tag.rpath)
65-
elif magic_bytes in (b"\xce\xfa\xed\xfe", b"\xcf\xfa\xed\xfe", b"\xfe\xed\xfa\xce", b"\xfe\xed\xfa\xcf"):
66-
macho = MachO(path)
67-
for header in macho.headers:
68-
for cmd_load, cmd, data in header.commands:
69-
if cmd_load.cmd == mach_o.LC_LOAD_DYLIB:
70-
info["needed"].append(data.decode().strip("\x00"))
71-
elif cmd_load.cmd == mach_o.LC_RPATH:
72-
info["rpaths"].append(data.decode().strip("\x00"))
80+
81+
dynsym = elf.get_section_by_name(".dynsym")
82+
if dynsym:
83+
info["undefined_symbols"] = [
84+
s.name
85+
for s in dynsym.iter_symbols()
86+
if s.entry["st_shndx"] == "SHN_UNDEF"
87+
]
88+
return info
89+
90+
def _get_macho_info(self, path):
91+
"""Extracts linking information from a Mach-O file."""
92+
info = {"rpaths": [], "needed": []}
93+
macho = MachO(path)
94+
for header in macho.headers:
95+
for cmd_load, cmd, data in header.commands:
96+
if cmd_load.cmd == mach_o.LC_LOAD_DYLIB:
97+
info["needed"].append(data.decode().strip("\x00"))
98+
elif cmd_load.cmd == mach_o.LC_RPATH:
99+
info["rpaths"].append(data.decode().strip("\x00"))
73100
return info
74101

75102
def _assert_elf_linking(self, path):
76103
"""Asserts dynamic linking properties for an ELF file."""
77-
with open(path, "rb") as f:
78-
elf = ELFFile(f)
79-
80-
# Check that the adder module depends on the increment library.
81-
needed = []
82-
dynamic_section = elf.get_section_by_name(".dynamic")
83-
self.assertIsNotNone(dynamic_section)
84-
for tag in dynamic_section.iter_tags("DT_NEEDED"):
85-
needed.append(tag.needed)
86-
self.assertIn("libincrement.so", needed)
87-
88-
# Check that the 'increment' symbol is undefined.
89-
dynsym_section = elf.get_section_by_name(".dynsym")
90-
self.assertIsNotNone(dynsym_section)
91-
undefined_symbols = [
92-
s.name
93-
for s in dynsym_section.iter_symbols()
94-
if s.entry["st_shndx"] == "SHN_UNDEF"
95-
]
96-
self.assertIn("increment", undefined_symbols)
104+
info = self._get_elf_info(path)
105+
self.assertIn("libincrement.so", info["needed"])
106+
self.assertIn("increment", info["undefined_symbols"])
97107

98108
def _assert_macho_linking(self, path):
99109
"""Asserts dynamic linking properties for a Mach-O file."""
100-
macho = MachO(path)
101-
102-
# Check dependency on the increment library.
103-
loaded_dylibs = [
104-
data.decode().strip("\x00")
105-
for header in macho.headers
106-
for cmd_load, cmd, data in header.commands
107-
if cmd_load.cmd == mach_o.LC_LOAD_DYLIB
108-
]
109-
self.assertIn("@rpath/libincrement.dylib", loaded_dylibs)
110-
111-
# Check that the 'increment' symbol is undefined.
112-
symtab = SymbolTable(macho)
113-
undefined_symbols = [
114-
s.n_name.decode()
115-
for s in symtab.nlists
116-
if s.n_type & 0x01 and s.n_sect == 0 # N_EXT and NO_SECT
117-
]
118-
self.assertIn("_increment", undefined_symbols)
110+
info = self._get_macho_info(path)
111+
self.assertIn("@rpath/libincrement.dylib", info["needed"])
119112

120113

121114
if __name__ == "__main__":

0 commit comments

Comments
 (0)