Skip to content

Conversation

swolchok
Copy link
Contributor

Description

@oremanj pointed out in a comment on #5842 that I missed part of the nanobind PR I was porting in such a way that we could have dangling pointers in internals::registered_types_cpp_fast. This PR adds a test that reproed the bug and then fixes the test.

…ind#5842

@oremanj pointed out in a comment on pybind#5842 that I missed part
of the nanobind PR I was porting in such a way that we could have
dangling pointers in internals::registered_types_cpp_fast. This PR
adds a test that reproed the bug and then fixes the test.
Comment on lines 340 to 341
// keys (the type_info from each DSO) mapped to the same
// type_info*. We need to keep track of these aliases so that we clean
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// keys (the type_info from each DSO) mapped to the same
// type_info*. We need to keep track of these aliases so that we clean
// keys (the std::type_info from each DSO) mapped to the same
// detail::type_info*. We need to keep track of these aliases so that we clean

Suggest disambiguating since both the key and value types are something::type_info

// nb_alias_chain` added in
// https://github.com/wjakob/nanobind/commit/b515b1f7f2f4ecc0357818e6201c94a9f4cbfdc2
#if PYBIND11_INTERNALS_VERSION >= 12
struct alias_chain_entry {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use std::forward_list instead of rolling your own singly linked list. nanobind goes to a lot of trouble to avoid anything from the STL, while pybind11 already has other uses of forward_list and it is basically the same thing you wrote here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL sizeof(std::forward_list) == 8 and it's in C++11, SGTM

def test_cross_module_use_after_one_module_dealloc():
# This is a regression test for a bug that occurred during development of
# internals::registered_types_cpp_fast (see #5842). registered_types_cpp_fast maps
# &typeid(T) to a raw non-owning pointer to a Python metaclass. If two DSOs both
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are just Python classes (types), not metaclasses (their instances are not types). I might say "type object pointer" to disambiguate from the std::type_info pointer.

Copy link
Collaborator

@oremanj oremanj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will need to skip the new test on 3.13 free-threaded, since types are immortal there. It should work fine on 3.14+ free-threaded. Suggestions are what I expect you need to make clang-tidy happy.

struct UnrelatedClass {};

TEST_SUBMODULE(class_cross_module_use_after_one_module_dealloc, m) {
m.def("register_and_instantiate_cross_dso_class", [](py::module_ m) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
m.def("register_and_instantiate_cross_dso_class", [](py::module_ m) {
m.def("register_and_instantiate_cross_dso_class", [](const py::module_ &m) {

return CrossDSOClass();
});
m.def("register_unrelated_class",
[](py::module_ m) { py::class_<UnrelatedClass>(m, "UnrelatedClass"); });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[](py::module_ m) { py::class_<UnrelatedClass>(m, "UnrelatedClass"); });
[](const py::module_ &m) { py::class_<UnrelatedClass>(m, "UnrelatedClass"); });

m.def("missing_header_return", []() { return std::vector<float>(); });

// test_class_cross_module_use_after_one_module_dealloc
m.def("consume_cross_dso_class", [](CrossDSOClass) {});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
m.def("consume_cross_dso_class", [](CrossDSOClass) {});
m.def("consume_cross_dso_class", [](const CrossDSOClass &) {});

@oremanj oremanj merged commit fc423c9 into pybind:master Oct 14, 2025
85 checks passed
@github-actions github-actions bot added the needs changelog Possibly needs a changelog entry label Oct 14, 2025
@swolchok
Copy link
Contributor Author

Thanks for fixing things up @oremanj! Was out today, planned to get to it tomorrow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs changelog Possibly needs a changelog entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants