MagicStack / MagicStack/uvloop

BusError in uvloop within loop extract_stack for nested async_generators

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

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

Ngôn ngữ chính
Cython
Star
11.9k
Fork
616
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

  • uvloop version:
  • 0.19.0 (tested 0.17.0 to 0.19.0)
  • Python version: 3.12.4
  • Platform: OSX Ventura 13.4/ Darwin 22.5.0
  • Can you reproduce the bug with PYTHONASYNCIODEBUG in env?:
  • This bug only occurs if -X dev or PYTHONDEVMODE=1 or PYTHONASYNCIODEBUG=1 or loop.set_debug(True)
  • Does uvloop behave differently from vanilla asyncio? How?:
  • Vanilla asyncio and uvloop with loop.set_debug(False) do not crash in nested async_generator .asend calls

I have a pattern called DeferredExecutor which basically allows one to write:

class Foo:
        @database(transaction=True, iterable=False)
        async def save(self, *args, **kwargs):
               # /snip
              rows = yield DeferredQuery("some sql")
              assert isinstance(rows, tuple)
              yield Return(...)

And have it be wrapped by a decorator that will call the async_generator, run the deferred queries against a DB and .asend( the result back into the generator, which will throw an StopAsyncIteration at the conclusion of the generator, and allows me to catch it and end the generators execution.

I am getting my database access object library to run on Python 3.12 (jumping from Python 3.7).

However, on Python 3.12, a particular integration test that uses a particularly reduced implementation:

class Tenant:
    @database(iterable=False, transaction=True)
    async def invite_users(cls, *tenant_user_pairs, instance=None):
        invites = (instance or cls).create_invites_for(*tenant_user_pairs)
        gen_event_loop = Invite.save.raw_iterable(*invites)
        result = None
        while True:
            result = await gen_event_loop.asend(result)
            if isinstance(result, Return):
                break
            result = yield result
        yield result # StopAsyncIteration gets thrown here

causes uvloop to crash with a Bus Error on OSX but only when loop.set_debug(True) (which is autoset via the environment variables or interpreter devmode)

Regular asyncio, debug or not, works just fine. If I patch the EventLoopPolicy to.set_debug(False) like:

def patch_uvloop():
    if uvloop_version_info < (99, 99, 99) and platform.system() == 'Darwin':
        cls = uvloop.EventLoopPolicy
        if hasattr(cls, '__patched__'):
            return cls
        class EventLoopPolicy(cls):
            __patched__ = True
            #  ARJ: so uvloop will crash the entire interpreter sometimes
            # and the crash originates on OSX. Disable debug mode
            # (which keeps it from touching uvloop's extract_stack() which 
            # explodes badly)

            def _loop_factory(self):
                loop = super()._loop_factory()
                loop.set_debug(False)
                return loop
        uvloop.EventLoopPolicy = EventLoopPolicy

asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

Then the crashes never happen.

I do have lldb/gdb and the patience to recompile things with more debugging information (provided I know -how-) but a careful inspection of the following stack trace shows that it explodes after going into the extract_stack function of uvloop:

This does remind me of https://github.com/python/cpython/issues/94694

I wonder if the extract_stack function is tolerant of encountering negative numbers in the offset extraction of the trace.

Stack report:
stack.txt

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

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

Tái hiện trường hợp async_generator lồng nhau trên Python 3.12.4 và macOS khi đã bật chế độ debug của uvloop, sử dụng báo cáo stack được cung cấp làm tham chiếu. Kiểm tra uvloop/handles/handle.pyx và uvloop/cbhandles.pyx xung quanh extract_stack, sau đó xác định nguyên nhân của Bus Error và xác minh rằng crash đã được giải quyết mà không tắt chế độ debug.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
python
Lĩnh vực
backend
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
35/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.