8000 gh-92112: Fix crash triggered by an evil custom `mro()` (#92113) · python/cpython@85354ed · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 85354ed

Browse files
author
Alexey Izbyshev
authored
gh-92112: Fix crash triggered by an evil custom mro() (#92113)
1 parent adcb6a6 commit 85354ed

File tree

3 files changed

+29
-9
lines changed

3 files changed

+29
-9
lines changed

Lib/test/test_descr.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5784,6 +5784,23 @@ def mro(cls):
57845784
class A(metaclass=M):
57855785
pass
57865786

5787+
def test_disappearing_custom_mro(self):
5788+
"""
5789+
gh-92112: A custom mro() returning a result conflicting with
5790+
__bases__ and deleting itself caused a double free.
5791+
"""
5792+
class B:
5793+
pass
5794+
5795+
class M(DebugHelperMeta):
5796+
def mro(cls):
5797+
del M.mro
5798+
return (B,)
5799+
5800+
with self.assertRaises(TypeError):
5801+
class A(metaclass=M):
5802+
pass
5803+
57875804

57885805
if __name__ == "__main__":
57895806
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix crash triggered by an evil custom ``mro()`` on a metaclass.

Objects/typeobject.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -345,22 +345,26 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
345345
Py_ssize_t i, n;
346346
int custom = !Py_IS_TYPE(type, &PyType_Type);
347347
int unbound;
348-
PyObject *mro_meth = NULL;
349-
PyObject *type_mro_meth = NULL;
350348

351349
if (custom) {
350+
PyObject *mro_meth, *type_mro_meth;
352351
mro_meth = lookup_maybe_method(
353352
(PyObject *)type, &_Py_ID(mro), &unbound);
354-
if (mro_meth == NULL)
353+
if (mro_meth == NULL) {
355354
goto clear;
355+
}
356356
type_mro_meth = lookup_maybe_method(
357357
(PyObject *)&PyType_Type, &_Py_ID(mro), &unbound);
358-
if (type_mro_meth == NULL)
358+
if (type_mro_meth == NULL) {
359+
Py_DECREF(mro_meth);
359360
goto clear;
360-
if (mro_meth != type_mro_meth)
361+
}
362+
int custom_mro = (mro_meth != type_mro_meth);
363+
Py_DECREF(mro_meth);
364+
Py_DECREF(type_mro_meth);
365+
if (custom_mro) {
361366
goto clear;
362-
Py_XDECREF(mro_meth);
363-
Py_XDECREF(type_mro_meth);
367+
}
364368
}
365369
n = PyTuple_GET_SIZE(bases);
366370
for (i = 0; i < n; i++) {
@@ -373,8 +377,6 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
373377
}
374378
return;
375379
clear:
376-
Py_XDECREF(mro_meth);
377-
Py_XDECREF(type_mro_meth);
378380
type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
379381
type->tp_version_tag = 0; /* 0 is not a valid version tag */
380382
}

0 commit comments

Comments
 (0)
0