Skip to content

Commit 9cf49aa

Browse files
miss-islingtonalbanDblurb-it[bot]pitrou
authored
[3.12] gh-77377: Ensure multiprocessing SemLock is valid for spawn-based Process before serializing it (GH-107275) (#108377)
gh-77377: Ensure multiprocessing SemLock is valid for spawn-based Process before serializing it (GH-107275) Ensure multiprocessing SemLock is valid for spawn Process before serializing it. Creating a multiprocessing SemLock with a fork context, and then trying to pass it to a spawn-created Process, would segfault if not detected early. --------- (cherry picked from commit 1700d34) Co-authored-by: albanD <[email protected]> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Antoine Pitrou <[email protected]>
1 parent 3aa7df6 commit 9cf49aa

File tree

3 files changed

+30
-2
lines changed

3 files changed

+30
-2
lines changed

Lib/multiprocessing/synchronize.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ class SemLock(object):
5050
def __init__(self, kind, value, maxvalue, *, ctx):
5151
if ctx is None:
5252
ctx = context._default_context.get_context()
53-
name = ctx.get_start_method()
54-
unlink_now = sys.platform == 'win32' or name == 'fork'
53+
self.is_fork_ctx = ctx.get_start_method() == 'fork'
54+
unlink_now = sys.platform == 'win32' or self.is_fork_ctx
5555
for i in range(100):
5656
try:
5757
sl = self._semlock = _multiprocessing.SemLock(
@@ -103,6 +103,11 @@ def __getstate__(self):
103103
if sys.platform == 'win32':
104104
h = context.get_spawning_popen().duplicate_for_child(sl.handle)
105105
else:
106+
if self.is_fork_ctx:
107+
raise RuntimeError('A SemLock created in a fork context is being '
108+
'shared with a process in a spawn context. This is '
109+
'not supported. Please use the same context to create '
110+
'multiprocessing objects and Process.')
106111
h = sl.handle
107112
return (h, sl.kind, sl.maxvalue, sl.name)
108113

Lib/test/_test_multiprocessing.py

+22
Original file line numberDiff line numberDiff line change
@@ -5383,6 +5383,28 @@ def test_preload_resources(self):
53835383
print(err)
53845384
self.fail("failed spawning forkserver or grandchild")
53855385

5386+
@unittest.skipIf(sys.platform == "win32",
5387+
"Only Spawn on windows so no risk of mixing")
5388+
@only_run_in_spawn_testsuite("avoids redundant testing.")
5389+
def test_mixed_startmethod(self):
5390+
# Fork-based locks cannot be used with spawned process
5391+
for process_method in ["spawn", "forkserver"]:
5392+
queue = multiprocessing.get_context("fork").Queue()
5393+
process_ctx = multiprocessing.get_context(process_method)
5394+
p = process_ctx.Process(target=close_queue, args=(queue,))
5395+
err_msg = "A SemLock created in a fork"
5396+
with self.assertRaisesRegex(RuntimeError, err_msg):
5397+
p.start()
5398+
5399+
# non-fork-based locks can be used with all other start methods
5400+
for queue_method in ["spawn", "forkserver"]:
5401+
for process_method in multiprocessing.get_all_start_methods():
5402+
queue = multiprocessing.get_context(queue_method).Queue()
5403+
process_ctx = multiprocessing.get_context(process_method)
5404+
p = process_ctx.Process(target=close_queue, args=(queue,))
5405+
p.start()
5406+
p.join()
5407+
53865408

53875409
@unittest.skipIf(sys.platform == "win32",
53885410
"test semantics don't make sense on Windows")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Ensure that multiprocessing synchronization objects created in a fork context are not sent to a different process created in a spawn context. This changes a segfault into an actionable RuntimeError in the parent process.

0 commit comments

Comments
 (0)