bpo-35059: Convert _Py_Dealloc() to static inline function#10223
bpo-35059: Convert _Py_Dealloc() to static inline function#10223vstinner merged 2 commits intopython:masterfrom vstinner:py_dealloc
Conversation
Convert _Py_Dealloc() macro into a static inline function. Moreover, it is now also defined as a static inline function if Py_TRACE_REFS is defined.
|
@methane: Py_INCREF and Py_DECREF have been converted to static inline functions. So I came back to _Py_Dealloc() as you asked me, and it seems like I found a solution to handle properly this one:
|
| #else | ||
| _Py_INC_TPFREES(op); | ||
| #endif | ||
| (*dealloc)(op); |
There was a problem hiding this comment.
Are you sure that it is safe to use a borrowed reference taken before calling _Py_INC_TPFREES?
There was a problem hiding this comment.
My PR doesn't change anything related to that. See the old code at line 1970: it does the same. I would say that it's safer to read dealloc before _Py_ForgetReference() or _Py_INC_TPFREES() than reading it after (as previously done in the old code at line 2277).
There was a problem hiding this comment.
_Py_INC_TPFREES decrements the refcount. Can it trigger executing arbitrary code?
There was a problem hiding this comment.
_Py_ForgetReference() and _Py_INC_TPFREES() is called before calling dealloc() since forever. If you consider that it's a bug, you should write a separated PR (and maybe open an issue).
I have no idea if this case can occur. I can only say that my PR only moves the code, it doesn't change the code. Since nobody ever reported a crash, I don't think that dealloc can become a dangling pointer.
Please see the discussion about Py_TYPE() borrowed reference:
https://mail.python.org/mm3/archives/list/capi-sig@python.org/thread/V5EMBIIJFJGJGBQPLCFFXCHAUFNTA45H/
Especially my second email: "I succeeded to get a dangling pointer to a deallocated type object using Py_TYPE()."
But to get a dangling pointer to a type, you have to remove all references to all instances and to the type itself. It seems doable, but also very unlikely in practice.
Again, if you consider that it's a bug, I suggest to open a separated issue and fix the bug in all stable branches. (And I have no strong opinion to know if it's a bug or not :-))
My discussion on capi-sig is able PyTypeObject* pointer, but here we are talking about dealloc which is a function pointer. To get a dangling pointer, you would have to somehow remove the function (code) from the memory. Maybe it's possible using ctypes, but it seems very very unlikely :-) (Don't do that at home, or very bad things can happen to you!)
|
@serhiy-storchaka: You asked interesting questions, but I merged my change anyway. For the coding style, if you want to change it: please write a separated PR to reformat all "static inline" at once, not only these ones. For _Py_Dealloc() race condition: if you consider that it's a bug, please open a new issue. My commit doesn't change the code, it only moves the code. |
| #else | ||
| #define _Py_Dealloc(op) ( \ | ||
| _Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA \ | ||
| (*Py_TYPE(op)->tp_dealloc)((PyObject *)(op))) |
There was a problem hiding this comment.
@serhiy-storchaka: Oh, I forgot to mention that my PR changes this code to read dealloc before _Py_INC_TPFREES(), it might make the code safer ;-)
Convert _Py_Dealloc() macro into a static inline function. Moreover,
it is now also defined as a static inline function if Py_TRACE_REFS
is defined.
https://bugs.python.org/issue35059