summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorPetr Viktorin <encukou@gmail.com>2021-10-21 09:46:20 (GMT)
committerGitHub <noreply@github.com>2021-10-21 09:46:20 (GMT)
commit8a310dd5f4242b5d28013c1905c6573477e3b957 (patch)
tree9d028d11dbdf09621435c9b62d13d24d480823e5 /Objects
parent2cbf50e8126905b57ba9d0d5aa4e238c817d5a03 (diff)
downloadcpython-8a310dd5f4242b5d28013c1905c6573477e3b957.zip
cpython-8a310dd5f4242b5d28013c1905c6573477e3b957.tar.gz
cpython-8a310dd5f4242b5d28013c1905c6573477e3b957.tar.bz2
bpo-45315: PyType_FromSpec: Copy spec->name and have the type own the memory for its name (GH-29103)
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typeobject.c51
1 files changed, 36 insertions, 15 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index aa07333..18bea47 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -2778,6 +2778,7 @@ type_new_alloc(type_new_ctx *ctx)
et->ht_name = Py_NewRef(ctx->name);
et->ht_module = NULL;
+ et->_ht_tpname = NULL;
return type;
}
@@ -3435,25 +3436,42 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
goto fail;
}
+ type = &res->ht_type;
+ /* The flags must be initialized early, before the GC traverses us */
+ type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE;
+
/* Set the type name and qualname */
const char *s = strrchr(spec->name, '.');
- if (s == NULL)
+ if (s == NULL) {
s = spec->name;
- else
+ }
+ else {
s++;
+ }
- type = &res->ht_type;
- /* The flags must be initialized early, before the GC traverses us */
- type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE;
res->ht_name = PyUnicode_FromString(s);
- if (!res->ht_name)
+ if (!res->ht_name) {
+ goto fail;
+ }
+ res->ht_qualname = Py_NewRef(res->ht_name);
+
+ /* Copy spec->name to a buffer we own.
+ *
+ * Unfortunately, we can't use tp_name directly (with some
+ * flag saying that it should be deallocated with the type),
+ * because tp_name is public API and may be set independently
+ * of any such flag.
+ * So, we use a separate buffer, _ht_tpname, that's always
+ * deallocated with the type (if it's non-NULL).
+ */
+ Py_ssize_t name_buf_len = strlen(spec->name) + 1;
+ res->_ht_tpname = PyMem_Malloc(name_buf_len);
+ if (res->_ht_tpname == NULL) {
goto fail;
- res->ht_qualname = res->ht_name;
- Py_INCREF(res->ht_qualname);
- type->tp_name = spec->name;
+ }
+ type->tp_name = memcpy(res->_ht_tpname, spec->name, name_buf_len);
- Py_XINCREF(module);
- res->ht_module = module;
+ res->ht_module = Py_XNewRef(module);
/* Adjust for empty tuple bases */
if (!bases) {
@@ -4082,6 +4100,7 @@ type_dealloc(PyTypeObject *type)
_PyDictKeys_DecRef(et->ht_cached_keys);
}
Py_XDECREF(et->ht_module);
+ PyMem_Free(et->_ht_tpname);
Py_TYPE(type)->tp_free((PyObject *)type);
}
@@ -4273,10 +4292,12 @@ type_traverse(PyTypeObject *type, visitproc visit, void *arg)
Py_VISIT(type->tp_base);
Py_VISIT(((PyHeapTypeObject *)type)->ht_module);
- /* There's no need to visit type->tp_subclasses or
- ((PyHeapTypeObject *)type)->ht_slots, because they can't be involved
- in cycles; tp_subclasses is a list of weak references,
- and slots is a tuple of strings. */
+ /* There's no need to visit others because they can't be involved
+ in cycles:
+ type->tp_subclasses is a list of weak references,
+ ((PyHeapTypeObject *)type)->ht_slots is a tuple of strings,
+ ((PyHeapTypeObject *)type)->ht_*name are strings.
+ */
return 0;
}