-
-
Notifications
You must be signed in to change notification settings - Fork 31.5k
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-95348: Split clear_weakref into two functions #95449
Conversation
Most changes to Python require a NEWS entry. Please add it using the blurb_it web app or the blurb command-line tool. |
2e5d65d
to
037ee37
Compare
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've left some comments.
Most importantly, the weakref should be removed from the weaklist before clear_weakref()
is called, not after.
then the weakref list itself (and thus the value of *list) will | ||
end up being set to NULL. */ | ||
*list = self->wr_next; | ||
self->wr_object = Py_None; |
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.
Clearing wr_object
should still happen in clear_weakref()
, not remove_weakref()
.
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.
The thing is, the program segfaults when I reverse the order of remove before clear
weaklist_remove_weakref(list, *list);
clear_weakref(*list);
causes a segfault for me.
Objects/weakrefobject.c
Outdated
if (callback != NULL) { | ||
Py_DECREF(callback); | ||
self->wr_callback = NULL; | ||
} | ||
} | ||
|
||
/* This function removes the pass in reference from the list of weak |
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 function removes the pass in reference from the list of weak | |
/* This function removes the passed-in reference from the list of weak |
Objects/weakrefobject.c
Outdated
/* This function is responsible for clearing the callback slot. When using this | ||
* function it must be called before calling remove_weakref_from_referent, | ||
* otherwise a segmentation fault will occur at build time. |
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.
The function should be clearing the weakref object. So:
/* This function is responsible for clearing the callback slot. When using this | |
* function it must be called before calling remove_weakref_from_referent, | |
* otherwise a segmentation fault will occur at build time. | |
/* This function clears the passed-in reference. It must have been removed | |
* from the weaklist already. (See weaklist_remove_weakref().) |
Objects/weakrefobject.c
Outdated
* references for the referent. This should be called from | ||
* remove_weakref_fromt_referent as it will pass the required list | ||
* argument. |
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.
There is no need for that last sentence.
* references for the referent. This should be called from | |
* remove_weakref_fromt_referent as it will pass the required list | |
* argument. | |
* references for the referent. |
self->wr_next = NULL; | ||
} | ||
|
||
/* This function removes the pass in reference from the list of weak references |
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 function removes the pass in reference from the list of weak references | |
/* This function removes the passed-in reference from the list of weak references |
Objects/weakrefobject.c
Outdated
end up being set to NULL. */ | ||
*list = self->wr_next; | ||
} | ||
self->wr_object = Py_None; |
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 belongs in clear_weakref()
.
self->wr_object = Py_None; |
Split ``clear_weakref`` into two functions: ``clear_weakref`` | ||
and ``remove_weakref``. Abstracts ``remove_weakref`` with | ||
``remove_weakref_from_referent`` in weakrefobject.c. | ||
Patch by Robert O'Shea. |
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 not sure that a NEWS entry is warranted. If this PR changes any behavior then something has gone wrong, so there isn't anything to communicate to users. This change is strictly about slightly improving the clarity of the Objects/weakrefobject.c code. That sort of minor maintainability improvement typically does not get a NEWS entry.
Objects/weakrefobject.c
Outdated
* argument. | ||
*/ | ||
static void | ||
remove_weakref(PyWeakReference *self, PyWeakReference **list) |
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 function is an operation on a weaklist, rather than on a single weakref, so let's change the name and signature accordingly:
remove_weakref(PyWeakReference *self, PyWeakReference **list) | |
weaklist_remove_ref(PyWeakReference **list, PyWeakReference *ref) |
Objects/weakrefobject.c
Outdated
* for the referent. This should be called after clear_weakref, otherwise a | ||
* segmentation fault will occur at build time. |
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.
We don't need to mention segfaulting.
* for the referent. This should be called after clear_weakref, otherwise a | |
* segmentation fault will occur at build time. | |
* for the referent. This should always be called before clear_weakref(). |
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
Objects/weakrefobject.c
Outdated
@@ -958,8 +983,11 @@ PyObject_ClearWeakRefs(PyObject *object) | |||
/* Remove the callback-less basic and proxy references */ | |||
if (*list != NULL && (*list)->wr_callback == NULL) { | |||
clear_weakref(*list); | |||
if (*list != NULL && (*list)->wr_callback == NULL) | |||
remove_weakref_from_referent(*list); |
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.
Here we already have the list, so we should use weaklist_remove_weakref()
directly:
remove_weakref_from_referent(*list); | |
weaklist_remove_weakref(list, *list); |
Objects/weakrefobject.c
Outdated
clear_weakref(*list); | ||
remove_weakref_from_referent(*list); |
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.
Likewise with weaklist_remove_weakref()
.
Objects/weakrefobject.c
Outdated
@@ -972,6 +1000,7 @@ PyObject_ClearWeakRefs(PyObject *object) | |||
|
|||
current->wr_callback = NULL; | |||
clear_weakref(current); | |||
remove_weakref_from_referent(current); |
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.
Likewise with weaklist_remove_weakref()
.
Objects/weakrefobject.c
Outdated
@@ -1002,6 +1031,7 @@ PyObject_ClearWeakRefs(PyObject *object) | |||
} | |||
current->wr_callback = NULL; | |||
clear_weakref(current); | |||
remove_weakref_from_referent(current); |
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.
Likewise with weaklist_remove_weakref()
.
Objects/weakrefobject.c
Outdated
@@ -1036,5 +1066,6 @@ _PyStaticType_ClearWeakRefs(PyTypeObject *type) | |||
weaklist before clearing its wr_object and wr_callback. | |||
That is how we're able to loop over the list. */ | |||
clear_weakref((PyWeakReference *)*list); | |||
remove_weakref_from_referent((PyWeakReference *)*list); |
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.
Likewise with weaklist_remove_weakref()
.
The issue with calling clear first is that wr_object is set to Py_None. Making it impossible to get the list after the fact. |
037ee37
to
355625a
Compare
(This advice applies to everyone, not just you. 😄) FYI, there are downsides to force-pushing once other people have started interacting with a PR:
So I recommend that, as soon as others are interacting with your PR (e.g. reviewing), you should avoid force-pushing. If you need to update the base branch (e.g. main) then use "merge" instead. All that said, force-pushing is usually fine up to the point that other people start looking at the PR. Personally, I use force-push extensively, but try to stick to the above advice (once others start participating). |
That only matters if you use |
I have made the requested changes; please review again This should be correct now. Apologies for the issue with the force push. |
Thanks for making the requested changes! @ericsnowcurrently: please review the changes made to this pull request. |
Fixes #95348
Moves the removal of the passed in reference from a list to a function called
remove_weakref
adding a parameter calledlist
that is a list of weak references. Then to abstract the need to get this list a functionremove_weakref_from_referent
has been added to automatically pass the list to theremove_weakref
.This is added to make the process more transparent as to what it is doing because as the issue mentions that where
clear_weakref
is used it isn't clear what it is doing.Functions added:
remove_weakref
remove_weakref_from_referent
remove_weakref
shouldn't be called by itself asremove_weakref_from_referent
will call it and pass the list of references.Also
remove_weakref_from_referent
should always be called after `clear_weakref, otherwise a segmentation fault will occur.3 tests were found to have failed but seem to occur even without changes to code: