mirror of
https://github.com/python/cpython.git
synced 2025-09-09 02:11:51 +00:00
gh-104614: Make Sure ob_type is Always Set Correctly by PyType_Ready() (gh-105122)
When I added the relevant condition to type_ready_set_bases() in gh-103912, I had missed that the function also sets tp_base and ob_type (if necessary). That led to problems for third-party static types. We fix that here, by making those extra operations distinct and by adjusting the condition to be more specific.
This commit is contained in:
parent
3698fda06e
commit
146939306a
4 changed files with 128 additions and 17 deletions
|
@ -306,11 +306,14 @@ clear_tp_bases(PyTypeObject *self)
|
|||
{
|
||||
if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
|
||||
if (_Py_IsMainInterpreter(_PyInterpreterState_GET())) {
|
||||
if (self->tp_bases != NULL
|
||||
&& PyTuple_GET_SIZE(self->tp_bases) > 0)
|
||||
{
|
||||
assert(_Py_IsImmortal(self->tp_bases));
|
||||
_Py_ClearImmortal(self->tp_bases);
|
||||
if (self->tp_bases != NULL) {
|
||||
if (PyTuple_GET_SIZE(self->tp_bases) == 0) {
|
||||
Py_CLEAR(self->tp_bases);
|
||||
}
|
||||
else {
|
||||
assert(_Py_IsImmortal(self->tp_bases));
|
||||
_Py_ClearImmortal(self->tp_bases);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -352,11 +355,14 @@ clear_tp_mro(PyTypeObject *self)
|
|||
{
|
||||
if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
|
||||
if (_Py_IsMainInterpreter(_PyInterpreterState_GET())) {
|
||||
if (self->tp_mro != NULL
|
||||
&& PyTuple_GET_SIZE(self->tp_mro) > 0)
|
||||
{
|
||||
assert(_Py_IsImmortal(self->tp_mro));
|
||||
_Py_ClearImmortal(self->tp_mro);
|
||||
if (self->tp_mro != NULL) {
|
||||
if (PyTuple_GET_SIZE(self->tp_mro) == 0) {
|
||||
Py_CLEAR(self->tp_mro);
|
||||
}
|
||||
else {
|
||||
assert(_Py_IsImmortal(self->tp_mro));
|
||||
_Py_ClearImmortal(self->tp_mro);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -6996,12 +7002,8 @@ type_ready_pre_checks(PyTypeObject *type)
|
|||
|
||||
|
||||
static int
|
||||
type_ready_set_bases(PyTypeObject *type)
|
||||
type_ready_set_base(PyTypeObject *type)
|
||||
{
|
||||
if (lookup_tp_bases(type) != NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize tp_base (defaults to BaseObject unless that's us) */
|
||||
PyTypeObject *base = type->tp_base;
|
||||
if (base == NULL && type != &PyBaseObject_Type) {
|
||||
|
@ -7025,6 +7027,12 @@ type_ready_set_bases(PyTypeObject *type)
|
|||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
type_ready_set_type(PyTypeObject *type)
|
||||
{
|
||||
/* Initialize ob_type if NULL. This means extensions that want to be
|
||||
compilable separately on Windows can call PyType_Ready() instead of
|
||||
initializing the ob_type field of their type objects. */
|
||||
|
@ -7032,11 +7040,25 @@ type_ready_set_bases(PyTypeObject *type)
|
|||
NULL when type is &PyBaseObject_Type, and we know its ob_type is
|
||||
not NULL (it's initialized to &PyType_Type). But coverity doesn't
|
||||
know that. */
|
||||
PyTypeObject *base = type->tp_base;
|
||||
if (Py_IS_TYPE(type, NULL) && base != NULL) {
|
||||
Py_SET_TYPE(type, Py_TYPE(base));
|
||||
}
|
||||
|
||||
/* Initialize tp_bases */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
type_ready_set_bases(PyTypeObject *type)
|
||||
{
|
||||
if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
|
||||
if (!_Py_IsMainInterpreter(_PyInterpreterState_GET())) {
|
||||
assert(lookup_tp_bases(type) != NULL);
|
||||
return 0;
|
||||
}
|
||||
assert(lookup_tp_bases(type) == NULL);
|
||||
}
|
||||
|
||||
PyObject *bases = lookup_tp_bases(type);
|
||||
if (bases == NULL) {
|
||||
PyTypeObject *base = type->tp_base;
|
||||
|
@ -7446,6 +7468,12 @@ type_ready(PyTypeObject *type, int rerunbuiltin)
|
|||
if (type_ready_set_dict(type) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (type_ready_set_base(type) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (type_ready_set_type(type) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (type_ready_set_bases(type) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue