python / python/cpython

multiprocessing.connection.Client deadlocks when trying to connect to a listener without a password

Ouverte
#123,736 6 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

stdlib topic-multiprocessing type-bug
Langage dominant
Python
Étoiles
77.2k
Forks
35.9k
Métriques de merge des PR
Métriques de PR en attente

Description

Bug report

Bug description:

We set up a multiprocessing.connection.Listener with no authkey. When we try to connect to it with a Client with an authkey, the Client deadlocks. Here is a working example:

import socket
import threading
import time
from multiprocessing.connection import Client, Listener


def _test(*, listener: str | None, client: str | None) -> tuple[Exception | None, Exception | None, list]:
    _autkey_listener = listener.encode() if listener else None
    _authkey_client = client.encode() if client else None

    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.bind(("localhost", 0))
        address = s.getsockname()

    thread_exc = None
    thread_got = []
    client_exc = None

    def target() -> None:
        try:
            with Listener(address, authkey=_autkey_listener) as l:
                c = l.accept()
                while True:
                    value = c.recv()
                    if not value:
                        break
                    thread_got.append(value)
        except Exception as e:
            nonlocal thread_exc
            thread_exc = e

    t = threading.Thread(target=target)
    t.start()

    try:
        with Client(address, authkey=_authkey_client) as c:
            c.send("hello")
            time.sleep(0.1)
            c.send(None)

        t.join()
    except Exception as e:
        client_exc = e

    return thread_exc, client_exc, thread_got


if __name__ == "__main__":
    print(" no passwords ".center(40, "-"))
    print(_test(listener=None, client=None))

    print(" two matching passwords ".center(40, "-"))
    print(_test(listener="password", client="password"))

    print(" client has wrong password ".center(40, "-"))
    print(_test(listener="password", client="wrong"))

    print(" client has no password ".center(40, "-"))
    print(_test(listener="password", client=None))

    # This is the case which deadlocks
    print(" listener has no password ".center(40, "-"))
    print(_test(listener=None, client="password"))

which outputs:

------------- no passwords -------------
(None, None, ['hello'])
-------- two matching passwords --------
(None, None, ['hello'])
------ client has wrong password -------
(AuthenticationError('digest received was wrong'), AuthenticationError('digest sent was rejected'), [])
-------- client has no password --------
(AuthenticationError("expected 'md5' of length 16 got 20"), None, [])
------- listener has no password -------

and then stops.

Upon some investigation, the following bit of code from Client is to blame:

  if authkey is not None:
      answer_challenge(c, authkey)
      deliver_challenge(c, authkey)

since the listener is not configured to deliver the challenge to the connections. I think this would be resolved with an optional timeout kwarg in answer_challenge. If this suggestion is accepted I would be very happy to work on it 👍

CPython versions tested on:

3.9, 3.10, 3.11, 3.12

Operating systems tested on:

macOS, Windows

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par multiprocessing.connection.Client et le chemin answer_challenge identifié dans le rapport, puis exécutez le reproducer fourni avec ses différentes combinaisons d’authentification. Le travail est terminé lorsque le cas listener-without-password et client-with-password ne se bloque plus, tandis que les autres cas signalés conservent les résultats démontrés.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
distributed-systems, networking
Type d'issue
Bug
Difficulté
3/5
Temps estimé
1-2 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
45/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.