Uh oh!
There was an error while loading. Please reload this page.
Detect and fail if using mismatched holders - #1161
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 fixespybind#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.
EricCousineau-TRI
commented
Oct 29, 2017
(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. |
jagerman
commented
Oct 29, 2017
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) {
returnstd::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)
throwstd::runtime_error("Cannot convert a shared_ptr with multiple refs");
return std::unique_ptr<B>(b.release());
}); |
EricCousineau-TRI
commented
Nov 1, 2017
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.) |
wjakob
commented
Nov 7, 2017
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 |
EricCousineau-TRI
commented
Nov 7, 2017
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?) |
jagerman
commented
Nov 7, 2017
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. |
jagerman
commented
Nov 7, 2017
Oh, I think you were referring to the holder conversion stuff in the comments above rather than the mismatched holder detection. |
EricCousineau-TRI
commented
Jan 3, 2018
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. |
oremanj
commented
Apr 23, 2018
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? |
jagerman
commented
Apr 23, 2018
@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. |
TallJimbo
commented
Aug 7, 2018
@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 |
rhaschke
commented
Oct 20, 2020
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. |
rhaschke
commented
Oct 20, 2020
Hm. As pointed out in #1161 (comment), this PR doesn't handle mismatching function arguments (only return types). |
| 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.
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. 👍
YannickJadoul
commented
Oct 20, 2020
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).