python / python/cpython

Free threading: Data race on a socket's timeout

Ouverte
#153,935 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

3.14 3.15 3.16 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:

Created from gh-153852 TSAN-0035

sock->sock_timeout is a plain PyTime_t and have no synchronization. On the free-threaded build, using the same socket from multiple threads causes a c-level data race , reported by TSAN.

Repro:

import socket
import threading

s = socket.socket()
barrier = threading.Barrier(2)
N = 1000


def reader():
    barrier.wait()
    for _ in range(N):
        s.gettimeout()


def writer():
    barrier.wait()
    for _ in range(N):
        s.settimeout(1.0)


threads = [threading.Thread(target=reader), threading.Thread(target=writer)]
for t in threads:
    t.start()
for t in threads:
    t.join()
s.close()
print("done")

Output:

python.exe(20351,0x204cf7840) malloc: nano zone abandoned due to inability to reserve vm space.
==================
WARNING: ThreadSanitizer: data race (pid=20351)
  Read of size 8 at 0x00010e600198 by thread T1:
    #0 sock_gettimeout_method socketmodule.c:3320 (_socket.cpython-316t-darwin.so:arm64+0x84b8)
    #1 method_vectorcall_NOARGS descrobject.c:448 (python.exe:arm64+0x1000a0c94)
    #2 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x100088b88)
    #3 _Py_VectorCallInstrumentation_StackRefSteal ceval.c:768 (python.exe:arm64+0x100290b68)
    #4 _PyEval_EvalFrameDefault generated_cases.c.h:1906 (python.exe:arm64+0x100295bc8)
    #5 _PyEval_Vector ceval.c:2172 (python.exe:arm64+0x10029000c)
    #6 _PyFunction_Vectorcall call.c (python.exe:arm64+0x1000891e8)
    #7 _PyObject_VectorcallPrepend call.c:855 (python.exe:arm64+0x10008a984)
    #8 method_vectorcall classobject.c:55 (python.exe:arm64+0x10008de88)
    #9 context_run context.c:731 (python.exe:arm64+0x1002dff38)
    #10 method_vectorcall_FASTCALL_KEYWORDS descrobject.c:421 (python.exe:arm64+0x1000a0b7c)
    #11 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x100088b88)
    #12 _Py_VectorCallInstrumentation_StackRefSteal ceval.c:768 (python.exe:arm64+0x100290b68)
    #13 _PyEval_EvalFrameDefault generated_cases.c.h:1906 (python.exe:arm64+0x100295bc8)
    #14 _PyEval_Vector ceval.c:2172 (python.exe:arm64+0x10029000c)
    #15 _PyFunction_Vectorcall call.c (python.exe:arm64+0x1000891e8)
    #16 _PyObject_VectorcallPrepend call.c:855 (python.exe:arm64+0x10008a984)
    #17 method_vectorcall classobject.c:55 (python.exe:arm64+0x10008de88)
    #18 _PyObject_Call call.c:348 (python.exe:arm64+0x100088e48)
    #19 PyObject_Call call.c:373 (python.exe:arm64+0x100088ec0)
    #20 thread_run _threadmodule.c:388 (python.exe:arm64+0x1004582e0)
    #21 pythread_wrapper thread_pthread.h:234 (python.exe:arm64+0x10038fe08)

  Previous write of size 8 at 0x00010e600198 by thread T2:
    #0 sock_settimeout socketmodule.c:3264 (_socket.cpython-316t-darwin.so:arm64+0x83fc)
    #1 method_vectorcall_O descrobject.c:476 (python.exe:arm64+0x1000a0e38)
    #2 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x100088b88)
    #3 _Py_VectorCallInstrumentation_StackRefSteal ceval.c:768 (python.exe:arm64+0x100290b68)
    #4 _PyEval_EvalFrameDefault generated_cases.c.h:1906 (python.exe:arm64+0x100295bc8)
    #5 _PyEval_Vector ceval.c:2172 (python.exe:arm64+0x10029000c)
    #6 _PyFunction_Vectorcall call.c (python.exe:arm64+0x1000891e8)
    #7 _PyObject_VectorcallPrepend call.c:855 (python.exe:arm64+0x10008a984)
    #8 method_vectorcall classobject.c:55 (python.exe:arm64+0x10008de88)
    #9 context_run context.c:731 (python.exe:arm64+0x1002dff38)
    #10 method_vectorcall_FASTCALL_KEYWORDS descrobject.c:421 (python.exe:arm64+0x1000a0b7c)
    #11 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x100088b88)
    #12 _Py_VectorCallInstrumentation_StackRefSteal ceval.c:768 (python.exe:arm64+0x100290b68)
    #13 _PyEval_EvalFrameDefault generated_cases.c.h:1906 (python.exe:arm64+0x100295bc8)
    #14 _PyEval_Vector ceval.c:2172 (python.exe:arm64+0x10029000c)
    #15 _PyFunction_Vectorcall call.c (python.exe:arm64+0x1000891e8)
    #16 _PyObject_VectorcallPrepend call.c:855 (python.exe:arm64+0x10008a984)
    #17 method_vectorcall classobject.c:55 (python.exe:arm64+0x10008de88)
    #18 _PyObject_Call call.c:348 (python.exe:arm64+0x100088e48)
    #19 PyObject_Call call.c:373 (python.exe:arm64+0x100088ec0)
    #20 thread_run _threadmodule.c:388 (python.exe:arm64+0x1004582e0)
    #21 pythread_wrapper thread_pthread.h:234 (python.exe:arm64+0x10038fe08)

  Thread T1 (tid=28859963, running) created by main thread at:
    #0 pthread_create <null>:126882288 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x309d8)
    #1 do_start_joinable_thread thread_pthread.h:281 (python.exe:arm64+0x10038f000)
    #2 PyThread_start_joinable_thread thread_pthread.h:323 (python.exe:arm64+0x10038ee38)
    #3 ThreadHandle_start _threadmodule.c:475 (python.exe:arm64+0x10045809c)
    #4 do_start_new_thread _threadmodule.c:1919 (python.exe:arm64+0x100457b7c)
    #5 thread_PyThread_start_joinable_thread _threadmodule.c:2042 (python.exe:arm64+0x100456ae0)
    #6 cfunction_call methodobject.c:564 (python.exe:arm64+0x1001310f4)
    #7 _PyObject_MakeTpCall call.c:242 (python.exe:arm64+0x100087f70)
    #8 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x100088c28)
    #9 _Py_VectorCallInstrumentation_StackRefSteal ceval.c:768 (python.exe:arm64+0x100290b68)
    #10 _PyEval_EvalFrameDefault generated_cases.c.h:3474 (python.exe:arm64+0x100298e58)
    #11 PyEval_EvalCode ceval.c:679 (python.exe:arm64+0x10028fb74)
    #12 run_eval_code_obj pythonrun.c:1406 (python.exe:arm64+0x10036aea4)
    #13 run_mod pythonrun.c:1509 (python.exe:arm64+0x10036abd4)
    #14 _PyRun_SimpleFile pythonrun.c:544 (python.exe:arm64+0x100365d88)
    #15 _PyRun_AnyFile pythonrun.c:92 (python.exe:arm64+0x100365534)
    #16 Py_RunMain main.c:891 (python.exe:arm64+0x1003a7aec)
    #17 pymain_main main.c:921 (python.exe:arm64+0x1003a7f3c)
    #18 Py_BytesMain main.c:945 (python.exe:arm64+0x1003a8010)
    #19 main python.c:15 (python.exe:arm64+0x1000032ac)

  Thread T2 (tid=28859964, running) created by main thread at:
    #0 pthread_create <null>:126884528 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x309d8)
    #1 do_start_joinable_thread thread_pthread.h:281 (python.exe:arm64+0x10038f000)
    #2 PyThread_start_joinable_thread thread_pthread.h:323 (python.exe:arm64+0x10038ee38)
    #3 ThreadHandle_start _threadmodule.c:475 (python.exe:arm64+0x10045809c)
    #4 do_start_new_thread _threadmodule.c:1919 (python.exe:arm64+0x100457b7c)
    #5 thread_PyThread_start_joinable_thread _threadmodule.c:2042 (python.exe:arm64+0x100456ae0)
    #6 cfunction_call methodobject.c:564 (python.exe:arm64+0x1001310f4)
    #7 _PyObject_MakeTpCall call.c:242 (python.exe:arm64+0x100087f70)
    #8 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x100088c28)
    #9 _Py_VectorCall_StackRefSteal ceval.c:726 (python.exe:arm64+0x1002903e4)
    #10 _PyEval_EvalFrameDefault generated_cases.c.h (python.exe:arm64+0x1002995c4)
    #11 PyEval_EvalCode ceval.c:679 (python.exe:arm64+0x10028fb74)
    #12 run_eval_code_obj pythonrun.c:1406 (python.exe:arm64+0x10036aea4)
    #13 run_mod pythonrun.c:1509 (python.exe:arm64+0x10036abd4)
    #14 _PyRun_SimpleFile pythonrun.c:544 (python.exe:arm64+0x100365d88)
    #15 _PyRun_AnyFile pythonrun.c:92 (python.exe:arm64+0x100365534)
    #16 Py_RunMain main.c:891 (python.exe:arm64+0x1003a7aec)
    #17 pymain_main main.c:921 (python.exe:arm64+0x1003a7f3c)
    #18 Py_BytesMain main.c:945 (python.exe:arm64+0x1003a8010)
    #19 main python.c:15 (python.exe:arm64+0x1000032ac)

SUMMARY: ThreadSanitizer: data race socketmodule.c:3320 in sock_gettimeout_method
==================
done
ThreadSanitizer: reported 1 warnings
[1]    20351 abort      ./python.exe repro_sock_timeout_race.py

Proposed fix:

Wrap s->sock_timeout with _Py_atomic_load_int64_relaxed

I have a fix ready

CPython versions tested on:

CPython main branch

Operating systems tested on:

macOS

Linked PRs
  • gh-153940

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 socketmodule.c, au niveau de sock_gettimeout_method (ligne 3320) et de sock_settimeout (ligne 3264), puis exécutez le reproducteur multithread fourni avec ThreadSanitizer. C’est terminé lorsque le délai d’expiration partagé du socket ne produit plus la race de données signalée ; gh-153940 est déjà lié comme correctif proposé.

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

Évaluation

Stack technique
python
Domaine
networking
Type d'issue
Bug
Difficulté
2/5
Temps estimé
1-3 heures
Activité
À l'abandon
Clarté
Clairement spécifiée
Accessibilité débutants
20/100

Recevez les nouvelles issues par e-mail

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