10000 bpo-40217: Make heap types always visit Py_TYPE(self) from tp_traverse by encukou · Pull Request #20433 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-40217: Make heap types always visit Py_TYPE(self) from tp_traverse #20433

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Revert "bpo-40217: Ensure Py_VISIT(Py_TYPE(self)) is always called fo…
…r PyType_FromSpec types (GH-19414)"

This reverts commit 0169d30.
  • Loading branch information
pablogsal committed May 23, 2020
commit 3bc77ee98c48eb9cafc80ad8ce40e8d35b36b301
92 changes: 1 addition & 91 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1039,42 +1039,6 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
return obj;
}

PyObject *
PyType_FromSpec_Alloc(PyTypeObject *type, Py_ssize_t nitems)
{
PyObject *obj;
const size_t size = _Py_SIZE_ROUND_UP(
_PyObject_VAR_SIZE(type, nitems+1) + sizeof(traverseproc),
SIZEOF_VOID_P);
/* note that we need to add one, for the sentinel and space for the
provided tp-traverse: See bpo-40217 for more details */

if (PyType_IS_GC(type)) {
obj = _PyObject_GC_Malloc(size);
}
else {
obj = (PyObject *)PyObject_MALLOC(size);
}

if (obj == NULL) {
return PyErr_NoMemory();
}

memset(obj, '\0', size);

if (type->tp_itemsize == 0) {
(void)PyObject_INIT(obj, type);
}
else {
(void) PyObject_INIT_VAR((PyVarObject *)obj, type, nitems);
}

if (PyType_IS_GC(type)) {
_PyObject_GC_TRACK(obj);
}
return obj;
}

PyObject *
PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
{
Expand Down Expand Up @@ -2910,36 +2874,6 @@ static const short slotoffsets[] = {
#include "typeslots.inc"
};

static int
PyType_FromSpec_tp_traverse(PyObject *self, visitproc visit, void *arg)
{
PyTypeObject *parent = Py_TYPE(self);

// Only a instance of a type that is directly created by
// PyType_FromSpec (not subclasses) must visit its parent.
if (parent->tp_traverse == PyType_FromSpec_tp_traverse) {
Py_VISIT(parent);
}

// Search for the original type that was created using PyType_FromSpec
PyTypeObject *base;
base = parent;
while (base->tp_traverse != PyType_FromSpec_tp_traverse) {
base = base->tp_base;
assert(base);
}

// Extract the user defined traverse function that we placed at the end
// of the type and call it.
size_t size = Py_SIZE(base);
size_t _offset = _PyObject_VAR_SIZE(&PyType_Type, size+1);
traverseproc fun = *(traverseproc*)((char*)base + _offset);
if (fun == NULL) {
return 0;
}
return fun(self, visit, arg);
}

PyObject *
PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
{
Expand Down Expand Up @@ -2985,7 +2919,7 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
}
}

res = (PyHeapTypeObject*)PyType_FromSpec_Alloc(&PyType_Type, nmembers);
res = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, nmembers);
if (res == NULL)
return NULL;
res_start = (char*)res;
Expand Down Expand Up @@ -3093,30 +3027,6 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
memcpy(PyHeapType_GET_MEMBERS(res), slot->pfunc, len);
type->tp_members = PyHeapType_GET_MEMBERS(res);
}
else if (slot->slot == Py_tp_traverse) {

/* Types created by PyType_FromSpec own a strong reference to their
* type, but this was added in Python 3.8. The tp_traverse function
* needs to call Py_VISIT on the type but all existing traverse
* functions cannot be updated (especially the ones from existing user
* functions) so we need to provide a tp_traverse that manually calls
* Py_VISIT(Py_TYPE(self)) and then call the provided tp_traverse. In
* this way, user functions do not need to be updated, preserve
* backwards compatibility.
*
* We store the user-provided traverse function at the end of the type
* (we have allocated space for it) so we can call it from our
* PyType_FromSpec_tp_traverse wrapper.
*
* Check bpo-40217 for more information and rationale about this issue.
*
* */

type->tp_traverse = PyType_FromSpec_tp_traverse;
size_t _offset = _PyObject_VAR_SIZE(&PyType_Type, nmembers+1);
traverseproc *user_traverse = (traverseproc*)((char*)type + _offset);
*user_traverse = slot->pfunc;
}
else {
/* Copy other slots directly */
*(void**)(res_start + slotoffsets[slot->slot]) = slot->pfunc;
Expand Down
0