[Python-checkins] bpo-42412: Fix possible leaks and check arguments in PyType_FromModuleAndSpec() (GH-23410)

miss-islington webhook-mailer at python.org
Sat Nov 21 06:09:44 EST 2020


https://github.com/python/cpython/commit/d153eb8a1e47123ecdb3fb47995a2c39ce7713ea
commit: d153eb8a1e47123ecdb3fb47995a2c39ce7713ea
branch: 3.9
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2020-11-21T03:09:40-08:00
summary:

bpo-42412: Fix possible leaks and check arguments in PyType_FromModuleAndSpec() (GH-23410)


* There were leaks if Py_tp_bases is used more than once or if some call is
  failed before setting tp_bases.
* There was a crash if the bases argument or the Py_tp_bases slot is not a tuple.
* The documentation was not accurate.
(cherry picked from commit 1db76394ea79030aa4ed5349c950f6c6da51450f)

Co-authored-by: Serhiy Storchaka <storchaka at gmail.com>

files:
M Doc/c-api/type.rst
M Objects/typeobject.c

diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst
index 73f26875d8194..822360e06170d 100644
--- a/Doc/c-api/type.rst
+++ b/Doc/c-api/type.rst
@@ -155,7 +155,8 @@ The following functions and structs are used to create
    If *bases* is a tuple, the created heap type contains all types contained
    in it as base types.
 
-   If *bases* is ``NULL``, the *Py_tp_base* slot is used instead.
+   If *bases* is ``NULL``, the *Py_tp_bases* slot is used instead.
+   If that also is ``NULL``, the *Py_tp_base* slot is used instead.
    If that also is ``NULL``, the new type derives from :class:`object`.
 
    The *module* argument can be used to record the module in which the new
@@ -247,7 +248,8 @@ The following functions and structs are used to create
       * :c:member:`~PyBufferProcs.bf_getbuffer`
       * :c:member:`~PyBufferProcs.bf_releasebuffer`
 
-      Setting :c:data:`Py_tp_bases` may be problematic on some platforms.
+      Setting :c:data:`Py_tp_bases` or :c:data:`Py_tp_base` may be
+      problematic on some platforms.
       To avoid issues, use the *bases* argument of
       :py:func:`PyType_FromSpecWithBases` instead.
 
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 1a12b0ce07fcf..acbe3fa3b5a7f 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -2951,26 +2951,40 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
                 base = slot->pfunc;
             else if (slot->slot == Py_tp_bases) {
                 bases = slot->pfunc;
-                Py_INCREF(bases);
             }
         }
-        if (!bases)
+        if (!bases) {
             bases = PyTuple_Pack(1, base);
-        if (!bases)
+            if (!bases)
+                goto fail;
+        }
+        else if (!PyTuple_Check(bases)) {
+            PyErr_SetString(PyExc_SystemError, "Py_tp_bases is not a tuple");
             goto fail;
+        }
+        else {
+            Py_INCREF(bases);
+        }
     }
-    else
+    else if (!PyTuple_Check(bases)) {
+        PyErr_SetString(PyExc_SystemError, "bases is not a tuple");
+        goto fail;
+    }
+    else {
         Py_INCREF(bases);
+    }
 
     /* Calculate best base, and check that all bases are type objects */
     base = best_base(bases);
     if (base == NULL) {
+        Py_DECREF(bases);
         goto fail;
     }
     if (!_PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) {
         PyErr_Format(PyExc_TypeError,
                      "type '%.100s' is not an acceptable base type",
                      base->tp_name);
+        Py_DECREF(bases);
         goto fail;
     }
 
@@ -2982,7 +2996,6 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
     type->tp_as_buffer = &res->as_buffer;
     /* Set tp_base and tp_bases */
     type->tp_bases = bases;
-    bases = NULL;
     Py_INCREF(base);
     type->tp_base = base;
 



More information about the Python-checkins mailing list