Free threading: Data race on a socket's timeout
オープン
まだ誰も着手していません。
3.14
3.15
3.16
extension-modules
topic-free-threading
type-bug
- 主要言語
- Python
- スター
- 77.2k
- フォーク
- 35.9k
- 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 にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
socketmodule.c の sock_gettimeout_method(3320 行目)と sock_settimeout(3264 行目)から始め、その後、提供されているスレッド化された再現プログラムを ThreadSanitizer で実行します。共有ソケットタイムアウトによって報告されたデータ競合が発生しなくなれば完了です。gh-153940 は提案された修正としてすでにリンクされています。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- python
- 領域
- networking
- issue の種類
- バグ
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 活発さ
- 停滞
- 明瞭さ
- 明確に書かれている
- 初心者へのやさしさ
- 20/100