Free threading: Data race on a socket's timeout
未關閉
還沒有人認領這個 Issue。
3.14
3.15
3.16
extension-modules
topic-free-threading
type-bug
- 主要語言
- Python
- 星號
- 77.2k
- 分支
- 36k
- PR 合併指標
- PR 指標待擷取
描述
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
貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
研究方向
從 socketmodule.c 中的 sock_gettimeout_method(第 3320 行)和 sock_settimeout(第 3264 行)開始,然後在 ThreadSanitizer 下執行提供的多執行緒重現程式。當共用的 socket timeout 不再產生所回報的資料競爭時,即表示完成;gh-153940 已作為提議的修正方案連結。
由索引模型根據 Issue 內容生成。
評估
- 技術堆疊
- python
- 領域
- networking
- Issue 類型
- 缺陷
- 難度
- 2/5
- 預估耗時
- 1-3 小時
- 活躍度
- 停滯
- 描述清晰度
- 描述清楚
- 新手友好度
- 20/100