Skip to content

Free threading: Data race on a socket's timeout #153935

Description

@deadlovelll

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixes3.15pre-release feature fixes, bugs and security fixes3.16new features, bugs and security fixesextension-modulesC modules in the Modules dirtopic-free-threadingtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions