Skip to content

fix: leave ref_small_vector source empty after move - #6161

Open
henryiii wants to merge 2 commits into
pybind:masterfrom
henryiii:fix/ref-small-vector-move
Open

fix: leave ref_small_vector source empty after move#6161
henryiii wants to merge 2 commits into
pybind:masterfrom
henryiii:fix/ref-small-vector-move

Conversation

@henryiii

@henryiii henryiii commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

🤖 AI text below 🤖

inline_array_or_vector used the implicit move constructor of its inline array, which copies the array and its size. The source kept its elements. For ref_small_vector, which owns a reference for each element, both the source and the destination then released the same references.

The inline array now has a move constructor and a move assignment operator that set the source size to 0. The heap branch already leaves the source empty, because std::vector guarantees it. The comment in the ref_small_vector move constructor is now correct.

The problem is latent today, because the only user relies on copy elision.

The change made the Clang 5 / Python 3.9 CI job segfault in the Catch "Threads" test, during interpreter finalization. The cause is a pre-existing bug in the "Enum module survives restart" test: it kept a py::module_ from the old interpreter across finalize_interpreter(), then reassigned it, which decrefs a stale pointer into memory the new interpreter had reused. The changed allocation pattern made that stale write hit a live object. The test now scopes the first import.

Fixes item 24 of #6159.

Suggested changelog entry:

  • Fixed a latent double reference release: moving a detail::ref_small_vector now leaves the source empty.

@henryiii
henryiii force-pushed the fix/ref-small-vector-move branch 3 times, most recently from eea78d0 to c523b41 Compare September 2, 2026 22:52
The enum restart test kept a py::module_ from the old interpreter alive
across finalize_interpreter(), then decref'd that stale pointer into
memory the new interpreter had reused. Depending on allocation layout
this corrupted a live object and crashed in the next finalize (seen on
Clang 5 / Python 3.9 CI after the ref_small_vector change shifted the
allocation pattern).
@henryiii
henryiii force-pushed the fix/ref-small-vector-move branch from 2b4f94e to a50e6af Compare September 3, 2026 04:05
auto enum_mod = py::module_::import("enum_module");
REQUIRE(enum_mod.attr("SomeEnum").attr("value1").attr("name").cast<std::string>() == "value1");
{
// Scoped so that no reference to the old interpreter's module survives the restart.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This was pretty terrible to debug. At least, it was for Claude, I mostly left it in the background. :)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants