Skip to content

Cython has defeated our Cython workaround #2908

Description

@njsmith

When we spawn a task, we inject a magic local variable into the top stack frame's local namespace, as part of our tricky control-C magic:

coro.cr_frame.f_locals.setdefault(LOCALS_KEY_KI_PROTECTION_ENABLED, system_task)

However, this doesn't work for async def functions defined in C or Cython, because they don't have a Python frame. So we a simple workaround, we detect this case and inject a no-op Python frame where we can insert our magic local (cf #550):

trio/src/trio/_core/_run.py

Lines 1747 to 1750 in d4ce2f9

if not hasattr(coro, "cr_frame"):
# This async function is implemented in C or Cython
async def python_wrapper(orig_coro: Awaitable[RetT]) -> RetT:
return await orig_coro

However, the bug came back at some point with newer versions of Cython:

             |   File "/root/.pyenv/versions/3.11.6/lib/python3.11/site-packages/trio/_core/_run.py", line 1599, in spawn_impl
             |     coro.cr_frame.f_locals.setdefault(LOCALS_KEY_KI_PROTECTION_ENABLED, system_task)
             |     ^^^^^^^^^^^^^^^^^^^^^^
             | AttributeError: 'NoneType' object has no attribute 'f_locals'

From the error message, it appears that Cython has added a cr_frame attribute to its fake coroutine objects... just it's None. So it's still not really there, but it's enough to sneak past our hasattr(coro, "cr_frame") test.

I think the fix here is just to replace the if not hasattr(coro, "cr_frame"): with if getattr(coro, "cr_frame", None) is None:. But it would be good to also run a test for this in CI. We do have a test for the interpreter's built-in C coroutines (test_async_function_implemented_in_C) and I originally assumed that would be enough, but obviously it wasn't, so I guess we need to do the legwork to install cython in CI and build a tiny Cython module.

Edit by CoolCat467:
Things to do:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions