python / python/cpython

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

未關閉
#152,767 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

extension-modules topic-free-threading type-bug
主要語言
Python
星號
77.2k
分支
36k
PR 合併指標
PR 指標待擷取

描述

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

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

研究方向

從 Modules/cjkcodecs/multibytecodec.c 中的 codecctx_errors_set 開始,然後在搭配 ThreadSanitizer 的 free-threaded build 下執行提供的多執行緒 reproducer。將行為與連結的 PR gh-153000 進行比較;當並行的 codec.errors 指派不再產生回報的 race 或錯誤的 handler 生命週期行為時,即表示完成。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
c, python
領域
backend
Issue 類型
缺陷
難度
4/5
預估耗時
3-5 天
活躍度
停滯
描述清晰度
描述清楚
新手友好度
30/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。