diff options
author | Petr Viktorin <encukou@gmail.com> | 2021-10-21 09:46:20 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-21 09:46:20 (GMT) |
commit | 8a310dd5f4242b5d28013c1905c6573477e3b957 (patch) | |
tree | 9d028d11dbdf09621435c9b62d13d24d480823e5 /Objects | |
parent | 2cbf50e8126905b57ba9d0d5aa4e238c817d5a03 (diff) | |
download | cpython-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.c | 51 |
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; } |