Skip to content

GH-81061: Fix refcount issue when returning None from a ctypes.py_object callback #13364

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

Merged

Conversation

dgelessus
Copy link
Contributor

@dgelessus dgelessus commented May 16, 2019

Right now this only adds a failing test for the issue, to check that the bug is properly detected in CI. Once that runs through I'll push the commit with the actual fix. Done

https://bugs.python.org/issue36880

Thank you to Eryk Sun for finding the cause of the bug and providing
the code fix.
@dgelessus dgelessus marked this pull request as ready for review May 16, 2019 17:46
dgelessus added a commit to dgelessus/rubicon-objc that referenced this pull request May 24, 2019
Previously, our ctypes_patch would trigger a bug in ctypes
(see https://bugs.python.org/issue36880 and python/cpython#13364),
which would eventually crash Python if done too often. This workaround
changes our ctypes_patch implementation so that it no longer triggers
the ctypes bug.

This fixes the crash reported in beeware/toga#549.
@csabella csabella requested review from pitrou and abalkin May 28, 2019 20:52
@pitrou
Copy link
Member

pitrou commented May 29, 2019

I don't feel competent to review ctypes issues, sorry. Perhaps @serhiy-storchaka

Copy link
Contributor

@kumaraditya303 kumaraditya303 left a comment

Choose a reason for hiding this comment

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

There are merge conflicts.

@bedevere-bot
Copy link

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 I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

# Conflicts:
#	Modules/_ctypes/callbacks.c
@dgelessus
Copy link
Contributor Author

Fixed the conflict, thanks. I have made the requested changes; please review again.

@bedevere-bot
Copy link

Thanks for making the requested changes!

@isidentical, @kumaraditya303: please review the changes made to this pull request.

@kumaraditya303 kumaraditya303 removed the request for review from abalkin January 2, 2023 11:01
Comment on lines +100 to +101
@support.refcount_test
def test_callback_py_object_none_return(self):
Copy link
Contributor

Choose a reason for hiding this comment

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

AFAICT, this test is rendered pointless in 3.12 due to the adoption of PEP 683 (Immortal Objects, Using a Fixed Refcount). Because None is immortal, executing Py_INCREF(Py_None) and Py_DECREF(Py_None) will no longer modify its refcount.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, good to know. I assume this isn't implemented yet though, because as of the current state of main (447d061), this test still hard-crashes without the fix.

# Allow for small variations in None's refcount from other
# sources.
self.assertAlmostEqual(
sys.getrefcount(None), none_refcount, delta=50)
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, in general we don't do these kind of tests. We have an automatic refleak detection mechanism but it will only work if the path that leaks references is exercised in the test suite. This means that you can add a test that ensures that the code you are adding to callbacks.c is actually executed but your test doesn't need to try to detect the refleak, that will be done automatically. I suppose the reason this was never detected is that we don't have a test that actually runs that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah okay. I was going by what the other tests in test_refcounts are doing. Should I adjust those as well to not check sys.getrefcount manually?

Copy link
Member

@pablogsal pablogsal Jan 3, 2023

Choose a reason for hiding this comment

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

Should I adjust those as well to not check sys.getrefcount manually?

Not as part of this issue (one issue per problem - only changing what's required for the problem at hand). I haven't checked those and maybe these are checked more specific things.

Copy link
Member

Choose a reason for hiding this comment

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

You can confirm that your test work running `./python -m test test_ctypes -R'.

Ensure that it detects the problem without your fix first :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I didn't know that just -m test works too (I used -m test.regrtest). Yes, I checked - with -R it now indeed detects the original problem.

return None

# Check that calling func does not affect None's refcount.
for _ in range(10000):
Copy link
Contributor

Choose a reason for hiding this comment

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

Single call should be enough to trigger the refleak checker.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately not... I tested again - apparently the refleak checker (with default settings: -m test --huntrleaks=: test.test_ctypes.test_refcounts) only detects if None's refcount is too high, not if it's too low. The latter case is only detected once None's refcount gets to zero/negative (which triggers an assertion), and that requires a thousand or so iterations of the broken code.

Copy link
Member

Choose a reason for hiding this comment

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

If None refcount goes too small it will crash at some point assuming the rest of the code decrements normally

Copy link
Contributor

Choose a reason for hiding this comment

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

Unfortunately not... I tested again - apparently the refleak checker (with default settings: -m test --huntrleaks=: test.test_ctypes.test_refcounts) only detects if None's refcount is too high, not if it's too low. The latter case is only detected once None's refcount gets to zero/negative (which triggers an assertion), and that requires a thousand or so iterations of the broken code.

I see, it is because of #74959.

@kumaraditya303 kumaraditya303 added type-bug An unexpected behavior, bug, or error 🔨 test-with-refleak-buildbots Test PR w/ refleak buildbots; report in status section labels Jan 8, 2023
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by @kumaraditya303 for commit 66ea175 🤖

If you want to schedule another build, you need to add the :hammer: test-with-refleak-buildbots label again.

@bedevere-bot bedevere-bot removed the 🔨 test-with-refleak-buildbots Test PR w/ refleak buildbots; report in status section label Jan 8, 2023
@kumaraditya303 kumaraditya303 changed the title bpo-36880: Fix refcount issue when returning None from a ctypes.py_object callback GH-81061: Fix refcount issue when returning None from a ctypes.py_object callback Jan 9, 2023
@kumaraditya303
Copy link
Contributor

Buildbots are happy, merging. Thanks for the PR.

@kumaraditya303 kumaraditya303 added needs backport to 3.10 only security fixes needs backport to 3.11 only security fixes labels Jan 9, 2023
@kumaraditya303 kumaraditya303 merged commit 837ba05 into python:main Jan 9, 2023
@miss-islington
Copy link
Contributor

Thanks @dgelessus for the PR, and @kumaraditya303 for merging it 🌮🎉.. I'm working now to backport this PR to: 3.10, 3.11.
🐍🍒⛏🤖

@bedevere-bot
Copy link

GH-100877 is a backport of this pull request to the 3.11 branch.

@bedevere-bot bedevere-bot removed the needs backport to 3.11 only security fixes label Jan 9, 2023
@bedevere-bot
Copy link

GH-100878 is a backport of this pull request to the 3.10 branch.

@bedevere-bot bedevere-bot removed the needs backport to 3.10 only security fixes label Jan 9, 2023
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jan 9, 2023
…es.py_object` callback (pythonGH-13364)

(cherry picked from commit 837ba05)

Co-authored-by: dgelessus <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jan 9, 2023
…es.py_object` callback (pythonGH-13364)

(cherry picked from commit 837ba05)

Co-authored-by: dgelessus <[email protected]>
miss-islington added a commit that referenced this pull request Jan 9, 2023
…object` callback (GH-13364)

(cherry picked from commit 837ba05)

Co-authored-by: dgelessus <[email protected]>
miss-islington added a commit that referenced this pull request Jan 9, 2023
…object` callback (GH-13364)

(cherry picked from commit 837ba05)

Co-authored-by: dgelessus <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tests Tests in the Lib/test dir type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants