python / python/cpython

FrameLocalsProxy `|=` and `update()` mishandle errors raised while merging mappings

Đang mở
#153,418 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

interpreter-core type-bug
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:

  1. framelocalsproxy_inplace_or() returns Py_NotImplemented when framelocalsproxy_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_CheckSlotResult error.
  2. framelocalsproxy_update() replaces any failure from framelocalsproxy_merge() with a generic TypeError, 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

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. 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.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. 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

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.