Skip to content

[smart_holder] Unique ptr deleter roundtrip tests and fix #4921

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
merged 13 commits into from
Nov 8, 2023

Conversation

iwanders
Copy link
Contributor

@iwanders iwanders commented Nov 5, 2023

Description

@rwgk , as promised; followup to #4850, this PR ensures custom deleters are propagated correctly and keep their state.

I only saw the note about conventional commits when I filed this PR, so their descriptions aren't that good, the work is mostly split out though in individual commits;

  • 7cc1e1f a failing unit test was introduced showing the deleter got lost.
  • 5b00921 subsequently fixes that.
  • ad7eaa4 adds a unit test for std::unique_ptr<atyp const, custom_deleter>, similar how the other default delete unit tests had that.
  • a49a7ce Fixes that new unit test for const atyp.
  • eb05f97 Removes the assignment in case the 'use_del_fun' is false, I don't think this is necessary as the code in smart_holder_poc guarantees that the del_fun is used in case there's anything but the default deleter, and for the default deleters no special handling is necessary.

Unit tests make check all pass, I ran clang format 13 on the files I touched, but didn't see a make format or anything along those lines, so it wouldn't surprise me if some linters still fail.

Happy to iterate, but feel free to push commits to this branch as you see fit. Filing as draft first before involving other code owners.

Somewhat related observation

One thing that stood out to me was this line;

delete static_cast<T *>(raw_ptr);

I feel that shouldn't be doing a delete, but instead do:

   std::default_delete<T>{}(raw_ptr);

Because the trait system that std::default_delete provides can be considered an extension point of the standard library, and calling delete would bypass any specializations that are provided.

Suggested changelog entry:

Custom deleters in unique_ptrs are stored and extracted correctly from the smart holder.

Feels like there's still a gap around the raw pointer flavour, but this at least
makes the unit test of the previous commit succeed.
Currently failing, custom deleter is lost.
Unit test from the previous commit passes.
At the construction of the smart holder, it is either a del_fun, or a default constructed deleter, so this complexity is unnecessary.
@iwanders iwanders force-pushed the unique_ptr_destructor_roundtrip branch 2 times, most recently from 1bc9821 to 711b158 Compare November 5, 2023 17:58
Clang 3.6 requires the extra constructors in the custom_deleter.
@iwanders iwanders force-pushed the unique_ptr_destructor_roundtrip branch from 711b158 to 8800800 Compare November 5, 2023 19:07
@rwgk
Copy link
Collaborator

rwgk commented Nov 6, 2023

@iwanders wrote (in the PR description):


One thing that stood out to me was this line;

delete static_cast<T *>(raw_ptr);

I feel that shouldn't be doing a delete, but instead do:

   std::default_delete<T>{}(raw_ptr);

I agree. I didn't think deeply at all about that line.

Do you want to fix that in a separate small PR on the side?

@iwanders
Copy link
Contributor Author

iwanders commented Nov 6, 2023

Oh, oops, I forgot std::make_unique is c++14 and not 11 😬 let me fix that.

Edit, should be fixed with 25c2e40

@iwanders iwanders force-pushed the unique_ptr_destructor_roundtrip branch 2 times, most recently from 6753d03 to 25c2e40 Compare November 6, 2023 23:48
@iwanders iwanders force-pushed the unique_ptr_destructor_roundtrip branch from 25c2e40 to 2c4fbda Compare November 7, 2023 00:05
@iwanders
Copy link
Contributor Author

iwanders commented Nov 7, 2023

Previous CI failed on c++20, the explicit string constructor is a requirement if we remove the default constructor, otherwise we can't instantiate the unique pointer in the unit test. Quick minimal example with compile error.

And force pushed again to fix clang tidy with f2f87f0, 🤞 should be in the clear now...

@iwanders iwanders force-pushed the unique_ptr_destructor_roundtrip branch from 2c4fbda to f2f87f0 Compare November 7, 2023 00:19
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.

I'll run some internal testing with this PR as is. My suggestions don't change anything substantial. Thanks!

@iwanders iwanders force-pushed the unique_ptr_destructor_roundtrip branch from 08a5015 to 5c062eb Compare November 7, 2023 13:07
@rwgk
Copy link
Collaborator

rwgk commented Nov 7, 2023

The latest commits all look good to me, thanks!

I'm not surprised by the test failures, most likely they're very easy to fix, like this:

assert re.match("passenger(_MvCtor)*_MvCtor", m.get_mtxt(recycled))

@rwgk
Copy link
Collaborator

rwgk commented Nov 7, 2023

I'll run some internal testing with this PR as is. My suggestions don't change anything substantial. Thanks!

Unit testing with all sanitizers in the Google toolchain passes. (as expected)

Global testing just changing pybind11 passes. (as expected; there are only a handful of smart_holder uses this way)

None of the remaining PyCLIF-pybind11 global test failures is fixed by this PR. (I had some wishful thinking some may be fixed.) — This was a "rerun" of global testing, after adding in this PR.

Fresh global testing — with this PR included from the start — with PyCLIF-pybind11 exercises the smart_holder functionality in vastly more situations, but it is very expensive. I'll do that next weekend at the latest. (It might need a little bit of trickery to determine for certain if this PR fixed latent bugs.)

@iwanders iwanders force-pushed the unique_ptr_destructor_roundtrip branch from c8214f5 to 21bbcd0 Compare November 7, 2023 23:38
@iwanders
Copy link
Contributor Author

iwanders commented Nov 7, 2023

I'm not surprised by the test failures, most likely they're very easy to fix, like this:

Awesome, thanks for that suggestion, I was surprised tbh, I would've expected the amount of move constructors to be equal on between the compilers, but guess there's still some variation in how they implement the language. Pipeline is running with that suggested fix now 🤞

None of the remaining PyCLIF-pybind11 global test failures is fixed by this PR. (I had some wishful thinking some may be fixed.) — This was a "rerun" of global testing, after adding in this PR.

Heh, well, I don't think too many people use a unique pointer with a custom deleter, so not too surprised. Regardless, it's a good improvement and I had fun doing some C++ for a good cause :)

@iwanders
Copy link
Contributor Author

iwanders commented Nov 8, 2023

This looks like a flakey test, at least, we didn't see this error before; https://github.com/pybind/pybind11/actions/runs/6791647051/job/18463525701?pr=4921

         FAILED test_iostream.py::test_flush - AssertionError: assert '### TestFact...(not flushed)' == '(not flushed)'
           + ### TestFactory2 @ 0x227bbf9d0a0 destroyed
             (not flushed)
         = 1 failed, 760 passed, 50 skipped, 26 xfailed, 7 xpassed in 200.07s (0:03:20) =

Going to incorporate the clang tidy noexcept suggestion, but thought I'd point it out in case it doesn't occur again.

@iwanders iwanders force-pushed the unique_ptr_destructor_roundtrip branch from 21bbcd0 to 8a75f12 Compare November 8, 2023 00:08
@rwgk
Copy link
Collaborator

rwgk commented Nov 8, 2023 via email

@rwgk
Copy link
Collaborator

rwgk commented Nov 8, 2023

Looks like it's working now (121 successful already, no failures).

Could you do me a small favor and click update branch here, or git merge smart_holder, git push interactively? (If I click the button here it'll mark me a collaborator just for that. I think it's better if it's clear that it's all your work.)

@iwanders iwanders marked this pull request as ready for review November 8, 2023 00:43
@iwanders
Copy link
Contributor Author

iwanders commented Nov 8, 2023

Done, I've also removed the 'draft' label, good to go in from my side, but if you want to wait until your big weekend run of tests that's fine by me of course, no rush.

@rwgk
Copy link
Collaborator

rwgk commented Nov 8, 2023

Done, I've also removed the 'draft' label, good to go in from my side, but if you want to wait until your big weekend run of tests that's fine by me of course, no rush.

Thanks for the great work!

I'll wait for the GHA to finish, then merge. For the weekend run I'd want to include this PR from the start anyway. Big maybe: if I see a reason to back it out for a rerun (to see if that resolves any failures), I can do that easily with a local revert. In the worst case (very much unexpected) we can revert here, or fix forward.

@rwgk rwgk merged commit e5ce963 into pybind:smart_holder Nov 8, 2023
@github-actions github-actions bot added the needs changelog Possibly needs a changelog entry label Nov 8, 2023
@rwgk rwgk removed the needs changelog Possibly needs a changelog entry label Nov 8, 2023
@iwanders
Copy link
Contributor Author

iwanders commented Nov 8, 2023

Please do let me know if any of the test runs uncover any issues, happy to help tackle them if related to this piece of work.

@rwgk
Copy link
Collaborator

rwgk commented Nov 13, 2023

For the weekend run I'd want to include this PR from the start anyway.

Done. No surprises.

Big maybe: if I see a reason to back it out for a rerun (to see if that resolves any failures), I can do that easily with a local revert.

I didn't really see a reason, but for completeness, and because it was easy, I tested with the local revert anyway. Very clearly: this PR did not break anything.

In summary (see #4921 (comment)): This PR did not fix anything in the wild, but also did not break anything.

I'm very thankful though that this bug was fixed, so that we no longer have it hanging over our heads as an uncertainty.

@iwanders
Copy link
Contributor Author

I didn't really see a reason, but for completeness, and because it was easy, I tested with the local revert anyway. Very clearly: this PR did not break anything.

Thanks for letting me know, glad we didn't discover any new bugs.

I'm very thankful though that this bug was fixed, so that we no longer have it hanging over our heads as an uncertainty.

Agreed, this is one of those 'would lead to an annoying bug in production' type of things.

rwgk added a commit to rwgk/pybind11 that referenced this pull request Mar 5, 2025
…major and/or influential contributors to smart_holder branch

* pybind#2904 by @rhaschke was merged on Mar 16, 2021
* pybind#3012 by @rhaschke was merged on May 28, 2021
* pybind#3039 by @jakobandersen was merged on Jun 29, 2021
* pybind#3048 by @Skylion007 was merged on Jun 18, 2021
* pybind#3588 by @virtuald was merged on Jan 3, 2022
* pybind#3633 by @wangxf123456 was merged on Jan 25, 2022
* pybind#3635 by @virtuald was merged on Jan 26, 2022
* pybind#3645 by @wangxf123456 was merged on Jan 25, 2022
* pybind#3796 by @wangxf123456 was merged on Mar 10, 2022
* pybind#3807 by @wangxf123456 was merged on Mar 18, 2022
* pybind#3838 by @wangxf123456 was merged on Apr 15, 2022
* pybind#3929 by @tomba was merged on May 7, 2022
* pybind#4031 by @wangxf123456 was merged on Jun 27, 2022
* pybind#4343 by @wangxf123456 was merged on Nov 18, 2022
* pybind#4381 by @wangxf123456 was merged on Dec 5, 2022
* pybind#4539 by @wangxf123456 was merged on Feb 28, 2023
* pybind#4609 by @wangxf123456 was merged on Apr 6, 2023
* pybind#4775 by @wangxf123456 was merged on Aug 3, 2023
* pybind#4921 by @iwanders was merged on Nov 7, 2023
* pybind#4924 by @iwanders was merged on Nov 6, 2023
* pybind#5401 by @msimacek was merged on Oct 8, 2024

Co-authored-by: Aaron Gokaslan <[email protected]>
Co-authored-by: Dustin Spicuzza <[email protected]>
Co-authored-by: Ivor Wanders <[email protected]>
Co-authored-by: Jakob Lykke Andersen <[email protected]>
Co-authored-by: Michael Šimáček <[email protected]>
Co-authored-by: Robert Haschke <[email protected]>
Co-authored-by: Tomi Valkeinen <[email protected]>
Co-authored-by: Xiaofei Wang <[email protected]>
rwgk added a commit that referenced this pull request Mar 5, 2025
* Pure `git merge --squash smart_holder` (no manual interventions).

* Remove ubench/ directory.

* Remove include/pybind11/smart_holder.h

* [ci skip] smart_ptrs.rst updates [WIP/unfinished]

* [ci skip] smart_ptrs.rst updates continued; also updating classes.rst, advanced/classes.rst

* Remove README_smart_holder.rst

* Restore original README.rst from master

* [ci skip] Minimal change to README.rst, to leave a hint that this is pybind11v3

* [ci skip] Work in ChatGPT suggestions.

* Change macro name to PYBIND11_RUN_TESTING_WITH_SMART_HOLDER_AS_DEFAULT_BUT_NEVER_USE_IN_PRODUCTION_PLEASE

* Add a note pointing to the holder reinterpret_cast.

* Incorporate suggestion by @virtuald: #5542 (comment)

* Systematically change most py::class_ to py::classh under docs/

* Remove references to README_smart_holder.rst

This should have been part of commit eb550d0.

* [ci skip] Fix minor oversight (``class_`` -> ``py::class_``) noticed by chance.

* [ci skip] Resolve suggestion by @virtuald

#5542 (comment)

* [ci skip] Apply suggestions by @timohl (thanks!)

* #5542 (comment)
* #5542 (comment)
* #5542 (comment)

* Replace `classh : class_` inhertance with `using`, as suggested by @henryiii

#5542 (comment)

* Revert "Systematically change most py::class_ to py::classh under docs/"

This reverts commit ac9d31e.

* docs: focus on py::smart_holder instead of py::classh

Signed-off-by: Henry Schreiner <[email protected]>

* Restore minor general fixes that got lost when ac9d31e was reverted.

* Remove `- smart_holder` from list of branches in all .github/workflows

* Extend classh note to explain whitespace noise motivation.

* Suggest `py::smart_holder` for "most situations for safety"

* Add back PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT

This define was
* introduced with #5286
* removed with #5531

It is has been in use here:
* https://github.com/pybind/pybind11_protobuf/blob/f02a2b7653bc50eb5119d125842a3870db95d251/pybind11_protobuf/native_proto_caster.h#L89-L101

Currently pybind11 unit tests for the two holder caster backwards compatibility traits

* `copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled`
* `move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled`

are missing.

* Add py::trampoline_self_life_support to all trampoline examples under docs/.

Address suggestion by @timohl:

* #5542 (comment)

Add to the "please think twice" note: the overhead for safety is likely in the noise.

Also fix a two-fold inconsistency introduced by revert-commit 1e646c9:

1.

py::trampoline_self_life_support is mentioned in a note, but is missing in the example right before.

2.

The section starting with

    To enable safely passing a ``std::unique_ptr`` to a trampoline object between

is obsolete.

* Fix whitespace accident (indentation) introduced with 1e646c9

Apparently the mis-indentation was introduced when resolving merge conflicts for what became 1e646c9

* WHITESPACE CHANGES ONLY in README.rst (list of people that made significant contributions)

* Add Ethan Steinberg to list of people that made significant contributions (for completeness, unrelated to smart_holder work).

* [ci skip] Add to list of people that made significant contributions: major and/or influential contributors to smart_holder branch

* #2904 by @rhaschke was merged on Mar 16, 2021
* #3012 by @rhaschke was merged on May 28, 2021
* #3039 by @jakobandersen was merged on Jun 29, 2021
* #3048 by @Skylion007 was merged on Jun 18, 2021
* #3588 by @virtuald was merged on Jan 3, 2022
* #3633 by @wangxf123456 was merged on Jan 25, 2022
* #3635 by @virtuald was merged on Jan 26, 2022
* #3645 by @wangxf123456 was merged on Jan 25, 2022
* #3796 by @wangxf123456 was merged on Mar 10, 2022
* #3807 by @wangxf123456 was merged on Mar 18, 2022
* #3838 by @wangxf123456 was merged on Apr 15, 2022
* #3929 by @tomba was merged on May 7, 2022
* #4031 by @wangxf123456 was merged on Jun 27, 2022
* #4343 by @wangxf123456 was merged on Nov 18, 2022
* #4381 by @wangxf123456 was merged on Dec 5, 2022
* #4539 by @wangxf123456 was merged on Feb 28, 2023
* #4609 by @wangxf123456 was merged on Apr 6, 2023
* #4775 by @wangxf123456 was merged on Aug 3, 2023
* #4921 by @iwanders was merged on Nov 7, 2023
* #4924 by @iwanders was merged on Nov 6, 2023
* #5401 by @msimacek was merged on Oct 8, 2024

Co-authored-by: Aaron Gokaslan <[email protected]>
Co-authored-by: Dustin Spicuzza <[email protected]>
Co-authored-by: Ivor Wanders <[email protected]>
Co-authored-by: Jakob Lykke Andersen <[email protected]>
Co-authored-by: Michael Šimáček <[email protected]>
Co-authored-by: Robert Haschke <[email protected]>
Co-authored-by: Tomi Valkeinen <[email protected]>
Co-authored-by: Xiaofei Wang <[email protected]>

---------

Signed-off-by: Henry Schreiner <[email protected]>
Co-authored-by: Henry Schreiner <[email protected]>
Co-authored-by: Aaron Gokaslan <[email protected]>
Co-authored-by: Dustin Spicuzza <[email protected]>
Co-authored-by: Ivor Wanders <[email protected]>
Co-authored-by: Jakob Lykke Andersen <[email protected]>
Co-authored-by: Michael Šimáček <[email protected]>
Co-authored-by: Robert Haschke <[email protected]>
Co-authored-by: Tomi Valkeinen <[email protected]>
Co-authored-by: Xiaofei Wang <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants