Call PyType_Ready() on ThreadCanary_Type - #274
Conversation
|
Why are you inspecting that type? Is this some kind of test harness? |
|
We see crashes when calling the Home Assistant guppy3 doesn't guard against NULL metatype and segfaults (I've opened a PR on guppy3 to guard against that zhuyifei1999/guppy3#56) My understanding is that live CPython objects should not have a NULL metatype, or is that intentionally the case here for some reason? |
|
It is, as the name says, a canary probe. Maybe we should make it only live in tests, nothing at runtime uses it. |
OK, that makes sense 👍 Edit: I seems to me the canary was added to fix https://foss.heptapod.net/pypy/cffi/-/work_items/362, and is not there to aid testing. cffi/src/c/misc_thread_common.h Lines 32 to 50 in 1f2d6ec cffi/src/c/misc_thread_common.h Lines 52 to 82 in 1f2d6ec |
|
OK, then the PyType_Ready should probably be called next to the type object creation, around line 214. Does that work? cffi/src/c/misc_thread_common.h Lines 210 to 220 in 61fe449 |
Done. |
|
Thanks @emontnemery |
|
@mattip thanks a lot for the quick merge! Do you have plans to make a release anytime soon? |
Proposed change
Call PyType_Ready() on ThreadCanary_Type before the first
thread_canaryis created. Placed inthread_canary_register().Background
ThreadCanary_Type (src/c/misc_thread_common.h) is declared with PyVarObject_HEAD_INIT(NULL, 0) and is never passed to PyType_Ready(), nor is its ob_type set explicitly - so its metatype stays NULL for the life of the process. Yet instances are created: thread_canary_register() does PyObject_New(ThreadCanaryObj, &ThreadCanary_Type) and stores the object in the foreign thread's PyThreadState dict.
Code that inspects such an instance's type dereferences the NULL metatype and crashes; in my case we get crashes when using zhuyifei1999/guppy3 to walk the heap.
CPython reference
The NULL in PyVarObject_HEAD_INIT(NULL, 0) is only a placeholder for compilers that reject &PyType_Type as a static initializer; it isn't meant to survive to runtime. Per the CPython C-API docs for the type ob_type field (https://docs.python.org/3/c-api/typeobj.html#pyobject-slots):