Skip to content

Destroy internals if created during Py_Finalize() - #892

Merged
jagerman merged 1 commit into
pybind:masterfrom
jagerman:internals-destroy-fix
Jun 8, 2017
Merged

Destroy internals if created during Py_Finalize()#892
jagerman merged 1 commit into
pybind:masterfrom
jagerman:internals-destroy-fix

Conversation

@jagerman

Copy link
Copy Markdown
Member

Py_Finalize could potentially invoke code that calls get_internals(),
which could create a new internals object if one didn't exist.
finalize_interpreter() didn't catch this because it only used the
pre-finalize interpreter pointer status; if this happens, it results in
the internals pointer not being properly destroyed with the interpreter,
which leaks, and also causes a get_internals() under a future
interpreter to return an internals object that is wrong in various ways.

The two lines added to embed.h are the fix; the rest is just adding a test case that triggers and detects the issue.

@jagerman

Copy link
Copy Markdown
MemberAuthor

Cc @dean0x7d for confirmation that the fix looks good.

@jagermanjagerman mentioned this pull request Jun 7, 2017
@jagerman
jagermanforce-pushed the internals-destroy-fix branch from f484d95 to dfa4238CompareJune 7, 2017 18:25
Comment threadinclude/pybind11/embed.h Outdated
// didn't exist above. (But we still use the above because if nothing calls get_internals() we
// might not have the static pointer set in get_internals_ptr())
if (!internals_ptr_ptr)
internals_ptr_ptr = &detail::get_internals_ptr();

@dean0x7ddean0x7dJun 8, 2017

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good catch! I'd suggest moving up get_internals_ptr() to mirror the code from detail:: get_internals(). This is invariant with respect to Py_Finalize():

auto **internals_ptr_ptr = &detail::get_internals_ptr();
if (builtins.contains(id) && isinstance<capsule>(builtins[id]))
internals_ptr_ptr = capsule(builtins[id]);

Edit: Originally suggested internals &*, but edited back to internals **.

Py_Finalize could potentially invoke code that calls `get_internals()`,
which could create a new internals object if one didn't exist.
`finalize_interpreter()` didn't catch this because it only used the
pre-finalize interpreter pointer status; if this happens, it results in
the internals pointer not being properly destroyed with the interpreter,
which leaks, and also causes a `get_internals()` under a future
interpreter to return an internals object that is wrong in various ways.
@jagerman
jagermanforce-pushed the internals-destroy-fix branch from dfa4238 to 4238defCompareJune 8, 2017 18:35
@jagerman
jagerman merged commit 4edb1ce into pybind:masterJun 8, 2017
@dean0x7ddean0x7d modified the milestone: v2.2Aug 13, 2017
@jagerman
jagerman deleted the internals-destroy-fix branch August 14, 2017 20:27
@rwgkrwgk mentioned this pull request Feb 9, 2023
Sign up for freeto 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

@jagerman@dean0x7d