-
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
[BUG] Keep pybind11 type casters alive recursively when needed #2527
Comments
Pull request added: #2532 |
@kenoslund-google I think this might be the same problem as #2245? I have worked on this in #2303, but I couldn't fully figure out how to fit it into the existing casters-framework, and then forgot about the PR. Any ideas how to escape the problems mentioned there are welcome, though. |
I think this is already possible to check by seeing if the type requires conversion: For an example: pybind11/include/pybind11/cast.h Line 2209 in 00edc30
It may not capture all other cases; however, at that point I think it could be defined "extrinsically", by making it into |
Issue description
When pybind11 casts from python->C++ for a function call, the casters for each argument are kept alive for the duration of the function call. This is important when passing a pointer or reference to memory owned by the caster (rather than owned by python). std::string is a common example of this- functions which take a std::string* or std::string& as one of their arguments (const or non-const) would fail without this behavior because the cast string would be freed before the function begins executing.
However, this behavior does not work recursively. For example, the list_caster constructs a caster for each element, moves the result out of it, and then discards the caster:
pybind11/include/pybind11/stl.h
Lines 152 to 157 in 3c7ef56
Thus, if you attempt to bind a function which takes a
std::vector<std::string*>
as one of its arguments, it will fail (and probably corrupt memory) because thestd::string
is owned by the element caster, which is destroyed before the function call begins.This is particularly a problem when writing a caster for Spans (https://abseil.io/tips/93). Since the span does not confer ownership, the caster must retain ownership of a vector for the span to reference. This breaks with nested spans (
Span<const Span<const T>>
) exactly the same waystd::vector<std::string*>
breaks.However, just keeping the casters alive recursively would be unnecessary and inefficient in many cases. For efficiency, I think the element casters should only be kept alive recursively if both of the following are true:
The second condition is easy enough check- if the element type is a pointer, l-value reference, or the caster does not support the
movable_cast_op_type
, then it is satisfied. This can be checked by adding a r-value reference to the element type and feeding it through the element caster's cast_op_type:However, there does not appear to be a way to check the the first condition; type_casters would probably have to declare it, which would require an addition to the type_caster API.
Reproducible example code
C++
python
I'll upload a PR as soon as I figure out how...
The text was updated successfully, but these errors were encountered: