Hacktoberfest 2026: die Issues, die Maintainer für den Oktober markiert haben – offen und einsteigerfreundlich. Hacktoberfest-Issues durchsuchen

test_forkserver_sigkill: join() can return before the child sets the event

Offen Anfängerfreundlich
#160,295 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
2/5
Geschätzter Aufwand
1-3 Stunden
Anfängerfreundlichkeit
71/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Aktiv
Tech-Stack
python
Bereich
testing

Rechercherichtung

Lies Lib/test/_test_multiprocessing.py, insbesondere check_forkserver_death() und test_forkserver_sigkill; der Fehler besteht darin, dass join() zurückkehren kann, bevor der Child-Prozess das Event setzt, nachdem der Forkserver beendet wurde. Aktualisiere die Event-Prüfung so, dass sie mit einem Timeout wartet, und führe anschließend den gezielten Forkserver-Test aus. Fertig ist die Änderung, wenn der Test dem Child-Prozess Zeit gibt, das Event zu setzen, und weiterhin den erwarteten Exit-Code prüft.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

tests topic-multiprocessing type-bug

Bug report

Bug description:

test_forkserver_sigkill failed once during a full ./python.exe -m test -j0 run on my machine (macOS 27.0.1, Apple M3, pydebug build of main at 1705e512b30). The load average was around 65 at the time. It passes when run on its own.

test test.test_multiprocessing_forkserver.test_processes failed -- Traceback (most recent call last):
  File "Lib/test/_test_multiprocessing.py", line 1007, in test_forkserver_sigkill
    self.check_forkserver_death(signal.SIGKILL)
  File "Lib/test/_test_multiprocessing.py", line 997, in check_forkserver_death
    self.assertTrue(evt.is_set())
AssertionError: False is not true

(paths shortened)

This is the same failure as gh-78221 (bpo-34040). It was worked around in 2018 by shortening the child's delay relative to the parent's sleep (07888e1cce), but the race is still there.

check_forkserver_death() kills the forkserver right after starting the first process. After a SIGKILL, the forkserver can no longer report that child's exit status: proc.join() gets EOF on the status pipe, and Popen.poll() in Lib/multiprocessing/popen_forkserver.py sets returncode to 255 immediately. The child may still be running at that point. The test then checks evt.is_set(), which only passes if the child has set the event by then (within the 1 second sleep plus the time proc2 takes). The next line already accepts exit code 255 for the case where the forkserver was killed.

SIGINT is not affected: the forkserver ignores it, stays alive and reports the real exit code.

To reproduce it reliably, stop the first child with SIGSTOP for a few seconds after killing the forkserver:

Reproducer
import multiprocessing as mp, os, signal, threading, time
from multiprocessing.forkserver import _forkserver

def sleep_and_set(evt, delay=0.0):
    time.sleep(delay)
    evt.set()

if __name__ == '__main__':
    mp.set_start_method('forkserver')
    _forkserver.ensure_running()
    evt = mp.Event()
    proc = mp.Process(target=sleep_and_set, args=(evt, 0.5))
    proc.start()
    os.kill(_forkserver._forkserver_pid, signal.SIGKILL)
    # Simulate the child not getting CPU time for 3 seconds.
    os.kill(proc.pid, signal.SIGSTOP)
    threading.Timer(3.0, os.kill, (proc.pid, signal.SIGCONT)).start()
    time.sleep(1.0)
    proc.join()
    print(proc.exitcode, evt.is_set())  # 255 False
    print(evt.wait(60))                 # True: the child did run, later

Waiting for the event with a timeout, instead of checking it right after join(), fixes it.

The same code is in 3.13, 3.14 and 3.15.

CPython versions tested on:

CPython main branch

Operating systems tested on:

macOS, Linux

Linked PRs
  • gh-160296
Vorherrschende Sprache
Python
Sterne
77.7k
Forks
38.3k
Ø Merge
12 Std. 27 Min.
Gemergte PRs (30 T.)
645

Entwicklungsumgebung

In Codespaces öffnen

Startet den Dev-Container des Projekts im Browser, mit Ihrem eigenen GitHub-Konto.

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus python/cpython

Alle Issues in python/cpython

Ähnliche Issues

Weitere Issues zu Python

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.