mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-28 08:02:00 +00:00
Fix premature destruction of args/kwargs arguments
The `py::args` or `py::kwargs` arguments aren't properly referenced when added to the function_call arguments list: their reference counts drop to zero if the first (non-converting) function call fails, which means they might be cleaned up before the second pass call runs. This commit adds a couple of extra `object`s to the `function_call` where we can stash a reference to them when needed to tie their lifetime to the function_call object's lifetime. (Credit to YannickJadoul for catching and proposing a fix in #1223).
This commit is contained in:
parent
53e0aa034b
commit
c715c70e0a
@ -1802,6 +1802,10 @@ struct function_call {
|
|||||||
/// The `convert` value the arguments should be loaded with
|
/// The `convert` value the arguments should be loaded with
|
||||||
std::vector<bool> args_convert;
|
std::vector<bool> args_convert;
|
||||||
|
|
||||||
|
/// Extra references for the optional `py::args` and/or `py::kwargs` arguments (which, if
|
||||||
|
/// present, are also in `args` but without a reference).
|
||||||
|
object args_ref, kwargs_ref;
|
||||||
|
|
||||||
/// The parent, if any
|
/// The parent, if any
|
||||||
handle parent;
|
handle parent;
|
||||||
|
|
||||||
|
@ -576,8 +576,8 @@ protected:
|
|||||||
continue; // Unconsumed kwargs, but no py::kwargs argument to accept them
|
continue; // Unconsumed kwargs, but no py::kwargs argument to accept them
|
||||||
|
|
||||||
// 4a. If we have a py::args argument, create a new tuple with leftovers
|
// 4a. If we have a py::args argument, create a new tuple with leftovers
|
||||||
tuple extra_args;
|
|
||||||
if (func.has_args) {
|
if (func.has_args) {
|
||||||
|
tuple extra_args;
|
||||||
if (args_to_copy == 0) {
|
if (args_to_copy == 0) {
|
||||||
// We didn't copy out any position arguments from the args_in tuple, so we
|
// We didn't copy out any position arguments from the args_in tuple, so we
|
||||||
// can reuse it directly without copying:
|
// can reuse it directly without copying:
|
||||||
@ -594,6 +594,7 @@ protected:
|
|||||||
}
|
}
|
||||||
call.args.push_back(extra_args);
|
call.args.push_back(extra_args);
|
||||||
call.args_convert.push_back(false);
|
call.args_convert.push_back(false);
|
||||||
|
call.args_ref = std::move(extra_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4b. If we have a py::kwargs, pass on any remaining kwargs
|
// 4b. If we have a py::kwargs, pass on any remaining kwargs
|
||||||
@ -602,6 +603,7 @@ protected:
|
|||||||
kwargs = dict(); // If we didn't get one, send an empty one
|
kwargs = dict(); // If we didn't get one, send an empty one
|
||||||
call.args.push_back(kwargs);
|
call.args.push_back(kwargs);
|
||||||
call.args_convert.push_back(false);
|
call.args_convert.push_back(false);
|
||||||
|
call.kwargs_ref = std::move(kwargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Put everything in a vector. Not technically step 5, we've been building it
|
// 5. Put everything in a vector. Not technically step 5, we've been building it
|
||||||
|
Loading…
Reference in New Issue
Block a user