Skip to content
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

Improve Python 3.11 support #3694

Merged
merged 21 commits into from
Mar 2, 2022

Conversation

Skylion007
Copy link
Collaborator

@Skylion007 Skylion007 commented Feb 7, 2022

Description

  • Unfortunately, 3.11a uncovered a bug in our multi-inheritance code that may cause memory leaks with dynamic_attrs, will deal with a follow up PR.
  • Fixes a compilation error caused by 3.11 requiring the use of the helper to get the f_back. This PR also backports the reference counting behavior of newer pythons (f_back being a strong reference that needs to be decremented).
  • Closes [BUG]: Remove Python 3.11/PyPy dispatch workaround #3530 by removing the workaround

Suggested changelog entry:

* Better support for Python 3.11 alphas.

@Skylion007 Skylion007 added the python dev Working on development versions of Python label Feb 7, 2022
@Skylion007 Skylion007 closed this Feb 7, 2022
@Skylion007 Skylion007 reopened this Feb 7, 2022
@Skylion007 Skylion007 requested review from henryiii and rwgk February 7, 2022 16:41
@Skylion007 Skylion007 changed the title Test 311 frame changes Python 3.11 support Feb 7, 2022
@Skylion007
Copy link
Collaborator Author

Okay, I have narrowed down the problem. It causes an MRO issue under these conditions:

  1. A type has multiple inheritance
  2. One of the bases has dynamic_attrs enabled
  3. The first base does NOT have dynamic_attrs enabled.

This causes the multiple inheritance code complain similar to issue #597 . We fixed that one by ensuring all classes have the same metaclass. Something breaks this fix in 3.11.

@@ -204,7 +204,9 @@ TEST_SUBMODULE(multiple_inheritance, m) {
m.def("i801e_b2", []() -> I801B2 * { return new I801E(); });

// test_mi_static_properties
py::class_<Vanilla>(m, "Vanilla").def(py::init<>()).def("vanilla", &Vanilla::vanilla);
py::class_<Vanilla>(m, "Vanilla", py::dynamic_attr())
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Making all bases in the hierarchy either static or dynamic_attrs works, but is not a tenable solution.

@Skylion007 Skylion007 changed the title Python 3.11 support Improve Python 3.11 support Feb 28, 2022
@@ -514,7 +515,14 @@ PYBIND11_NOINLINE std::string error_string() {
errorString += " " + handle(f_code->co_filename).cast<std::string>() + "("
+ std::to_string(lineno)
+ "): " + handle(f_code->co_name).cast<std::string>() + "\n";
frame = frame->f_back;
# if PY_VERSION_HEX >= 0x030900B1
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Nit: Maybe we should add a backport section details/common.h . I just wasn't sure if the recommend static inline stuff would cause any nasty ODR / LTO issues so I left it as is.

@tacaswell
Copy link

This fixes compiling scipy with py311.

@rwgk
Copy link
Collaborator

rwgk commented Feb 28, 2022

I looked a bit but have questions for my understanding:

Is it true that

  • the change in pybind11.h is purely a 3.11 compatibility fix?

  • the change in type_caster_base.h is for 3.11 compatibility, but also an actual fix for a bug that exists already pre 3.11? (Does the fix involve the Py_XINCREF(frame); and matching Py_DECREF(frame);?)

It would be useful to explain in a couple sentences in the PR description.

@Skylion007
Copy link
Collaborator Author

@rwgk This fixes 3.11 compatability. The issue is the new API returns a strong reference (instead of a weak reference) which means we need to decref it. The easiest way to handle this was to have the old code path make a strong reference too. I'll edit the PR description.

Copy link
Collaborator

@rwgk rwgk left a comment

Choose a reason for hiding this comment

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

The changes LGTM, too, but I'm wondering about

  • @Skylion007 I didn't see edits to the PR description, would be nice to have them.
  • the valgrind error looks like it needs attention
  • is it OK to ignore the upstream failure?

@Skylion007
Copy link
Collaborator Author

@rwgk Good catch on the Valgrind error, seems I am not doing the incref / decrefs properly. Thoughts @henryiii ?

@Skylion007
Copy link
Collaborator Author

Thanks for pointing out that issue @henryiii. Looks good to me now.

@rwgk
Copy link
Collaborator

rwgk commented Mar 1, 2022

I'll run some quick interactive tests in with the Google toolchain.

include/pybind11/pybind11.h Outdated Show resolved Hide resolved
@rwgk
Copy link
Collaborator

rwgk commented Mar 1, 2022

I did a manual & embarrassingly simple leak check (diff below + top command), with Python 3.7 and 3.9. I'm happy to report I didn't see a leak. (I identified that test by inserting an assert in the middle of the changed code in type_caster_base.h)

ASAN testing was happy, too.

+++ b/tests/test_exceptions.py
@@ -246,6 +246,7 @@ def test_throw_nested_exception():

 # This can often happen if you wrap a pybind11 class in a Python wrapper
 def test_invalid_repr():
+  while True:
     class MyRepr:
         def __repr__(self):
             raise AttributeError("Example error")

@Skylion007 Skylion007 merged commit 42a8e31 into pybind:master Mar 2, 2022
@Skylion007 Skylion007 deleted the test-311-frame-changes branch March 2, 2022 18:18
@github-actions github-actions bot added the needs changelog Possibly needs a changelog entry label Mar 2, 2022
henryiii added a commit to henryiii/pybind11 that referenced this pull request Mar 2, 2022
* Test out Python 3.11 migration

* Clean up a bit

* Remove todo

* Test workaround

* Fix potential bug uncovered in 3.11

* Try to fix it more

* last ditch fix

* Revert. Tp-traverse isn't the problem

* Test workaround

* Try this hack

* Revert MRO changes

* Use f_back properly

* Qualify auto

* Update include/pybind11/pybind11.h

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Simplify code slightly

* Ensure co_varnames decref if dict_getitem throws

* Eager decref f_code

Co-authored-by: Henry Schreiner <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
henryiii added a commit that referenced this pull request Mar 2, 2022
* Test out Python 3.11 migration

* Clean up a bit

* Remove todo

* Test workaround

* Fix potential bug uncovered in 3.11

* Try to fix it more

* last ditch fix

* Revert. Tp-traverse isn't the problem

* Test workaround

* Try this hack

* Revert MRO changes

* Use f_back properly

* Qualify auto

* Update include/pybind11/pybind11.h

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Simplify code slightly

* Ensure co_varnames decref if dict_getitem throws

* Eager decref f_code

Co-authored-by: Henry Schreiner <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
@henryiii henryiii removed the needs changelog Possibly needs a changelog entry label Mar 29, 2022
svenevs added a commit to svenevs/pybind11 that referenced this pull request Nov 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
python dev Working on development versions of Python
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG]: Remove Python 3.11/PyPy dispatch workaround
4 participants