mirror of
https://github.com/pybind/pybind11.git
synced 2024-12-01 17:37:15 +00:00
Using unique_ptr in local_load to replace static variable. Also adding local_load_safety_guard.
This commit is contained in:
parent
631a288d69
commit
3d17f6f6a1
@ -31,6 +31,9 @@ inline std::pair<bool, handle> find_existing_python_instance(void *src_void_ptr,
|
||||
return std::make_pair(false, handle());
|
||||
}
|
||||
|
||||
// The modified_type_caster_generic_load_impl could replace type_caster_generic::load_impl but not
|
||||
// vice versa. The main difference is that the original code only propagates a reference to the
|
||||
// held value, while the modified implementation propagates value_and_holder.
|
||||
// clang-format off
|
||||
class modified_type_caster_generic_load_impl {
|
||||
public:
|
||||
@ -84,12 +87,14 @@ public:
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) {
|
||||
// Not thread safe. But the GIL needs to be held anyway in the context of this code.
|
||||
static modified_type_caster_generic_load_impl caster;
|
||||
caster = modified_type_caster_generic_load_impl(ti);
|
||||
if (caster.load(src, false)) {
|
||||
std::unique_ptr<modified_type_caster_generic_load_impl> loader(
|
||||
new modified_type_caster_generic_load_impl(ti));
|
||||
if (loader->load(src, false)) {
|
||||
// Trick to work with the existing pybind11 internals.
|
||||
return &caster; // Any pointer except nullptr;
|
||||
// The void pointer is immediately captured in a new unique_ptr in
|
||||
// try_load_foreign_module_local. If this assumption is violated sanitizers
|
||||
// will most likely flag a leak (verified to be the case with ASAN).
|
||||
return static_cast<void *>(loader.release());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -108,15 +113,23 @@ public:
|
||||
|| (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype)))
|
||||
return false;
|
||||
|
||||
void* void_ptr = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo);
|
||||
if (void_ptr != nullptr) {
|
||||
auto foreign_load_impl = static_cast<modified_type_caster_generic_load_impl *>(void_ptr);
|
||||
void* foreign_loader_void_ptr =
|
||||
foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo);
|
||||
if (foreign_loader_void_ptr != nullptr) {
|
||||
auto foreign_loader = std::unique_ptr<modified_type_caster_generic_load_impl>(
|
||||
static_cast<modified_type_caster_generic_load_impl *>(foreign_loader_void_ptr));
|
||||
// Magic number intentionally hard-coded for simplicity and maximum robustness.
|
||||
if (foreign_loader->local_load_safety_guard != 37726257887406645) {
|
||||
pybind11_fail(
|
||||
"Unexpected local_load_safety_guard,"
|
||||
" possibly due to py::class_ vs py::classh mixup.");
|
||||
}
|
||||
if (loaded_v_h_cpptype != nullptr) {
|
||||
pybind11_fail("classh_type_casters: try_load_foreign_module_local failure.");
|
||||
}
|
||||
loaded_v_h = foreign_load_impl->loaded_v_h;
|
||||
loaded_v_h_cpptype = foreign_load_impl->loaded_v_h_cpptype;
|
||||
implicit_cast = foreign_load_impl->implicit_cast;
|
||||
loaded_v_h = foreign_loader->loaded_v_h;
|
||||
loaded_v_h_cpptype = foreign_loader->loaded_v_h_cpptype;
|
||||
implicit_cast = foreign_loader->implicit_cast;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -216,6 +229,9 @@ public:
|
||||
void *(*implicit_cast)(void *) = nullptr;
|
||||
value_and_holder loaded_v_h;
|
||||
bool reinterpret_cast_deemed_ok = false;
|
||||
// Magic number intentionally hard-coded, to guard against class_ vs classh mixups.
|
||||
// Ideally type_caster_generic would have a similar guard, but this requires a change there.
|
||||
std::size_t local_load_safety_guard = 37726257887406645;
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user