mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
[3.13] gh-132835: Add defensive NULL checks to MRO resolution (GH-134763) (GH-140437)
Currently, there are a few places where tp_mro could theoretically
become NULL, but do not in practice. This commit adds defensive checks for
NULL values to ensure that any changes do not introduce a crash and that
state invariants are upheld.
The assertions added in this commit are all instances where a NULL value would get passed to something not expecting a NULL, so it is better to catch an assertion failure than crash later on.
There are a few cases where it is OK for the return of lookup_tp_mro to be NULL, such as when passed to is_subtype_with_mro, which handles this explicitly.
(cherry picked from commit a8edca62fc)
Co-authored-by: Emma Smith <emma@emmatyping.dev>
This commit is contained in:
parent
69230d1c56
commit
30c2661b6e
1 changed files with 10 additions and 4 deletions
|
|
@ -1499,7 +1499,7 @@ static int recurse_down_subclasses(PyTypeObject *type, PyObject *name,
|
|||
update_callback callback, void *data);
|
||||
|
||||
static int
|
||||
mro_hierarchy(PyTypeObject *type, PyObject *temp)
|
||||
mro_hierarchy_for_complete_type(PyTypeObject *type, PyObject *temp)
|
||||
{
|
||||
ASSERT_TYPE_LOCK_HELD();
|
||||
|
||||
|
|
@ -1510,6 +1510,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
|
|||
return res;
|
||||
}
|
||||
PyObject *new_mro = lookup_tp_mro(type);
|
||||
assert(new_mro != NULL);
|
||||
|
||||
PyObject *tuple;
|
||||
if (old_mro != NULL) {
|
||||
|
|
@ -1554,7 +1555,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
|
|||
Py_ssize_t n = PyList_GET_SIZE(subclasses);
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
PyTypeObject *subclass = _PyType_CAST(PyList_GET_ITEM(subclasses, i));
|
||||
res = mro_hierarchy(subclass, temp);
|
||||
res = mro_hierarchy_for_complete_type(subclass, temp);
|
||||
if (res < 0) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -1636,7 +1637,7 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, void *context)
|
|||
if (temp == NULL) {
|
||||
goto bail;
|
||||
}
|
||||
if (mro_hierarchy(type, temp) < 0) {
|
||||
if (mro_hierarchy_for_complete_type(type, temp) < 0) {
|
||||
goto undo;
|
||||
}
|
||||
Py_DECREF(temp);
|
||||
|
|
@ -2865,6 +2866,7 @@ mro_implementation_unlocked(PyTypeObject *type)
|
|||
*/
|
||||
PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, 0));
|
||||
PyObject *base_mro = lookup_tp_mro(base);
|
||||
assert(base_mro != NULL);
|
||||
Py_ssize_t k = PyTuple_GET_SIZE(base_mro);
|
||||
PyObject *result = PyTuple_New(k + 1);
|
||||
if (result == NULL) {
|
||||
|
|
@ -2899,9 +2901,12 @@ mro_implementation_unlocked(PyTypeObject *type)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *mro_to_merge;
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, i));
|
||||
to_merge[i] = lookup_tp_mro(base);
|
||||
mro_to_merge = lookup_tp_mro(base);
|
||||
assert(mro_to_merge != NULL);
|
||||
to_merge[i] = mro_to_merge;
|
||||
}
|
||||
to_merge[n] = bases;
|
||||
|
||||
|
|
@ -8014,6 +8019,7 @@ type_ready_inherit(PyTypeObject *type)
|
|||
|
||||
// Inherit slots
|
||||
PyObject *mro = lookup_tp_mro(type);
|
||||
assert(mro != NULL);
|
||||
Py_ssize_t n = PyTuple_GET_SIZE(mro);
|
||||
for (Py_ssize_t i = 1; i < n; i++) {
|
||||
PyObject *b = PyTuple_GET_ITEM(mro, i);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue