Skip to content

bpo-35993: Fix an incorrect use of released memory#11852

Merged
vstinner merged 8 commits into
python:masterfrom
matrixise:bpo-35993
Feb 20, 2019
Merged

bpo-35993: Fix an incorrect use of released memory#11852
vstinner merged 8 commits into
python:masterfrom
matrixise:bpo-35993

Conversation

@matrixise

@matrixise matrixise commented Feb 14, 2019

Copy link
Copy Markdown
Member

Comment thread Python/pystate.c Outdated
}
PyMem_RawFree(interp);
tmp_interp = interp;
PyMem_RawFree(tmp_interp);

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.

I don't understand how the current code can work since PyMem_RawFree() fills freed memory with a byte pattern 0xDB and so interp = interp->next should just crash.

I don't see how this change fix anything: interp still points to freed bytes.

You should read interp->next before PyMem_RawFree(), and so change how the loop is written.

cc @ericsnowcurrently

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.

When PyMem_RawFree(tmp_interp) the tmp_interp point to interp, so you are freed interp too, right?

What about this?

tmp_interp = interp->next;
for (; tmp_interp !=NULL; interp = tmp_interp){
...
tmp_interp = interp->next;
PyMem_RawFree(interp);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

sure? the last time I have coded in C, that was in 2007 :/ ok

@matrixise matrixise Feb 14, 2019

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

or just

PyInterpreterState *tmp_interp = NULL;
for (; interp != NULL;) {
    ...
    tmp_interp = interp;
    interp = interp->next;
    PyMem_RawFree(tmp_interp);
}

@vstinner and @eamanu

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@eamanu are you on Zulip or IRC?

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.

@matrixise I am connecting to zulip

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.

With a while (interp) should work the same, and the jungling of tmp/interp looks good to me.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@JulienPalard I have just updated my PR, thanks for the review.
Now, I am going to wait for the review of @vstinner, he is more expert than me with the C language.

JulienPalard
JulienPalard previously approved these changes Feb 14, 2019

@JulienPalard JulienPalard left a comment

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.

LGTM

@eamanu eamanu 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

@matrixise matrixise changed the title bpo-35993: Fix an incorrect use of released memory WIP: bpo-35993: Fix an incorrect use of released memory Feb 14, 2019
Comment thread Python/pystate.c Outdated
for (; interp != NULL; interp = interp->next) {
fprintf(stdout, "1. interp: %p\n", interp);
fprintf(stdout, "2. interp->next: %p\n", interp->next);
fprintf(stdout, "2.1. _PyRuntime.interpreters.main: %p\n", _PyRuntime.interpreters.main);

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.

Remove debug printf.

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.

(Those have been pushed recently to diagnose the "take infinite time to build when this code is added" / "make CI timeout" issue)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@vstinner yep, just for the debug and because I wanted to show you

Comment thread Python/pystate.c Outdated
Comment thread Python/pystate.c Outdated
@bedevere-bot

Copy link
Copy Markdown

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.

@vstinner vstinner left a comment

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.

I don't understand how the current code can code: it must crash if I understand correctly.

Is the function called? You may modify the code to add abort(), run the full Python test suite and check if a test does crash.

If there is no crash, would it be possible to add a test?

cc @ericsnowcurrently

@vstinner

Copy link
Copy Markdown
Member
for (; tmp_interp !=NULL; interp = tmp_interp){
...
tmp_interp = interp->next;
PyMem_RawFree(interp);
}

I prefer this version, especially if you rename tmp_interp to next_interp.

@JulienPalard

Copy link
Copy Markdown
Member

Current version does not compile, runs indefinitely, making CI timeout.

@matrixise

Copy link
Copy Markdown
Member Author

@vstinner it's my fault if my PR is broken after the approval of @JulienPalard. But I am working on it and try to fix it.

@matrixise

Copy link
Copy Markdown
Member Author

@vstinner @ericsnowcurrently the current code is used when you compile Python, but there is no crash (un/fortunately)

@JulienPalard JulienPalard left a comment

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.

LGTM

@matrixise

Copy link
Copy Markdown
Member Author

@vstinner the code works and the tests pass. no lock on travis.

@matrixise matrixise changed the title WIP: bpo-35993: Fix an incorrect use of released memory bpo-35993: Fix an incorrect use of released memory Feb 14, 2019
@vstinner

Copy link
Copy Markdown
Member

@vstinner @ericsnowcurrently the current code is used when you compile Python

Would you mind to elaborate? I would like to make sure that the function is properly tested.

but there is no crash (un/fortunately)

Strange. So maybe the current code is just fine? Or we miss a test.

@matrixise

Copy link
Copy Markdown
Member Author

@vstinner example when you compile python

gcc -pthread -shared build/temp.linux-x86_64-3.8-pydebug/home/stephane/src/github.com/python/cpython/Modules/_contextvarsmodule.o -L/home/stephane/src/github.com/python/cpython-add_smtpshandler/lib -L/usr/local/lib -o build/lib.linux-x86_64-3.8-pydebug/_contextvars.cpython-38dm-x86_64-linux-gnu.so
1 _PyInterpreterState_DeleteExceptMain
2 _PyInterpreterState_DeleteExceptMain
#### _PyInterpreterState_DeleteExceptMain
building 'cmath' extension
gcc -pthread -fPIC -Wno-unused-result -Wsign-compare -g -Og -Wall -std=c99 -Wextra -Wno-unused-result -Wno-unused-parameter -Wno-missing-field-initializers -Werror=implicit-function-declaration -I./Include/internal -I./Include -I/home/stephane/src/github.com/python/cpython-add_smtpshandler/include -I. -I/usr/local/include -I/home/stephane/src/github.com/python/cpython/Include -I/home/stephane/src/github.com/python/cpython -c /home/stephane/src/github.com/python/cpython/Modules/cmathmodule.c -o build/temp.linux-x86_64-3.8-pydebug/home/stephane/src/github.com/python/cpython/Modules/cmathmodule.o
1 _PyInterpreterState_DeleteExceptMain
2 _PyInterpreterState_DeleteExceptMain
#### _PyInterpreterState_DeleteExceptMain

@vstinner

Copy link
Copy Markdown
Member

Ok, but I guess that the code path which trigger the bug is not taken, since according to the bug tracker, it must crash. I guess that no test call this function with more than 1 interpreter. That's why I added @ericsnowcurrently in copy of this change :-)

@eamanu

eamanu commented Feb 14, 2019

Copy link
Copy Markdown
Contributor

I am not sure when _PyInterpreterState_DeleteExceptMain() is called. This way we could test it. @vstinner @matrixise

Comment thread Python/pystate.c Outdated
@matrixise

Copy link
Copy Markdown
Member Author

@eamanu as you can see my paste in the previous comment, the function is called when we try to compile Python, certainly in the Makefile.

@methane

methane commented Feb 15, 2019

Copy link
Copy Markdown
Member

I don't understand how the current code can code: it must crash if I understand correctly.

@vstinner this for loop iterate over (sub)interpreters.
When there is only main interpreter, PyMem_RawFree(interp); is never called.

cpython/Python/pystate.c

Lines 285 to 289 in 3e028b2

if (interp == _PyRuntime.interpreters.main) {
_PyRuntime.interpreters.main->next = NULL;
_PyRuntime.interpreters.head = interp;
continue;
}

@matrixise

Copy link
Copy Markdown
Member Author

@ericsnowcurrently Any advice for a test for this part?
Thank you,

@@ -0,0 +1 @@
Fix an incorrect use of released memory. Contributed by Stéphane Wirtel

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.

Only from this NEWS entry, it's hard to know which code is impacted. I found PyOS_AfterFork_Child() which calls _PyInterpreterState_DeleteExceptMain(). I understand that the bug triggers if an application using multiple interpreters forks... it sounds like a very unusual use case. I propose:

"Fix a crash on fork when using subinterpreters. Contributed by Stéphane Wirtel."

@matrixise

Copy link
Copy Markdown
Member Author

@vstinner I have just updated the blurb entry, sorry I didn't see your notification

@vstinner
vstinner merged commit b5409da into python:master Feb 20, 2019
@miss-islington

Copy link
Copy Markdown
Contributor

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

@miss-islington

Copy link
Copy Markdown
Contributor

Sorry, @matrixise and @vstinner, I could not cleanly backport this to 3.7 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker b5409dacc4885146a27d06482b346e55fa12d2ec 3.7

@vstinner

Copy link
Copy Markdown
Member

Ah, it's a new function in Python 3.8. I didn't know. No need to backport in that case.

@matrixise

Copy link
Copy Markdown
Member Author

@vstinner thank you for the merge ;-) a good news for today ;-)

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.

8 participants