diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 972682e5eb..508afab756 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -513,8 +513,11 @@ class internals_pp_manager { /// Drop all the references we're currently holding. void unref() { #ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT - last_istate_.reset(); - internals_tls_p_.reset(); + if (get_num_interpreters_seen() > 1) { + last_istate_.reset(); + internals_tls_p_.reset(); + return; + } #endif internals_singleton_pp_ = nullptr; } diff --git a/tests/test_embed/test_subinterpreter.cpp b/tests/test_embed/test_subinterpreter.cpp index d314394389..3c7c35be19 100644 --- a/tests/test_embed/test_subinterpreter.cpp +++ b/tests/test_embed/test_subinterpreter.cpp @@ -20,11 +20,21 @@ bool has_state_dict_internals_obj(); uintptr_t get_details_as_uintptr(); void unsafe_reset_internals_for_single_interpreter() { - // unsafe normally, but for subsequent tests, put this back.. we know there are no threads - // running and only 1 interpreter + // NOTE: This code is NOT SAFE unless the caller guarantees no other threads are alive + // NOTE: This code is tied to the precise implementation of the internals holder + + // first, unref the thread local internals py::detail::get_internals_pp_manager().unref(); py::detail::get_local_internals_pp_manager().unref(); + + // we know there are no other interpreters, so we can lower this. SUPER DANGEROUS py::detail::get_num_interpreters_seen() = 1; + + // now we unref the static global singleton internals + py::detail::get_internals_pp_manager().unref(); + py::detail::get_local_internals_pp_manager().unref(); + + // finally, we reload the static global singleton py::detail::get_internals(); py::detail::get_local_internals(); }