Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

bpo-35943: PyImport_GetModule() can return partially-initialized module#15057

Merged
brettcannon merged 11 commits into
python:masterpython/cpython:masterfrom
nanjekyejoannah:issue35943nanjekyejoannah/cpython:issue35943Copy head branch name to clipboard
Sep 11, 2019
Merged

bpo-35943: PyImport_GetModule() can return partially-initialized module#15057
brettcannon merged 11 commits into
python:masterpython/cpython:masterfrom
nanjekyejoannah:issue35943nanjekyejoannah/cpython:issue35943Copy head branch name to clipboard

Conversation

@nanjekyejoannah

@nanjekyejoannah nanjekyejoannah commented Jul 31, 2019

Copy link
Copy Markdown
Contributor

Added optimization to prevent PyImport_GetModule() from returning partially-initialized module.

https://bugs.python.org/issue35943

Comment thread Python/import.c Outdated

@gnprice gnprice left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This feels like a somewhat tricky bit of logic that it'd be best not to duplicate.

How about pulling it out from PyImport_ImportModuleLevelObject as its own function? I think I'd take the whole body of the if (mod != NULL ...) block. A good description of what it means might be "ensure initialized", so perhaps spelled import_ensure_initialized.

(I'd make it a static function, so it isn't visible outside this file -- that avoids any need to worry about the API.)

Then this function here only needs to add a couple of lines, invoking that one.

Comment thread Python/import.c Outdated
Comment thread Python/import.c
Comment thread Python/import.c Outdated
Comment thread Python/import.c Outdated

@gnprice gnprice left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks @nanjekyejoannah for the update! I think this refactor worked out very well.

Comment thread Python/import.c Outdated
int value = import_ensure_initialized(tstate, mod, name);
if (value == -1) {
remove_importlib_frames(tstate);
return NULL;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm looking back at what the goto error in the original context does, as a guide to what this error case should likely do.

One is remove_importlib_frames -- great. A couple of other steps there don't appear to apply.

But another one is Py_XDECREF(mod);. And in fact it does look like we should do that here. (If there hadn't been an error, we'd have returned mod to the caller -- which must mean the caller would own the reference, so it must be that we own the reference here. Which means if we return NULL and so don't pass the pointer on to some other code that will own the reference, it's up to us here to decref it away.)

I think that's then all of it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm looking back at what the goto error in the original context does, as a guide to what this error case should likely do.

One is remove_importlib_frames -- great. A couple of other steps there don't appear to apply.

But another one is Py_XDECREF(mod);. And in fact it does look like we should do that here. (If there hadn't been an error, we'd have returned mod to the caller -- which must mean the caller would own the reference, so it must be that we own the reference here. Which means if we return NULL and so don't pass the pointer on to some other code that will own the reference, it's up to us here to decref it away.)

One is remove_importlib_frames -- great. A couple of other steps there don't appear to apply.

Am also returning null following a review from @serhiy-storchaka above. no?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I agree about doing Py_XDECREF(mod). Thanks @gnprice .

Comment thread Python/import.c Outdated
mod = import_get_module(tstate, name);
if (mod != NULL && mod != Py_None) {
int value = import_ensure_initialized(tstate, mod, name);
if (value == -1) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same thing @serhiy-storchaka suggested at the other call site.

@@ -0,0 +1 @@
Added optimization to prevent `PyImport_GetModule()` from returning partially-initialized module. No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh also:

This NEWS entry (and the commit message) say "optimization", but the change is actually better than that! This changes the function's behavior, in a way that makes the API safer and makes it easier to avoid bugs when using it. So let's write the description to make that clear. 🙂

One good description might be:

The function :c:func:`PyImport_GetModule` now ensures any module it returns is fully initialized.

Also I think C API rather than Library would be the most helpful home for the NEWS entry.

@nanjekyejoannah

Copy link
Copy Markdown
Contributor Author

@gnprice and @serhiy-storchaka, I have made some changes PTAL.

Comment thread Python/import.c Outdated
Comment thread Python/import.c Outdated
Comment thread Misc/NEWS.d/next/Library/2019-07-31-15-52-51.bpo-35943.-KswoB.rst Outdated
Comment thread Python/import.c Outdated

@gnprice gnprice left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM! Thanks @nanjekyejoannah for this patch, and for all the updates.

Comment thread Misc/NEWS.d/next/Library/2019-07-31-15-52-51.bpo-35943.-KswoB.rst Outdated
Comment thread Python/import.c Outdated
@serhiy-storchaka

Copy link
Copy Markdown
Member

LGTM. @ericsnowcurrently, please take a look.

nanjekyejoannah and others added 2 commits August 3, 2019 12:32
Co-Authored-By: Serhiy Storchaka <storchaka@gmail.com>
Co-Authored-By: Serhiy Storchaka <storchaka@gmail.com>
@nanjekyejoannah

Copy link
Copy Markdown
Contributor Author

I have made the requested changes @ericsnowcurrently , @serhiy-storchaka , @gnprice PTAL .

Comment thread Python/import.c Outdated
stuffing the new module in sys.modules.
*/
spec = _PyObject_GetAttrId(mod, &PyId___spec__);
if (spec == NULL) {

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.

_PyModuleSpec_IsInitializing() was specially designed for convenience, so there is no need to check spec for NULL. You can save 4 lines of code.

Comment thread Python/import.c Outdated
Comment thread Python/import.c Outdated
@brettcannon

Copy link
Copy Markdown
Member

@nanjekyejoannah FYI you forgot to use the phrase "I have made the requested changes; please review again" to tell the bot to flag this PR as ready for re-review. I'll go ahead and do the label change manually.

@nanjekyejoannah

Copy link
Copy Markdown
Contributor Author

@nanjekyejoannah FYI you forgot to use the phrase "I have made the requested changes; please review again" to tell the bot to flag this PR as ready for re-review. I'll go ahead and do the label change manually.

My bad. Thanks for the reminder.

@bedevere-bot

Copy link
Copy Markdown

Thanks for making the requested changes!

@serhiy-storchaka, @ericsnowcurrently: please review the changes made to this pull request.

@vstinner

Copy link
Copy Markdown
Member

I didn't follow this change closely. When I look at the final merged change, it looks simple. But here I see a long discussion, which makes me understand that writing this change was quite difficult. So, well done Joannah for helping to make Python more correct ✨ 🍰 ✨ ;-)

DinoV pushed a commit to DinoV/cpython that referenced this pull request Sep 12, 2019
@miss-islington

Copy link
Copy Markdown
Contributor

Thanks @nanjekyejoannah for the PR, and @brettcannon for merging it 🌮🎉.. I'm working now to backport this PR to: 3.7.
🐍🍒⛏🤖

@miss-islington

Copy link
Copy Markdown
Contributor

Sorry, @nanjekyejoannah and @brettcannon, I could not cleanly backport this to 3.7 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 37c22206981f52ae35c28b39f7530f8438afbfdb 3.7

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.

9 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.