Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign upbpo-38076 Clear the interpreter state only after clearing module globals #18039
Conversation
This comment has been minimized.
This comment has been minimized.
bedevere-bot
commented
Jan 17, 2020
If you want to schedule another build, you need to add the " |
This comment has been minimized.
This comment has been minimized.
I'm about to hop on a plane so I can't check it now but I'm curious what happens with:
|
This comment has been minimized.
This comment has been minimized.
Still segfaults on my system:
|
This comment has been minimized.
This comment has been minimized.
That of course fails since we are clearing the module state before we clear up the sys globals. You bring up a good point though. I'll just push this past the clearing of every module dictionary. I just tested that locally and it worked, even on your new example. I will add a new test and update the PR |
This comment has been minimized.
This comment has been minimized.
Another possibility would be restoring sys to its original form like we do builtins: https://github.com/eduardo-elizondo/cpython/blob/f2cfc13f65e94f755b5d47218f4479bca30118fc/Python/import.c#L564 And then collecting and then killing off sys/builtin and collecting again. |
It'd be good to add the various test cases in the bug to the PR as well. |
This comment has been minimized.
This comment has been minimized.
@DinoV given that sys is also treated specially just like builtins, it might make sense to also add this. Also, agreed now that you've pointed out a couple of other edge cases, I'll add more tests. |
This comment has been minimized.
This comment has been minimized.
Actually, I decided against creating a sysdict copy to avoid increasing the heap memory needed for the interpreter state. Just pushing further back the module state clearing does the trick. By the way, as you might have noticed in the sys test, |
@@ -619,6 +617,9 @@ _PyImport_Cleanup(PyThreadState *tstate) | |||
} | |||
_PyModule_ClearDict(interp->builtins); | |||
|
|||
/* Clear module dict copies stored in the interpreter state */ |
This comment has been minimized.
This comment has been minimized.
eduardo-elizondo
Jan 18, 2020
Author
Contributor
I'm tempted to change this comment to: "Clear module dict copies stored in the interpreter state only after all the modules have been cleared" or something along those lines.
This comment has been minimized.
This comment has been minimized.
Jongy
commented
Jan 18, 2020
Wow. Funny story. I was debugging some Python crash I got lately, and realized it has something to do with mishandled refcounts. I hooked After "solving" that with a temporary Just before getting off the computer, I hopped by the latest PRs of CPython, to see what kind of interpreter bugs people usually encounter and fix. And so it happens the very first PR I stumble upon is this exact problem. Luckiest click ever. TL;DR it was funny and I can confirm moving |
eduardo-elizondo commentedJan 17, 2020
•
edited
Currently, during runtime destruction,
_PyImport_Cleanup
is clearing the interpreter state before clearing out the modules themselves. This leads to a segfault on modules that rely on the module state to clear themselves up.For example, let's take the small snippet added in the issue by @DinoV :
The module
_struct
uses the module state to runpack
. Therefore, the module state has to be alive until after the module has been cleared out to successfully runC.__del__
. This happens at line 606, when_PyImport_Cleanup
calls_PyModule_Clear
. In fact, the loop that calls_PyModule_Clear
has in its comments:That means that we can't clear the module state (which is used by C Extensions) before we run that loop.
Moving
_PyInterpreterState_ClearModules
until after it, fixes the segfault in the code snippet.Finally, this updates a test in
io
to correctly assert the error that it now throws (since it now finds the io module state). The test that uses this is:test_create_at_shutdown_without_encoding
. Given this test is now working is a proof that the module state now stays alive even when__del__
is called at module destruction time. Thus, I didn't add a new tests for this.https://bugs.python.org/issue38076