-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Detect and fail if using mismatched holders #1161
base: master
Are you sure you want to change the base?
Conversation
This adds a check when registering a class or a function with a holder return that the same wrapped type hasn't been previously seen using a different holder type. This fixes pybind#1138 by detecting the failure; currently attempting to use two different holder types (e.g. a unique_ptr<T> and shared_ptr<T>) in difference places can segfault because we don't have any type safety on the holder instances.
(Follow up from #1138) Just a couple of comments / questions (quoting from this PR and your comment in the other PR):
I have covered a constrained case of this under #1146 - by permitting This also adds in a layer to check type mismatches when erasing the holders (via Is there a way something like this could be incorporated into this new PR that you have?
To follow up, sorry, I should have followed up on the old PR. The newer PR, #1146 (which is unfortunately large, so it got lost in the details), had a mechanism to handle this; however, this setup (using
Can I ask if you have an idea of how this would work? I cannot think of anything at the moment. |
Well, just brainstorming a bit (because I haven't really thought this through): One possible way is with a declaration along the lines of Or perhaps more flexible, a py::holder_conversion<A>([](std::unique_ptr<A> &&a) {
return std::shared_ptr(std::move(a)); }); That would also allow you to do things like go the other way (albeit with a required run-time check): py::holder_conversion<B>([](std::shared_ptr<B> &&b) {
if (b.use_count() > 1)
throw std::runtime_error("Cannot convert a shared_ptr with multiple refs");
return std::unique_ptr<B>(b.release());
}); |
That makes sense, but this seems like it would be strictly runtime rather than compile-time.
That makes sense too, and seems like it could ultimately be the underlying implementation for the first alternative.
AFAIK, it is not possible to convert a That being said, could some sort of mechanism like this be used to more intuitively release (If this is too off-topic to this PR, I can move these comments to another thread.) |
This strikes me as fairly heavy weight (code added to every function dispatcher). Can't we just point out in the docs that you're not supposed to mix holder types? It strikes me as a fairly rare design pattern to use |
True - but if it doesn't add too much weight, could there still be a way to raise an alarm if attempting to convert holder types? (And just to check, are you talking about the suggestions for conversions? Or are you talking about the original PR?) |
I somewhat agree and am a bit ambivalent about this PR, but it's not that heavy: the code is only added to function and class initialization, not function dispatching. |
Oh, I think you were referring to the holder conversion stuff in the comments above rather than the mismatched holder detection. |
Sorry for late-follow-up, but it seems like @tadeu may have encountered this in #1215. Once concern with the current PR is that it may only check Return values but ignore input arguments (and possibly casting). I'd be happy to make those changes if you'd like, as it'd be a nice step to incorporate bits of #1146. |
I spent a while today debugging a segfault that would've given a clear error message in the presence of this PR - are there any plans to merge it? |
@wjakob - thoughts on this PR? (As it is now -- there are other comments here that went off on a bit of a tangent). The basic protection here seems useful and relatively cheap—a check when registering classs and function, and yet another container in the internals struct. |
@pschella and I just encountered this, and disallowing mixed holder types is a big problem for our codebase (regardless of whether the failure mode is a segfault or a friendlier exception). We consider it good practice to use Our organization may be able to contribute some effort towards fixing this, and the |
I came across the same issue and suggested another fix in #2052. However, the one here is more elegant as it detects the conflicting holder types during function/class definition. I think this PR should be merged to avoid potential segfaults and establish a warning mechanism to ensure consistent holder types. @EricCousineau-TRI's original aim, on the other hand, was to automatically convert between different holder types. |
Hm. As pointed out in #1161 (comment), this PR doesn't handle mismatching function arguments (only return types). |
@@ -68,6 +68,7 @@ struct internals { | |||
type_map<type_info *> registered_types_cpp; // std::type_index -> pybind11's type information | |||
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py; // PyTypeObject* -> base type_info(s) | |||
std::unordered_multimap<const void *, instance*> registered_instances; // void * -> instance* | |||
type_map<const std::type_info *> holders_seen; // type -> seen holder type (to detect holder conflicts) |
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 was puzzled why you use a global map holders_seen
here, instead of storing the unique holder type of a registered type in its typeinfo as I did in #2052. However, your approach just considers the first occurrence of a holder type as the gold standard. 👍
Adding this to the 2.7 milestone. Not per se to have this included as-is, but to make sure we discuss this old, but probably still relevant PR. |
This adds a check when registering a class or a function with a holder return that the same wrapped type hasn't been previously seen using a different holder type.
This fixes #1138 by detecting the failure; currently attempting to use two different holder types (e.g. a unique_ptr and shared_ptr) in difference places can segfault because we don't have any type safety on the holder instances.
This an alternative to #1139, which I don't think will work for pybind as is (I'll comment in that PR).