[Python-Dev] A Subtle Bug in Class Initializations
Benjamin Peterson
benjamin at python.org
Wed Aug 8 00:13:56 EDT 2018
This would be a good thing to fix. The only hard part is dealing with thirdparty extensions.
Note we also have been working around this problem by putting PyType_Ready calls in various generic code paths of the interpreter when an uninitialized type passes through.
On Mon, Aug 6, 2018, at 11:02, Eddie Elizondo wrote:
> Solution:
> Here are my proposed solutions in order from less controversial to most
> controversial. Note that all of them I already tried in a local branch
> and are working:
>
> 1) Initialize all uninitialized types.
>
> Example:
> https://github.com/eduardo-elizondo/cpython/commit/bc53db3cf4e5a6923b0b1afa6181305553faf173
That fixes CPython but what about thirdparty extensions?
>
> 2) Move all PyVarObject_HEAD_INIT to NULL except PyType_Type,
> PyBaseObject_Type and the booleans.
>
> 3) Special case the initialization of PyType_Type and PyBaseObject_Type
> within PyType_Ready to now make all calls to PyVarObject_HEAD_INIT use
> NULL. To enable this a small change within PyType_Ready is needed to
> initialize PyType_Type PyBaseObject:
> if (base == NULL) {
> Py_TYPE(&PyType_Type) = &PyType_Type;
> Py_TYPE(type) = &PyType_Type;
> }
>
> Also, the booleans have to be fully initialized without calling
> PyVarObject_HEAD_INIT. I propose:
>
> struct _longobject _Py_FalseStruct = {
> PyObject_HEAD_INIT(&PyBool_Type), 0, { 0 }
> };
>
> This will clean-up the entire codebase of this anti-pattern.
>
> Example:
> https://github.com/eduardo-elizondo/cpython/commit/542fd79e4279c64c077c127b175a8d856d3c5f0b
>
> 4) Modify PyVarObject_HEAD_INIT to ignore the input and initialize to
> NULL and 0.
> In order to prevent this antipattern within extension code as well, we
> should make PyVarObject_HEAD_INIT ignore the inputs and just set the
> value to NULL.
>
> #define PyVarObject_HEAD_INIT(type, size) \
> { PyObject_HEAD_INIT(NULL) 0 },
>
> This will prevent external code to have a semi-initialized type that is
> not initialized through PyType_Ready.
When does that fail, though? The first time someone tries to do anything with the type?
>
> 5) Finally, I would go even further and suggest making
> PyVarObject_HEAD_INIT argumentless.
>
> #define PyVarObject_HEAD_INIT \
> { PyObject_HEAD_INIT(NULL) 0 },
>
> However, this breaks backward compatibility. That being said, this will
> make extension maintainers aware of this antipattern.
More information about the Python-Dev
mailing list