python / python/cpython

Segfault in `_Unpickler_MemoPut` (`_pickle.c`) from `Unpickler.memo` assignment with free-threading

未关闭
#150,505 5 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

interpreter-core topic-free-threading type-bug
主要语言
Python
星标
77.2k
派生
35.9k
PR 合并指标
PR 指标待抓取

描述

Bug report

Bug description:

Unpickler_set_memo modifies self->memo and self->memo_size without any critical section.

When two threads set .memo on the same Unpickler instance concurrently, one can set self->memo = NULL while another is still indexing into it via _Unpickler_MemoPut, leading to a NULL-pointer dereference.

Reproducer:

import io
import pickle
from threading import Thread

shared_unpickler = pickle.Unpickler(io.BytesIO(b''))

def assign():
    for _ in range(10000):
        shared_unpickler.memo = {j: j for j in range(100)}

if __name__ == "__main__":
    threads = [Thread(target=assign) for _ in range(8)]
    for t in threads: t.start()
    for t in threads: t.join()

TSAN report:

WARNING: ThreadSanitizer: data race (pid=214122)
  Read of size 8 at 0x7dca529b9130 by thread T2:
    #0 _Unpickler_MemoPut /home/cpython/./Modules/_pickle.c:1631:22 (_pickle.cpython-316t-x86_64-linux-gnu.so+0x2122f) 
    #1 Unpickler_set_memo /home/cpython/./Modules/_pickle.c:7804:17 (_pickle.cpython-316t-x86_64-linux-gnu.so+0x26b77) 
    #2 getset_set /home/cpython/Objects/descrobject.c:250:16 (python3.16t+0x22d8fb) 
    #3 _PyObject_GenericSetAttrWithDict /home/cpython/Objects/object.c:2049:19 (python3.16t+0x2d844b) 
    #4 PyObject_GenericSetAttr /home/cpython/Objects/object.c:2120:12 (python3.16t+0x2d8d4b) 
    #5 Unpickler_setattr /home/cpython/./Modules/_pickle.c:7857:12 (_pickle.cpython-316t-x86_64-linux-gnu.so+0x24eca) 
    #6 PyObject_SetAttr /home/cpython/Objects/object.c:1533:15 (python3.16t+0x2d480f) 
    #7 _PyEval_EvalFrameDefault /home/cpython/Python/generated_cases.c.h:11536:27 (python3.16t+0x45231a) 
    #8 _PyEval_EvalFrame /home/cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463) 
    #9 _PyEval_Vector /home/cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
    #10 _PyFunction_Vectorcall /home/cpython/Objects/call.c (python3.16t+0x215013) 
    #11 _PyObject_VectorcallTstate /home/cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11) 
    #12 _PyObject_VectorcallPrepend /home/cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
    #13 method_vectorcall /home/cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132) 
    #14 _PyObject_VectorcallTstate /home/cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x48ec15) 
    #15 context_run /home/cpython/Python/context.c:728:29 (python3.16t+0x48ec15)
    #16 method_vectorcall_FASTCALL_KEYWORDS /home/cpython/Objects/descrobject.c:421:24 (python3.16t+0x22e84c) 
    #17 _PyObject_VectorcallTstate /home/cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x2149a8) 
    #18 PyObject_Vectorcall /home/cpython/Objects/call.c:327:12 (python3.16t+0x2149a8)
    #19 _Py_VectorCallInstrumentation_StackRefSteal /home/cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8) 
    #20 _PyEval_EvalFrameDefault /home/cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022) 
    #21 _PyEval_EvalFrame /home/cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463) 
    #22 _PyEval_Vector /home/cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
    #23 _PyFunction_Vectorcall /home/cpython/Objects/call.c (python3.16t+0x215013) 
    #24 _PyObject_VectorcallTstate /home/cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11) 
    #25 _PyObject_VectorcallPrepend /home/cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
    #26 method_vectorcall /home/cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132) 
    #27 _PyVectorcall_Call /home/cpython/Objects/call.c:273:16 (python3.16t+0x214ca2) 
    #28 _PyObject_Call /home/cpython/Objects/call.c:348:16 (python3.16t+0x214ca2)
    #29 PyObject_Call /home/cpython/Objects/call.c:373:12 (python3.16t+0x214d07) 
    #30 thread_run /home/cpython/./Modules/_threadmodule.c:388:21 (python3.16t+0x61a708) 
    #31 pythread_wrapper /home/cpython/Python/thread_pthread.h:234:5 (python3.16t+0x5473bb) 

  Previous write of size 8 at 0x7dca529b9130 by thread T1:
    #0 Unpickler_set_memo /home/cpython/./Modules/_pickle.c:7816:21 (_pickle.cpython-316t-x86_64-linux-gnu.so+0x26cc4) 
    #1 getset_set /home/cpython/Objects/descrobject.c:250:16 (python3.16t+0x22d8fb) 
    #2 _PyObject_GenericSetAttrWithDict /home/cpython/Objects/object.c:2049:19 (python3.16t+0x2d844b) 
    #3 PyObject_GenericSetAttr /home/cpython/Objects/object.c:2120:12 (python3.16t+0x2d8d4b) 
    #4 Unpickler_setattr /home/cpython/./Modules/_pickle.c:7857:12 (_pickle.cpython-316t-x86_64-linux-gnu.so+0x24eca) 
    #5 PyObject_SetAttr /home/cpython/Objects/object.c:1533:15 (python3.16t+0x2d480f) 
    #6 _PyEval_EvalFrameDefault /home/cpython/Python/generated_cases.c.h:11536:27 (python3.16t+0x45231a) 
    #7 _PyEval_EvalFrame /home/cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463) 
    #8 _PyEval_Vector /home/cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
    #9 _PyFunction_Vectorcall /home/cpython/Objects/call.c (python3.16t+0x215013) 
    #10 _PyObject_VectorcallTstate /home/cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11) 
    #11 _PyObject_VectorcallPrepend /home/cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
    #12 method_vectorcall /home/cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132) 
    #13 _PyObject_VectorcallTstate /home/cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x48ec15) 
    #14 context_run /home/cpython/Python/context.c:728:29 (python3.16t+0x48ec15)
    #15 method_vectorcall_FASTCALL_KEYWORDS /home/cpython/Objects/descrobject.c:421:24 (python3.16t+0x22e84c) 
    #16 _PyObject_VectorcallTstate /home/cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x2149a8) 
    #17 PyObject_Vectorcall /home/cpython/Objects/call.c:327:12 (python3.16t+0x2149a8)
    #18 _Py_VectorCallInstrumentation_StackRefSteal /home/cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8) 
    #19 _PyEval_EvalFrameDefault /home/cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022) 
    #20 _PyEval_EvalFrame /home/cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463) 
    #21 _PyEval_Vector /home/cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
    #22 _PyFunction_Vectorcall /home/cpython/Objects/call.c (python3.16t+0x215013) 
    #23 _PyObject_VectorcallTstate /home/cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11) 
    #24 _PyObject_VectorcallPrepend /home/cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
    #25 method_vectorcall /home/cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132) 
    #26 _PyVectorcall_Call /home/cpython/Objects/call.c:273:16 (python3.16t+0x214ca2) 
    #27 _PyObject_Call /home/cpython/Objects/call.c:348:16 (python3.16t+0x214ca2)
    #28 PyObject_Call /home/cpython/Objects/call.c:373:12 (python3.16t+0x214d07) 
    #29 thread_run /home/cpython/./Modules/_threadmodule.c:388:21 (python3.16t+0x61a708) 
    #30 pythread_wrapper /home/cpython/Python/thread_pthread.h:234:5 (python3.16t+0x5473bb) 

SUMMARY: ThreadSanitizer: data race /home/cpython/./Modules/_pickle.c:1631:22 in _Unpickler_MemoPut
==================

==214455==ERROR: ThreadSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7afb5f96f25a bp 0x7afb187fd6f0 sp 0x7afb187fd690 T214460)
==214455==The signal is caused by a READ memory access.
==214455==Hint: address points to the zero page.
    #0 _Unpickler_MemoPut /home/cpython/./Modules/_pickle.c:1657:16 (_pickle.cpython-316t-x86_64-linux-gnu.so+0x2125a) 
    #1 Unpickler_set_memo /home/cpython/./Modules/_pickle.c:7804:17 (_pickle.cpython-316t-x86_64-linux-gnu.so+0x26b77) 
    #2 getset_set /home/cpython/Objects/descrobject.c:250:16 (python3.16t+0x22d8fb) 
    #3 _PyObject_GenericSetAttrWithDict /home/cpython/Objects/object.c:2049:19 (python3.16t+0x2d844b) 
    #4 PyObject_GenericSetAttr /home/cpython/Objects/object.c:2120:12 (python3.16t+0x2d8d4b) 
    #5 Unpickler_setattr /home/cpython/./Modules/_pickle.c:7857:12 (_pickle.cpython-316t-x86_64-linux-gnu.so+0x24eca) 
    #6 PyObject_SetAttr /home/cpython/Objects/object.c:1533:15 (python3.16t+0x2d480f) 
    #7 _PyEval_EvalFrameDefault /home/cpython/Python/generated_cases.c.h:11536:27 (python3.16t+0x45231a) 
    #8 _PyEval_EvalFrame /home/cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463) 
    #9 _PyEval_Vector /home/cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
    #10 _PyFunction_Vectorcall /home/cpython/Objects/call.c (python3.16t+0x215013) 
    #11 _PyObject_VectorcallTstate /home/cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11) 
    #12 _PyObject_VectorcallPrepend /home/cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
    #13 method_vectorcall /home/cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132) 
    #14 _PyObject_VectorcallTstate /home/cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x48ec15) 
    #15 context_run /home/cpython/Python/context.c:728:29 (python3.16t+0x48ec15)
    #16 method_vectorcall_FASTCALL_KEYWORDS /home/cpython/Objects/descrobject.c:421:24 (python3.16t+0x22e84c) 
    #17 _PyObject_VectorcallTstate /home/cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x2149a8) 
    #18 PyObject_Vectorcall /home/cpython/Objects/call.c:327:12 (python3.16t+0x2149a8)
    #19 _Py_VectorCallInstrumentation_StackRefSteal /home/cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8) 
    #20 _PyEval_EvalFrameDefault /home/cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022) 
    #21 _PyEval_EvalFrame /home/cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463) 
    #22 _PyEval_Vector /home/cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
    #23 _PyFunction_Vectorcall /home/cpython/Objects/call.c (python3.16t+0x215013) 
    #24 _PyObject_VectorcallTstate /home/cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11) 
    #25 _PyObject_VectorcallPrepend /home/cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
    #26 method_vectorcall /home/cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132) 
    #27 _PyVectorcall_Call /home/cpython/Objects/call.c:273:16 (python3.16t+0x214ca2) 
    #28 _PyObject_Call /home/cpython/Objects/call.c:348:16 (python3.16t+0x214ca2)
    #29 PyObject_Call /home/cpython/Objects/call.c:373:12 (python3.16t+0x214d07) 
    #30 thread_run /home/cpython/./Modules/_threadmodule.c:388:21 (python3.16t+0x61a708) 
    #31 pythread_wrapper /home/cpython/Python/thread_pthread.h:234:5 (python3.16t+0x5473bb) 
    #32 __tsan_thread_start_func <null> (python3.16t+0xf9182) 
    #33 start_thread nptl/pthread_create.c:447:8 (libc.so.6+0x9caa3) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
    #34 clone3 misc/../sysdeps/unix/sysv/linux/x86_64/clone3.S:78 (libc.so.6+0x129c6b) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)

ThreadSanitizer can not provide additional info.
SUMMARY: ThreadSanitizer: SEGV /home/cpython/./Modules/_pickle.c:1657:16 in _Unpickler_MemoPut
==214455==ABORTING
CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs
  • gh-150550

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从 Modules/_pickle.c 中的 _Unpickler_MemoPut 和 Unpickler_set_memo 开始,使用提供的线程 reproducer 和 TSAN 报告来追踪竞争条件。检查链接的 PR gh-150550,并验证并发的 Unpickler.memo 赋值不再产生 data race 或 NULL 指针解引用。

由索引模型根据 Issue 内容生成。

评估

技术栈
c, python
领域
backend
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
基本清楚
新手友好度
25/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。