Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-40412: Nullify inittab_copy during finalization #19746

Merged
merged 3 commits into from
May 1, 2020

Conversation

indygreg
Copy link
Contributor

@indygreg indygreg commented Apr 28, 2020

Otherwise we leave a dangling pointer to free'd memory. If we
then initialize a new interpreter in the same process and call
PyImport_ExtendInittab, we will (likely) crash when calling
PyMem_RawRealloc(inittab_copy, ...) since the pointer address
is bogus.

https://bugs.python.org/issue40412

Automerge-Triggered-By: @brettcannon

Otherwise we leave a dangling pointer to free'd memory. If we
then initialize a new interpreter in the same process and call
PyImport_ExtendInittab, we will (likely) crash when calling
PyMem_RawRealloc(inittab_copy, ...) since the pointer address
is bogus.
Copy link
Member

@ericsnowcurrently ericsnowcurrently left a comment

Choose a reason for hiding this comment

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

LGTM

Good catch! How did you notice this?

@indygreg
Copy link
Contributor Author

indygreg commented May 1, 2020

I discovered it while writing tests for PyOxidizer's custom meta path importer. The tests initialize several Python interpreters per process.

Also, is it too late to get this patch in 3.8.3?

@brettcannon
Copy link
Member

@indygreg mind doing a quick news entry? This close to beta means people are starting to care about every change more and more. You can use https://blurb-it.herokuapp.com/ as linked from "Details" for the bedevere/news line if you want to use a web form to fill it out.

Copy link
Member

@brettcannon brettcannon left a comment

Choose a reason for hiding this comment

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

Simplification of the news entry and then this is ready to go!

@bedevere-bot
Copy link

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@brettcannon brettcannon self-requested a review May 1, 2020 17:46
@miss-islington
Copy link
Contributor

@indygreg: Status check is done, and it's a failure ❌ .

@brettcannon
Copy link
Member

OK, thanks to the flag being set for submitting my own suggestions, this PR looks good to go! I have set it to automerge and backport to 3.8 and 3.7.

@brettcannon
Copy link
Member

I also tossed in a 3.6 backport in case Ned wants to take it due to it being a memory thing.

@miss-islington
Copy link
Contributor

@indygreg: Status check is done, and it's a failure ❌ .

@miss-islington
Copy link
Contributor

@indygreg: Status check is done, and it's a success ✅ .

@miss-islington miss-islington merged commit 64224a4 into python:master May 1, 2020
@miss-islington
Copy link
Contributor

Thanks @indygreg for the PR 🌮🎉.. I'm working now to backport this PR to: 3.6, 3.7, 3.8.
🐍🍒⛏🤖

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request May 1, 2020
Otherwise we leave a dangling pointer to free'd memory. If we
then initialize a new interpreter in the same process and call
PyImport_ExtendInittab, we will (likely) crash when calling
PyMem_RawRealloc(inittab_copy, ...) since the pointer address
is bogus.

Automerge-Triggered-By: @brettcannon
(cherry picked from commit 64224a4)

Co-authored-by: Gregory Szorc <[email protected]>
@bedevere-bot bedevere-bot removed the needs backport to 3.8 only security fixes label May 1, 2020
@bedevere-bot
Copy link

GH-19841 is a backport of this pull request to the 3.8 branch.

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request May 1, 2020
Otherwise we leave a dangling pointer to free'd memory. If we
then initialize a new interpreter in the same process and call
PyImport_ExtendInittab, we will (likely) crash when calling
PyMem_RawRealloc(inittab_copy, ...) since the pointer address
is bogus.

Automerge-Triggered-By: @brettcannon
(cherry picked from commit 64224a4)

Co-authored-by: Gregory Szorc <[email protected]>
@bedevere-bot
Copy link

GH-19842 is a backport of this pull request to the 3.7 branch.

@miss-islington
Copy link
Contributor

Sorry, @indygreg, I could not cleanly backport this to 3.6 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 64224a4727321a8dd33e6f769edda401193ebef0 3.6

@miss-islington miss-islington self-assigned this May 1, 2020
@indygreg
Copy link
Contributor Author

indygreg commented May 1, 2020

While NULLifying the invalid pointer is certainly worthy of backporting everywhere, I'm not sure this issue is reproducible on Python <3.8. The reason is that the code that clears this pointer appears to be called after Py_FinalizeEx(). I'm unsure if this code existed before initialization API refactors in 3.8. @vstinner would know.

I've already thrown away PyOxidizer's code to support Python 3.7 and can't easily test. This will require a source inspection to validate against older versions.

miss-islington added a commit that referenced this pull request May 1, 2020
Otherwise we leave a dangling pointer to free'd memory. If we
then initialize a new interpreter in the same process and call
PyImport_ExtendInittab, we will (likely) crash when calling
PyMem_RawRealloc(inittab_copy, ...) since the pointer address
is bogus.

Automerge-Triggered-By: @brettcannon
(cherry picked from commit 64224a4)

Co-authored-by: Gregory Szorc <[email protected]>
@vstinner
Copy link
Member

vstinner commented May 4, 2020

Hum, inittab_copy is freed by pymain_free(). I added this function to clear objects and memory which cannot be freed by Py_Finalize() for backward compatibility.

The PEP 587 says:

PyImport_FrozenModules, PyImport_AppendInittab() and PyImport_ExtendInittab() functions are still relevant and continue to work as previously. They should be set or called after Python preinitialization and before the Python initialization.

I understood that PyImport_AppendInittab() can be called only once, but Py_Initialize() and Py_Finalized() can be called multiple times: the PyImport_AppendInittab() call is expected to be saved even after Py_Finalized().

I understand that this change only impacts C code which calls Py_RunMain() or Py_Main() multiple times. I'm not sure if it was supported previously, but it's a good thing if slowly Python supports it :-)

@vstinner
Copy link
Member

vstinner commented May 4, 2020

I'm not sure this issue is reproducible on Python <3.8

I introduced the issue in Python 3.7 with commit 92a3c6f:

commit 92a3c6f493ad411e4cf0acdf305ef4876aa90669
Author: Victor Stinner <[email protected]>
Date:   Wed Dec 6 18:12:59 2017 +0100

    [bpo-32030](https://bugs.python.org/issue32030): Add _PyImport_Fini2() (#4737)
    
    PyImport_ExtendInittab() now uses PyMem_RawRealloc() rather than
    PyMem_Realloc(). PyImport_ExtendInittab() can be called before
    Py_Initialize() whereas only the PyMem_Raw allocator is supposed to
    be used before Py_Initialize().
    
    Add _PyImport_Fini2() to release the memory allocated by
    PyImport_ExtendInittab() at exit. PyImport_ExtendInittab() now forces
    the usage of the default raw allocator, to be able to release memory
    in _PyImport_Fini2().

A backport of the fix sounds safe, but I don't think that it is safe to call Py_Main() multiple times in Python 3.7. Maybe it works, I don't know :-)

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.

7 participants