已合并
fix: add PyObject_ClearWeakRefs in NPU Stream/Event tp_dealloc #41678
21xiu创建于 7月14日
fix: add PyObject_ClearWeakRefs in NPU Stream/Event tp_dealloc #41678
已合并
21xiu创建于 7月14日
21xiu
21xiu成员
7月14日

【合入来源】

如有社区issue,请关联issue链接
请勿携带内部流程信息(需求链接、问题单、内部issue等)

【修改方案】

PyTorch 基础类 THPStream / THPEvent 中增加了 weakref 支持(添加了 weakreflist 字段),但 NPU 后端的 tp_dealloc 覆盖函数未同步更新。
CPython 对静态 PyType 不会自动链式调用父类 tp_dealloc,因此 THNPEvent_dealloc 和 THNPStream_dealloc 一直缺少:

  1. PyObject_ClearWeakRefs() — 未清理 weakref,导致 wr_object 悬空指向已释放内存
  2. Py_CLEAR(self->context)(仅 Stream)— lazy stream context 泄漏

【资料变更】

不涉及

【接口变更】

不涉及

【功能验证】

pytest test/dynamo/test_stream.py -k test_npu_stream_event_weakref_callback
修改前:
ScreenShot_20260714192241.JPG
修改后:
ScreenShot_20260714192439.JPG

【CheckList】

PR提交人对以下CheckList自检项进行全量自检,自检通过或不涉及,均修改 [ ] 为 [x]

likedislike
Pull Request已成功合入, 合并人@ascend-robot
(感谢 21xiu 的贡献)
21xiu21xiu成员
7月14日 创建了 pull request,commit 2675159d
atomgit-bot
atomgit-bot
7月14日 评论:

变更摘要

此 PR 修复了 NPU 后端 THNPEvent_deallocTHNPStream_dealloc 中因未同步上游 PyTorch 基础类 weakref 支持而导致的内存安全问题。由于 CPython 对静态 PyType 不会自动链式调用父类 tp_dealloc,NPU 的覆盖实现缺少 PyObject_ClearWeakRefs() 调用,导致 weakref 的 wr_object 悬空指向已释放内存(use-after-free);同时 THNPStream_dealloc 还缺少对 self->context 的清理,造成 lazy stream context 泄漏。修复后添加了相应的回归测试。

主要改动

  • THNPEvent_dealloc 添加 weakref 清理:在 torch_npu/csrc/npu/Event.cppTHNPEvent_dealloc 中,析构 npu_event 之后、调用 tp_free 之前插入 PyObject_ClearWeakRefs((PyObject*)self);,确保 weakref 引用在对象释放前被正确清理。
  • THNPStream_dealloc 添加 weakref 清理与 context 释放:在 torch_npu/csrc/npu/Stream.cppTHNPStream_dealloc 中,新增 PyObject_ClearWeakRefs((PyObject*)self);Py_CLEAR(self->context);,分别解决悬空指针和 context 泄漏问题。
  • 新增 weakref 回调回归测试:在 test/dynamo/test_stream.py 中添加 _assert_weakref_callback_fires 辅助方法及 test_npu_stream_event_weakref_callback 测试用例,验证 torch.npu.Streamtorch.npu.Event 对象销毁时 weakref 回调能正常触发。
  • 新增 dynamo 注册表悬空指针回归测试:添加 test_dynamo_registry_no_dangling_weakref 测试用例,模拟 torch.compile 捕获 current_stream() 后 wrapper 被释放的场景,验证 index_to_external_object_weakref 注册表中的 weakref 不会保留悬空指针。
likedislike
不准确?
atomgit-bot
atomgit-bot
7月14日 评论:

代码审查

经过全面审查,我确认此 diff 中的三处更改均正确且必要,未发现错误、安全风险、可靠性问题或回归风险。

变更分析:

  1. torch_npu/csrc/npu/Event.cpp 第 121 行:在 THNPEvent_dealloctp_free 之前添加 PyObject_ClearWeakRefs。当父类 THPEvent 支持 weakref 后,子类自定义的 tp_dealloc 覆盖必须自行调用此函数,否则 weakref 的 wr_object 会悬空指向已释放的内存。此修改正确。

  2. torch_npu/csrc/npu/Stream.cpp 第 79-80 行:在 THNPStream_dealloc 中添加 PyObject_ClearWeakRefsPy_CLEAR(self->context)。前者防止 weakref 悬空,后者修复 lazy stream context 泄漏。调用顺序(先清 NPU 资源 → 清 weakref → 清 context → 释放内存)合理:weakref 回调不会访问已析构的 NPU 资源,且 Py_CLEAR 能用 Py_XDECREF 安全处理 NULL。

  3. test/dynamo/test_stream.py 第 3-117 行:添加了两个回归测试:

    • test_npu_stream_event_weakref_callback:验证 Stream/Event 析构时 weakref 回调正确触发。
    • test_dynamo_registry_no_dangling_weakref:复现原始 UAF 场景,验证 dynamo registry 中的 weakref 在 wrapper 释放后被正确清空。

    测试逻辑严谨,辅助方法 _assert_weakref_callback_fires 正确使用了 weakref.ref 回调机制和 gc.collect()


审查结论: 共审查 3 个文件,P0–P3 问题数均为 0。此更改安全,可以合入。

⚠️ 已识别出整体风险,但无法提取行内评论,请参考整体评估。

likedislike
不准确?
ascend-robotascend-robot成员
7月14日 添加了label:ascend-cla/yes
此处折叠了60条消息 查看更多
chujinjin成员
7月16日 评论:

/lgtm

likedislike
ascend-robotascend-robot成员
7月16日 添加了label:lgtm
ascend-robotascend-robot成员
7月16日 关闭了关联的issue
ascend-robotascend-robot成员
7月16日 合入了pull request
ascend-robot
ascend-robot成员
7月16日 评论:
流水线 pytorch_gitcode_PR_multiVersion#12662 [ commitID:44e7ce28 ] 已完成
likedislike