python / python/cpython

Data race in the `codec.errors` setter (`codecctx_errors_set`) on a shared stateful codec

Ouverte
#152,767 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

extension-modules topic-free-threading 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:
Bug description:

In the free-threaded build, the codecctx_errors_set decrefs the old handler(ERROR_DECREF(self->errors)) and stores the new one (self->errors = cb) without any synchronization

https://github.com/python/cpython/blob/ecdef1773006529b0fea6639d0effeecbb41679c/Modules/cjkcodecs/multibytecodec.c#L170-L197

For any handler name other than the strict/ignore/replace sentinels (e.g. backslashreplace), self->errors holds a real refcounted PyUnicode.

The decref-then-assign is not atomic, so concurrent codec.errors = drops references incorrectly and can free a handler while it is still referenced.

Reproducer:

import codecs
import random
from threading import Thread
shared = codecs.getincrementalencoder('shift_jis')()
NAMES = ['backslashreplace', 'xmlcharrefreplace', 'namereplace']

def thread1():
    for _ in range(20000):
        try:
            shared.errors = random.choice(NAMES)
        except Exception:
            pass

if __name__ == "__main__":
    threads = [Thread(target=thread1) for _ in range(8)]
    for t in threads: t.start()
    for t in threads: t.join()

TSAN Report:

==================
WARNING: ThreadSanitizer: data race (pid=3576762)
  Read of size 8 at 0x7fffb65a1cc0 by thread T2:
    #0 codecctx_errors_set /cpython/./Modules/cjkcodecs/multibytecodec.c:194:5 
    #1 getset_set /cpython/Objects/descrobject.c:250:16 
    #2 _PyObject_GenericSetAttrWithDict /cpython/Objects/object.c:2049:19
    #3 PyObject_GenericSetAttr /cpython/Objects/object.c:2120:12
    #4 PyObject_SetAttr /cpython/Objects/object.c:1533:15
    #5 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:12146:27 
...

  Previous write of size 8 at 0x7fffb65a1cc0 by thread T1:
    #0 codecctx_errors_set /cpython/./Modules/cjkcodecs/multibytecodec.c:195:18
    #1 getset_set /cpython/Objects/descrobject.c:250:16 
    #2 _PyObject_GenericSetAttrWithDict /cpython/Objects/object.c:2049:19
    #3 PyObject_GenericSetAttr /cpython/Objects/object.c:2120:12 
    #4 PyObject_SetAttr /cpython/Objects/object.c:1533:15 
    #5 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:12146:27 
...

SUMMARY: ThreadSanitizer: data race /cpython/./Modules/cjkcodecs/multibytecodec.c:194:5 in codecctx_errors_set
==================
CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs
  • gh-153000

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 dans Modules/cjkcodecs/multibytecodec.c, au niveau de codecctx_errors_set, puis exécutez le reproducer avec threads fourni avec le free-threaded build sous ThreadSanitizer. Comparez le comportement avec le PR lié gh-153000 ; c’est terminé lorsque les affectations concurrentes de codec.errors ne produisent plus la race signalée ni un comportement incorrect concernant la durée de vie du handler.

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

Évaluation

Stack technique
c, python
Domaine
backend
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
À l'abandon
Clarté
Clairement spécifiée
Accessibilité débutants
30/100

Recevez les nouvelles issues par e-mail

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