Pull Request已成功合入, 合并人@ascend-robot
(感谢 21xiu 的贡献)变更摘要
此 PR 修复了 NPU 后端 THNPEvent_dealloc 和 THNPStream_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.cpp的THNPEvent_dealloc中,析构npu_event之后、调用tp_free之前插入PyObject_ClearWeakRefs((PyObject*)self);,确保 weakref 引用在对象释放前被正确清理。THNPStream_dealloc添加 weakref 清理与 context 释放:在torch_npu/csrc/npu/Stream.cpp的THNPStream_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.Stream和torch.npu.Event对象销毁时 weakref 回调能正常触发。 - 新增 dynamo 注册表悬空指针回归测试:添加
test_dynamo_registry_no_dangling_weakref测试用例,模拟torch.compile捕获current_stream()后 wrapper 被释放的场景,验证index_to_external_object_weakref注册表中的 weakref 不会保留悬空指针。


代码审查
经过全面审查,我确认此 diff 中的三处更改均正确且必要,未发现错误、安全风险、可靠性问题或回归风险。
变更分析:
-
torch_npu/csrc/npu/Event.cpp第 121 行:在THNPEvent_dealloc的tp_free之前添加PyObject_ClearWeakRefs。当父类THPEvent支持 weakref 后,子类自定义的tp_dealloc覆盖必须自行调用此函数,否则 weakref 的wr_object会悬空指向已释放的内存。此修改正确。 -
torch_npu/csrc/npu/Stream.cpp第 79-80 行:在THNPStream_dealloc中添加PyObject_ClearWeakRefs和Py_CLEAR(self->context)。前者防止 weakref 悬空,后者修复 lazy stream context 泄漏。调用顺序(先清 NPU 资源 → 清 weakref → 清 context → 释放内存)合理:weakref 回调不会访问已析构的 NPU 资源,且Py_CLEAR能用Py_XDECREF安全处理 NULL。 -
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。此更改安全,可以合入。
⚠️ 已识别出整体风险,但无法提取行内评论,请参考整体评估。




【合入来源】
【修改方案】
PyTorch 基础类 THPStream / THPEvent 中增加了 weakref 支持(添加了 weakreflist 字段),但 NPU 后端的 tp_dealloc 覆盖函数未同步更新。
CPython 对静态 PyType 不会自动链式调用父类 tp_dealloc,因此 THNPEvent_dealloc 和 THNPStream_dealloc 一直缺少:
【资料变更】
不涉及
【接口变更】
不涉及
【功能验证】
pytest test/dynamo/test_stream.py -k test_npu_stream_event_weakref_callback


修改前:
修改后:
【CheckList】