python / python/cpython

multiprocessing.shared_memory: failed attach unlinks another process's block

Ouverte
#153,279 0 commentaires 1 réaction 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

SharedMemory.__init__ calls self.unlink() from its OSError cleanup handler:

try:
    if create and size:
        os.ftruncate(self._fd, size)
    stats = os.fstat(self._fd)
    size = stats.st_size
    self._mmap = mmap.mmap(self._fd, size)
except OSError:
    self.unlink()
    raise

This runs unconditionally, including on the attach path (create=False).
unlink() calls shm_unlink(), which permanently destroys the named block.
So if mmap() fails while attaching to a block created by another process
(e.g. ENOMEM under memory pressure), the failing attach destroys another
owner's live shared memory block
.

Reproduction (simulating an mmap failure during attach):

from unittest import mock
from multiprocessing import shared_memory

owner = shared_memory.SharedMemory(create=True, size=1024)
try:
    with mock.patch("multiprocessing.shared_memory.mmap.mmap",
                    side_effect=OSError("ENOMEM")):
        shared_memory.SharedMemory(owner.name)   # attach
except OSError:
    pass

shared_memory.SharedMemory(owner.name)   # FileNotFoundError: block destroyed

Secondary issue: resource_tracker.register() runs after this try/except, so
on the create=True path the block is not yet registered. unlink() still
calls resource_tracker.unregister(), so the resource_tracker does
cache[rtype].remove(name) on an unknown name → KeyError printed as a
traceback, with the tracker's exit code set to 3.

Expected behavior

A failed attach must not unlink a block it does not own. On error the fd should
just be closed; the block should be unlinked only when it was created in this
call, and without a spurious unregister for a never-registered block.

Your environment

  • CPython main (3.16.0a0); also affects earlier versions
  • Linux / POSIX shared memory (_USE_POSIX)
Linked PRs
  • gh-153280

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.shared_memory.SharedMemory.init et reproduisez l’échec de attach avec le mock montré dans l’issue. Vérifiez le comportement du cleanup et du resource-tracker pour les chemins d’attach et de create. C’est terminé lorsqu’un attach échoué laisse le bloc existant utilisable et ne produit pas d’erreur parasite du tracker ; l’issue inclut la PR liée gh-153280.

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

Évaluation

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

Recevez les nouvelles issues par e-mail

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