-
-
Notifications
You must be signed in to change notification settings - Fork 30.3k
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-126083: Fix a reference leak in asyncio.Task
when reinitializing with new non-None
context
#126103
Conversation
Adding @sobolevn to the reviews since they may have some context from looking at the issue. @Nico-Posada Congrats on working on tackling your first contribution. |
Lib/test/test_asyncio/test_tasks.py
Outdated
coro = coroutine_function() | ||
task = asyncio.Task.__new__(asyncio.Task) | ||
|
||
for _ in range(10000): |
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.
Do we really need 10000 iterations to find a leak?
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.
Well, maybe not 10000, but finding leaks is certainly easier with more iterations. Maybe 1000 should do?
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 changed it to 5, the bug would be triggered every time so with a low amount you should still be able to see the ref leak.
Misc/NEWS.d/next/Library/2024-10-28-22-35-22.gh-issue-126083.TuI--n.rst
Outdated
Show resolved
Hide resolved
Seeing this output when running tests locally: test_proper_refcounts (test.test_asyncio.test_tasks.PyTask_PyFuture_SubclassTests.test_proper_refcounts) ... /Users/willingc/Code/cpython/Lib/unittest/case.py:606: RuntimeWarning: coroutine 'coroutine_function' was never awaited
result = method()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
ok |
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.
To fix the warning :)
Thanks for the detailed review @sobolevn |
Misc/NEWS.d/next/Library/2024-10-28-22-35-22.gh-issue-126083.TuI--n.rst
Outdated
Show resolved
Hide resolved
Ah that's annoying, I thought I was signed in to my GitHub account when I made that commit. Is there any way to revert this to change ownership? Not sure if I can resign the CLA with that account. |
I've done that before too, yeah. I think the only way is to overwrite the commit locally and then force push it. |
a4f3b12
to
8e5effe
Compare
Lib/test/test_asyncio/test_tasks.py
Outdated
for _ in range(5): | ||
try: | ||
task.__init__(coro, loop=loop, context=obj, name=Break()) | ||
except Exception as e: |
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.
question: do we expect this exception in all cases? if so, use with self.assertRaisesRegex(RuntimeError, 'break'):
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.
So update it to be this?
for _ in range(5):
with self.assertRaisesRegex(RuntimeError, 'break'):
task.__init__(coro, loop=loop, context=obj, name=Break())
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.
FTR: In order to catch the correct exception in #126120, I used a custom exception + a special argument so that I'm sure that I catch and expect the correct one (and not just a random one because of something else). So what I did was something like:
# what I want to catch
def foo():
raise ReachableCode(1)
# what I don't want to catch yet
def bar():
raise ReachableCode(2)
# where I call the thing I want to catch
with self.assertRaises(ReachableCode) as cm:
something_that_calls_foo()
self.assertEqual(len(cm.exception.args), 1)
self.assertIs(cm.exception.args[0], 1)
I find this pattern quite good (maybe a bit too exhaustive) because I can really see what I'm catching.
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 like the idea of the ReachableCode exception class, but I still think it's easier and more readable to just do
with self.assertRaisesRegex(ReachableCode, 'str here'):
...
and use a string in the arg instead of an int
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 think I'll go with that as well to simplify the tests on my side (but not today).
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.
LGTM as well
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.
Thanks you! Congrats on your first CPython PR! 🎉
Thanks @Nico-Posada for the PR, and @sobolevn for merging it 🌮🎉.. I'm working now to backport this PR to: 3.12, 3.13. |
…lizing with new non-`None` context (pythonGH-126103) (cherry picked from commit d07dcce6935364cab807e0df931ed09b088ade69) Co-authored-by: Nico-Posada <[email protected]>
…lizing with new non-`None` context (pythonGH-126103) (cherry picked from commit d07dcce6935364cab807e0df931ed09b088ade69) Co-authored-by: Nico-Posada <[email protected]>
GH-126229 is a backport of this pull request to the 3.13 branch. |
GH-126230 is a backport of this pull request to the 3.12 branch. |
Fix for ref leak described in #126083.
This is my first CPython PR so feedback is appreciated :)
_asyncio_Task___init___impl
in_asynciomodule.c
#126083