Skip to content
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
Prev Previous commit
Next Next commit
PEP 646: Various fixes to genericaliasobject.c
Based on Fidget-Spinner's feedback:
1. Remove the explicit flag for 'exhausted', instead using 'gi->obj == NULL' to tell whether the iterator is exhausted.
2. Construct `starred_tuple` using the `Py_GenericAlias` constructor instead of constructing it manually.
3. Fix reference counting.
4. Make `Py_GenericAliasIterType` static.
  • Loading branch information
mrahtz committed Jan 15, 2022
commit 9991937e5472a9d98868d1426bff09578a4b0c0f
30 changes: 7 additions & 23 deletions Objects/genericaliasobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ typedef struct {
typedef struct {
PyObject_HEAD
PyObject *obj; /* Set to NULL when iterator is exhausted */
int exhausted;
} gaiterobject;

static void
Expand Down Expand Up @@ -642,37 +641,23 @@ static PyNumberMethods ga_as_number = {

static PyObject *
ga_iternext(gaiterobject *gi) {
gaobject *alias = (gaobject *) gi->obj;

if (gi->exhausted) {
gi->obj = NULL;
if (gi->obj == NULL) {
return NULL;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like you could potentially be missing a decref here for gi->obj since I see it being increfed in gi_iter. If so,

Suggested change
return NULL;
Py_SETREF(gi->obj, NULL);
return NULL;

If I'm just shooting my mouth off, then just please ignore what I said :).

One way to test for refleaks is to run the tests with the refleak hunter (requires a debug build):

python_d.exe -m test test_typing -R 3:3

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, super nice about the refleak hunter - I had no idea that was a thing!

And good catch about the decref too. One thing I'm unsure about is where we should do it, though. Reading https://docs.python.org/3/c-api/gcsupport.html, am I right in thinking that the iterator object gi counts as a container type, because it contains references to another object? If so, that same page says "Before fields which refer to other containers are invalidated, PyObject_GC_UnTrack() must be called". That would imply we should be setting gi->obj to NULL in the deallocator, in which case we'd also call the setref there?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Friendly poke :)

}
gi->exhausted = 1;

gaobject *starred_tuple = PyObject_GC_New(gaobject, &Py_GenericAliasType);
starred_tuple->origin = alias->origin;
starred_tuple->args = alias->args;
starred_tuple->parameters = alias->parameters;
starred_tuple->weakreflist = alias->weakreflist;
starred_tuple->starred = 1;
Py_INCREF(alias->args);
// We may not have any parameters to deal with - e.g. `*tuple[int]`
if (alias->parameters != NULL) {
Py_INCREF(alias->parameters);
}
_PyObject_GC_TRACK(starred_tuple);
return (PyObject *) starred_tuple;
gaobject *alias = (gaobject *) gi->obj;
PyObject *starred_tuple = Py_GenericAlias(alias->origin, alias->args);
((gaobject * ) starred_tuple)->starred = 1;
Py_SETREF(gi->obj, NULL);
return starred_tuple;
}

static void
ga_iter_dealloc(gaiterobject *gi) {
_PyObject_GC_UNTRACK(gi);
Py_XDECREF(gi->obj);
PyObject_GC_Del(gi);
}

PyTypeObject Py_GenericAliasIterType = {
static PyTypeObject Py_GenericAliasIterType = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
.tp_name = "generic_alias_iter",
.tp_basicsize = sizeof(gaiterobject),
Expand All @@ -693,7 +678,6 @@ ga_iter(PyObject *self) {
if (gi == NULL)
return NULL;
gi->obj = self;
gi->exhausted = 0;
Py_INCREF(self);
_PyObject_GC_TRACK(gi);
return (PyObject *) gi;
Expand Down