Skip to content

Fix image base calculation for PyInstaller MacOS bundles - #858

Open
trisiak wants to merge 2 commits into
benfred:masterfrom
trisiak:pyinstaller-macos-image-base
Open

Fix image base calculation for PyInstaller MacOS bundles#858
trisiak wants to merge 2 commits into
benfred:masterfrom
trisiak:pyinstaller-macos-image-base

Conversation

@trisiak

@trisiak trisiak commented Jun 24, 2026

Copy link
Copy Markdown
  • support for attaching to PyInstaller onedir bundles (follow-up to Can't profile pyinstaller binaries on OSX #207?) which have multiple entries in their maps and the first one that was picked was just a stub; now scans for the magic string
  • while trying to make this work, the reported version was 0.0.0 so added an extra guard for obvious mistakes like that (like in py-spy dump not getting proper version information #845, which this likely closes); happy to drop that if it's too overeager in assuming that only Python 2 and Python 3 exist :-)

with this, I was able to connect to my bundled app

trisiak added 2 commits June 24, 2026 11:59
… map

On macOS, `PythonProcessInfo::new` used the first executable memory map
matching the libpython filename (`libmaps[0]`) as the dylib's load base,
and `parse_binary` slides every symbol/section address by that base.

With some dyld layouts — notably PyInstaller onedir bundles, where a
separate `libpythonX.Y.dylib` is loaded by the bootloader — small
executable stubs of the dylib are mapped at lower addresses than its
real `__TEXT` segment. `libmaps[0]` then points at a stub, not the image
base, so every symbol read lands on the wrong address: `Py_Version`
reads as 0 (yielding a bogus "0.0.0" and an "Unsupported version of
Python" error), and `_PyRuntime` / BSS lookups fail as well.

Pick the base by probing each candidate executable map for a Mach-O
magic at its start (the image header lives at the start of `__TEXT`),
falling back to the first map if none match so existing layouts are
unaffected. Linux and Windows paths are unchanged.
`get_python_version` returns immediately on the Py_Version symbol path,
even when the decoded result is nonsense (e.g. "0.0.0" from a misresolved
symbol address) and even propagating a read error with `?`. Either case
aborts detection before the sys.version string scan — which often still
succeeds — gets a chance.

Treat the Py_Version path as best-effort: ignore a read error, and only
short-circuit on a plausible decode (major 2 or 3); otherwise fall
through to the remaining strategies. Defense in depth alongside the
image-base fix.
@trisiak trisiak changed the title Adjust the PyInstaller MacOS image base Fix image base calculation for PyInstaller MacOS bundles Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant