Skip to content

Commit f663aa2

Browse files
[3.14] gh-143706: Fix sys.argv not set during multiprocessing forkserver __main__ preload (GH-143717) (#143763)
gh-143706: Fix sys.argv not set during multiprocessing forkserver `__main__` preload (GH-143717) The forkserver was not passing sys.argv to its main() function, causing sys.argv to be empty during `__main__` module import in child processes. This fixes a non-obvious regression inadvertently introduced by the gh-126631 main preloading fix. (cherry picked from commit 298d544) Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com>
1 parent 110a77b commit f663aa2

File tree

4 files changed

+52
-1
lines changed

4 files changed

+52
-1
lines changed

Lib/multiprocessing/forkserver.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ def ensure_running(self):
152152
main_kws['sys_path'] = data['sys_path']
153153
if 'init_main_from_path' in data:
154154
main_kws['main_path'] = data['init_main_from_path']
155+
if 'sys_argv' in data:
156+
main_kws['sys_argv'] = data['sys_argv']
155157

156158
with socket.socket(socket.AF_UNIX) as listener:
157159
address = connection.arbitrary_address('AF_UNIX')
@@ -197,7 +199,7 @@ def ensure_running(self):
197199
#
198200

199201
def main(listener_fd, alive_r, preload, main_path=None, sys_path=None,
200-
*, authkey_r=None):
202+
*, sys_argv=None, authkey_r=None):
201203
"""Run forkserver."""
202204
if authkey_r is not None:
203205
try:
@@ -209,6 +211,8 @@ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None,
209211
authkey = b''
210212

211213
if preload:
214+
if sys_argv is not None:
215+
sys.argv[:] = sys_argv
212216
if sys_path is not None:
213217
sys.path[:] = sys_path
214218
if '__main__' in preload and main_path is not None:

Lib/test/_test_multiprocessing.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6939,6 +6939,26 @@ def test_preload_main(self):
69396939
out = out.decode().split("\n")
69406940
self.assertEqual(out, ['__main__', '__mp_main__', 'f', 'f', ''])
69416941

6942+
def test_preload_main_sys_argv(self):
6943+
# gh-143706: Check that sys.argv is set before __main__ is pre-loaded
6944+
if multiprocessing.get_start_method() != "forkserver":
6945+
self.skipTest("forkserver specific test")
6946+
6947+
name = os.path.join(os.path.dirname(__file__), 'mp_preload_sysargv.py')
6948+
_, out, err = test.support.script_helper.assert_python_ok(
6949+
name, 'foo', 'bar')
6950+
self.assertEqual(err, b'')
6951+
6952+
out = out.decode().split("\n")
6953+
expected_argv = "['foo', 'bar']"
6954+
self.assertEqual(out, [
6955+
f"module:{expected_argv}",
6956+
f"fun:{expected_argv}",
6957+
f"module:{expected_argv}",
6958+
f"fun:{expected_argv}",
6959+
'',
6960+
])
6961+
69426962
#
69436963
# Mixins
69446964
#

Lib/test/mp_preload_sysargv.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# gh-143706: Test that sys.argv is correctly set during main module import
2+
# when using forkserver with __main__ preloading.
3+
4+
import multiprocessing
5+
import sys
6+
7+
# This will be printed during module import - sys.argv should be correct here
8+
print(f"module:{sys.argv[1:]}")
9+
10+
def fun():
11+
# This will be printed when the function is called
12+
print(f"fun:{sys.argv[1:]}")
13+
14+
if __name__ == "__main__":
15+
ctx = multiprocessing.get_context("forkserver")
16+
ctx.set_forkserver_preload(['__main__'])
17+
18+
fun()
19+
20+
p = ctx.Process(target=fun)
21+
p.start()
22+
p.join()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fix :mod:`multiprocessing` forkserver so that :data:`sys.argv` is correctly
2+
set before ``__main__`` is preloaded. Previously, :data:`sys.argv` was empty
3+
during main module import in forkserver child processes. This fixes a
4+
regression introduced in 3.13.8 and 3.14.1. Root caused by Aaron Wieczorek,
5+
test provided by Thomas Watson, thanks!

0 commit comments

Comments
 (0)