FrameLocalsProxy `|=` and `update()` mishandle errors raised while merging mappings
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Python
- Star
- 77.2k
- Fork
- 35.9k
- Chỉ số merge pull request
- Chỉ số pull request đang chờ
Mô tả
Bug report
Bug description:
Bug description
FrameLocalsProxy does not correctly propagate exceptions raised while merging a dict subclass or another supported mapping-like object.
There are two related problems in Objects/frameobject.c:
framelocalsproxy_inplace_or()returnsPy_NotImplementedwhenframelocalsproxy_merge()fails. If the merge failed because Python code raised an exception, the slot returns a normal object while an exception is still set. In a pydebug build this triggers a fatal_Py_CheckSlotResulterror.framelocalsproxy_update()replaces any failure fromframelocalsproxy_merge()with a genericTypeError, masking the original exception.
This is a sub-issue of https://github.com/python/cpython/issues/146102 with gist details
A minimal reproducer is below.
import operator
import sys
class BadDict(dict):
def keys(self):
raise RuntimeError("keys() failed!")
def repro_update():
locs = sys._getframe().f_locals
print(type(locs))
try:
locs.update(BadDict())
except TypeError as exc:
print("BUG: update() masked RuntimeError as TypeError:", exc)
except RuntimeError as exc:
print("OK: update() propagated RuntimeError:", exc)
def repro_inplace_or():
locs = sys._getframe().f_locals
print(type(locs))
try:
operator.ior(locs, BadDict())
except RuntimeError as exc:
print("OK: |= propagated RuntimeError:", exc)
except BaseException as exc:
print("BUG: |= raised wrong exception:", type(exc).__name__, exc)
else:
print("BUG: |= swallowed RuntimeError")
repro_update()
repro_inplace_or()
operator.ior(locs, BadDict()) is used to exercise the same nb_inplace_or slot as locs |= BadDict().
Actual behavior
For .update(), the original RuntimeError from BadDict.keys() is replaced with a generic TypeError:
<class 'FrameLocalsProxy'>
BUG: update() masked RuntimeError as TypeError: update() argument must be dict or another FrameLocalsProxy
For |= on a pydebug build, the interpreter aborts because the slot reports success while an exception remains set:
<class 'FrameLocalsProxy'>
Fatal Python error: _Py_CheckSlotResult: Slot |= of type FrameLocalsProxy succeeded with an exception set
Python runtime state: initialized
Traceback (most recent call last):
File "/tmp/repro_ior.py", line 6, in keys
raise RuntimeError("keys() failed!")
RuntimeError: keys() failed!
Aborted (core dumped)
Expected behavior
Both FrameLocalsProxy.update() and FrameLocalsProxy.__ior__() should propagate the original exception raised while merging:
<class 'FrameLocalsProxy'>
OK: update() propagated RuntimeError: keys() failed!
<class 'FrameLocalsProxy'>
OK: |= propagated RuntimeError: keys() failed!
I will submit a PR to fix this
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
- gh-153421
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu trong Objects/frameobject.c tại framelocalsproxy_inplace_or() và framelocalsproxy_update(), sau đó chạy trình tái hiện tối thiểu với BadDict.keys() phát sinh RuntimeError. Được coi là hoàn tất khi cả hai thao tác đều truyền tiếp ngoại lệ ban đầu mà không xảy ra lỗi slot trong bản build debug, kèm theo phạm vi kiểm thử hồi quy cho hành vi được báo cáo.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- c, python
- Lĩnh vực
- backend
- Loại issue
- Lỗi
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức phù hợp với người mới
- 25/100