-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
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
gh-104614: Make Sure ob_type is Always Set Correctly by PyType_Ready() #105122
Changes from all commits
fe12a90
86f8ec6
e4337e2
b680117
08a0321
80d20c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2627,6 +2627,50 @@ type_get_tp_mro(PyObject *self, PyObject *type) | |
} | ||
|
||
|
||
/* We only use 2 in test_capi/test_misc.py. */ | ||
#define NUM_BASIC_STATIC_TYPES 2 | ||
static PyTypeObject BasicStaticTypes[NUM_BASIC_STATIC_TYPES] = { | ||
#define INIT_BASIC_STATIC_TYPE \ | ||
{ \ | ||
PyVarObject_HEAD_INIT(NULL, 0) \ | ||
.tp_name = "BasicStaticType", \ | ||
.tp_basicsize = sizeof(PyObject), \ | ||
} | ||
INIT_BASIC_STATIC_TYPE, | ||
INIT_BASIC_STATIC_TYPE, | ||
#undef INIT_BASIC_STATIC_TYPE | ||
}; | ||
static int num_basic_static_types_used = 0; | ||
|
||
static PyObject * | ||
get_basic_static_type(PyObject *self, PyObject *args) | ||
{ | ||
PyObject *base = NULL; | ||
if (!PyArg_ParseTuple(args, "|O", &base)) { | ||
return NULL; | ||
} | ||
assert(base == NULL || PyType_Check(base)); | ||
|
||
if(num_basic_static_types_used >= NUM_BASIC_STATIC_TYPES) { | ||
PyErr_SetString(PyExc_RuntimeError, "no more available basic static types"); | ||
return NULL; | ||
} | ||
PyTypeObject *cls = &BasicStaticTypes[num_basic_static_types_used++]; | ||
|
||
if (base != NULL) { | ||
cls->tp_base = (PyTypeObject *)Py_NewRef(base); | ||
cls->tp_bases = Py_BuildValue("(O)", base); | ||
if (cls->tp_bases == NULL) { | ||
return NULL; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should decref There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Opened gh-105225. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for following up after-the-fact! |
||
} | ||
} | ||
if (PyType_Ready(cls) < 0) { | ||
return NULL; | ||
} | ||
return (PyObject *)cls; | ||
} | ||
|
||
|
||
// Test PyThreadState C API | ||
static PyObject * | ||
test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) | ||
|
@@ -3384,6 +3428,7 @@ static PyMethodDef TestMethods[] = { | |
{"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")}, | ||
{"type_get_tp_bases", type_get_tp_bases, METH_O}, | ||
{"type_get_tp_mro", type_get_tp_mro, METH_O}, | ||
{"get_basic_static_type", get_basic_static_type, METH_VARARGS, NULL}, | ||
{"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL}, | ||
{"frame_getlocals", frame_getlocals, METH_O, NULL}, | ||
{"frame_getglobals", frame_getglobals, METH_O, NULL}, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is nice. IMO, we should use a similar approach in
test_import
instead of the hack suggested in gh-104796.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps also gh-105085 should have been solved like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm glad you appreciate the solution 😄, but actually am a bit torn about this. On the one hand, it gets us what we want in a simple, clear way (IMHO). On the other hand, this approach means there may be code paths that don't get checked for ref leaks, which we'd want to avoid.
If we use this pattern elsewhere, we'll need to be vigilant about making sure we don't miss any ref leak coverage. I'm not sure how easy that would be generally, though it's unlikely that there are more than a handful of tests where we'd want to skip refleak detection. FWIW, in this case I don't think ref leaks are much of a concern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this skip the whole
class Test
instead of a smallerdef test_...
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, so you make sure to collect all your "ref leak unsafe" tests in a single unittest class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, create a decorator for it.