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

[master] Wrong caching of overrides #3465

Merged
merged 5 commits into from
Nov 15, 2021

Conversation

Trigve
Copy link
Contributor

@Trigve Trigve commented Nov 13, 2021

Description

There was a problem when the python type, which was stored in override
cache for C++ functions, was destroyed and the record wasn't removed from the
override cache. Therefor, dangling pointer was stored there. Then when the
memory was reused and new type was allocated at the given address and the
method with the same name (as previously stored in the cache) was actually
overridden in python, it would wrongly find it in the override cache for C++
functions and therefor override from python wouldn't be called.
The fix is to erase the type from the override cache when the type is destroyed.

Closes: #3369

Suggested changelog entry:

Fix caching of the C++ overrides

There was a problem when the python type, which was stored in override
cache for C++ functions, was destroyed and  the record wasn't removed from the
override cache. Therefor, dangling pointer was stored there. Then when the
memory was reused and new type was allocated at the given address and the
method with the same name (as previously stored in the cache) was actually
overridden in python, it would wrongly find it in the override cache for C++
functions and therefor override from python wouldn't be called.
The fix is to erase the type from the override cache when the type is destroyed.
@rwgk
Copy link
Collaborator

rwgk commented Nov 13, 2021

FYI I'll be on and off a lot today but will keep an eye on this.

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.

Suggestions aiming to nudge things to the right places.

@@ -1979,6 +1979,16 @@ inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_t
// gets destroyed:
weakref((PyObject *) type, cpp_function([type](handle wr) {
get_internals().registered_types_py.erase(type);

// Actually just `std::erase_if`, but that's only available in C++20
Copy link
Collaborator

Choose a reason for hiding this comment

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

What do you think about something like:

erase_if(cache.begin(), cache.end(), [](const xxx& v){ return yyy; });

here and implementing erase_if in detail/common.h (bottom), using the "(2) equivalent to" code from here:

https://en.cppreference.com/w/cpp/container/vector/erase2

auto it = std::remove_if(c.begin(), c.end(), pred);
auto r = std::distance(it, c.end());
c.erase(it, c.end());
return r;

Later, when we introduce PYBIND11_CPP20 we can use std::erase_if directly. (Maybe just leave something like // TODO PYBIND11_CPP20: std::erase_if for now.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The code for the erasure was actually copied and modified from

// Actually just `std::erase_if`, but that's only available in C++20

It would be better to create a helper function as you suggested, but I didn't want to add it in this PR as it isn't isn't connected to the issue. I think it would be better to add it as a separate commit.

test_derived(test_derived const &Copy) = delete;
};

class py_test_derived : public test_derived {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Personal preference for clarity (in case you like that, too): class test_derived_trampoline : test_derived

Copy link
Contributor Author

@Trigve Trigve Nov 13, 2021

Choose a reason for hiding this comment

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

Renamed to test_override_cache_helper_trampoline

@@ -34,6 +34,24 @@ struct NoBraceInitialization {
std::vector<int> vec;
};

class test_derived {
Copy link
Collaborator

Choose a reason for hiding this comment

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

At 2nd look, test_virtual_functions.* appears to be a significantly better fit, because this is closely tied to trampolines.

test_derived is a very generic name, something a bit more tailored to the purpose would be ideal (easier to pin-point and relate to what's being exerised). Maybe exercise_override_cache or test_override_cache_helper ...?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved and renamed to test_override_cache_helper

@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does test_trampoline make sense here? To leave it a little bit open (for the future) but not a widely as "derived".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed to test_trampoline.py

Rename the classes and files so they're no too generic. Also, better place to
test the stuff is in test_virtual_functions.cpp/.py as we're basically testing
the virtual functions/trampolines.
@rwgk
Copy link
Collaborator

rwgk commented Nov 13, 2021 via email

@Trigve
Copy link
Contributor Author

Trigve commented Nov 13, 2021

I cannot look at the code right now, but from the comments it sounds good. If you haven't done already, could you please add a comment here: todo consolidate with xxx in class.h? Also request review from Skylion007

How do I request a review? I've read the docs but I don't have option to add one.

@rwgk
Copy link
Collaborator

rwgk commented Nov 13, 2021 via email

@rwgk rwgk requested a review from Skylion007 November 13, 2021 22:22
@rwgk
Copy link
Collaborator

rwgk commented Nov 14, 2021

@henryiii do you want to take a look, too?

Copy link
Collaborator

@henryiii henryiii left a comment

Choose a reason for hiding this comment

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

Looks reasonable to me.

@Skylion007 Skylion007 merged commit afdc09d into pybind:master Nov 15, 2021
@github-actions github-actions bot added the needs changelog Possibly needs a changelog entry label Nov 15, 2021
@rwgk
Copy link
Collaborator

rwgk commented Nov 15, 2021

Thanks @Trigve for the great unit tests!

rwgk pushed a commit to rwgk/pybind11 that referenced this pull request Nov 15, 2021
@Trigve Trigve deleted the override_cache_master branch November 16, 2021 15:07
@henryiii henryiii removed the needs changelog Possibly needs a changelog entry label Dec 21, 2021
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.

[BUG]: Wrong caching of the overrides
4 participants