Repository navigation
Off-by-one error in Lib/multiprocessing/util.py _SUN_PATH_MAX calculation causes forkserver OSError: AF_UNIX path too long #140734
Copy link
Copy link
Closed
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixesOS-linuxstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-multiprocessingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Bug report
Bug description:
This test case fails with OSError: AF_UNIX path too long on Linux if the adjustment argument is 0, and succeeds if the adjustment argument is 1:
#!/usr/bin/env python3.14
import multiprocessing
import os
import sys
from multiprocessing.util import _SUN_PATH_MAX
def target():
print("fork was successful")
def run_proc(adjustment):
os.environ["TMPDIR"] = (
"/tmp/" + (_SUN_PATH_MAX - len("/tmp/") - 14 - 14 - adjustment) * "X"
)
os.makedirs(os.environ["TMPDIR"], exist_ok=True)
print("TMPDIR length", len(os.environ["TMPDIR"]))
proc = multiprocessing.Process(target=target)
proc.start()
try:
proc.join()
finally:
try:
os.rmdir(os.environ["TMPDIR"])
except OSError:
pass
def main(argv):
adjustment = int(argv[1])
run_proc(adjustment)
if __name__ == "__main__":
main(sys.argv)Test results:
$ for adjustment in 0 1; do ./forkserver_bug.py $adjustment; done
TMPDIR length 80
Traceback (most recent call last):
File "/home/zmedico/./forkserver_bug.py", line 37, in <module>
main(sys.argv)
~~~~^^^^^^^^^^
File "/home/zmedico/./forkserver_bug.py", line 33, in main
run_proc(adjustment)
~~~~~~~~^^^^^^^^^^^^
File "/home/zmedico/./forkserver_bug.py", line 21, in run_proc
proc.start()
~~~~~~~~~~^^
File "/usr/lib/python3.14/multiprocessing/process.py", line 121, in start
self._popen = self._Popen(self)
~~~~~~~~~~~^^^^^^
File "/usr/lib/python3.14/multiprocessing/context.py", line 224, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/usr/lib/python3.14/multiprocessing/context.py", line 300, in _Popen
return Popen(process_obj)
File "/usr/lib/python3.14/multiprocessing/popen_forkserver.py", line 35, in __init__
super().__init__(process_obj)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/usr/lib/python3.14/multiprocessing/popen_fork.py", line 20, in __init__
self._launch(process_obj)
~~~~~~~~~~~~^^^^^^^^^^^^^
File "/usr/lib/python3.14/multiprocessing/popen_forkserver.py", line 51, in _launch
self.sentinel, w = forkserver.connect_to_new_process(self._fds)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
File "/usr/lib/python3.14/multiprocessing/forkserver.py", line 89, in connect_to_new_process
self.ensure_running()
~~~~~~~~~~~~~~~~~~~^^
File "/usr/lib/python3.14/multiprocessing/forkserver.py", line 157, in ensure_running
listener.bind(address)
~~~~~~~~~~~~~^^^^^^^^^
OSError: AF_UNIX path too long
TMPDIR length 79
fork was successfulI think this would fix it for Linux, but I'm not sure about other platforms:
--- a/Lib/multiprocessing/util.py
+++ b/Lib/multiprocessing/util.py
@@ -176,5 +176,5 @@ def _get_base_temp_dir(tempfile):
# len(base_tempdir + '/pymp-XXXXXXXX' + '/sock-XXXXXXXX')
sun_path_len = len(base_tempdir) + 14 + 14
- if sun_path_len <= _SUN_PATH_MAX:
+ if sun_path_len < _SUN_PATH_MAX:
return base_tempdir
# Fallback to the default system-wide temporary directory.
@@ -202,5 +202,5 @@ def _get_base_temp_dir(tempfile):
warn("Ignoring user-defined temporary directory: %s", base_tempdir)
# at most max(map(len, dirlist)) + 14 + 14 = 36 characters
- assert len(base_system_tempdir) + 14 + 14 <= _SUN_PATH_MAX
+ assert len(base_system_tempdir) + 14 + 14 < _SUN_PATH_MAX
return base_system_tempdirCPython versions tested on:
3.14
Operating systems tested on:
Linux
Linked PRs
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixesOS-linuxstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-multiprocessingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Activity
sergey-miryanov commentedon Oct 29, 2025
@zmedico Do you want to prepare a PR?
picnixz commentedon Oct 29, 2025
Thanks for catching this. Out of curiosity, was it an issue in practice?
thesamesam commentedon Oct 29, 2025
It was! See https://bugs.gentoo.org/965213.
picnixz commentedon Oct 29, 2025
Thank you. But in your case it would still be an issue as now the restriction is even stricter, right?
thesamesam commentedon Oct 29, 2025
I don't think so - with the fixed length, the code from #134085 will fallback correctly to another tempdir, right? It's just that it didn't account for a path that is on the boundary.
picnixz commentedon Oct 29, 2025
I forgot about my own fallback :') I think for BSD* systems, 104 also includes a null termination so other nix-based distros should be fine (after the fix).
picnixz commentedon Oct 29, 2025
I'm going to work on this one but won't be able to fix until this w-e (anyway, the next release is in 2 months and this isn't enough for a quick release). The patch is really easy but I want an additional test but the tests are a bit too intricate.
YvesDup commentedon Oct 29, 2025
Run perfectly on MacOSX regardless of
adjustmentvaluepicnixz commentedon Oct 29, 2025
For macOS, _SUN_PATH_MAX should be 92 I guess as it was the most conservative estimate for POSIX systems. If the real limit is above, then it won't be an issue indeed.
YvesDup commentedon Oct 29, 2025
For macOS, _SUN_PATH_MAX is 92.
picnixz commentedon Oct 29, 2025
Yes, but the real bound may be different. I couldn't find documentation telling me what the exact value is so I took the most conservative one. If your kernel implementation uses another value (maybe 108), then you won't see the crash.
If you want to check your runtime
_SUN_PATH_MAX, try to change that limit until when the reproducer fails.picnixz commentedon Nov 2, 2025
I gave up on testing this. It's too annoying and the tests wouldn't really be that interesting. Anyone can add testing in a follow-up PR though.
gh-140734: fix off-by-one error when comparing to `_SUN_PATH_MAX` (#1…
pythongh-140734: fix off-by-one error when comparing to `_SUN_PATH_MA…
pythongh-140734: fix off-by-one error when comparing to `_SUN_PATH_MA…
[3.13] gh-140734: fix off-by-one error when comparing to `_SUN_PATH_M…
[3.14] gh-140734: fix off-by-one error when comparing to `_SUN_PATH_M…
picnixz commentedon Nov 7, 2025
Thanks for the report!
thesamesam commentedon Nov 7, 2025
Thank you!
pythongh-140734: fix off-by-one error when comparing to `_SUN_PATH_MA…