diff options
author | Victor Stinner <vstinner@python.org> | 2020-11-03 17:07:15 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-03 17:07:15 (GMT) |
commit | fd957c124c44441d9c5eaf61f7af8cf266bafcb1 (patch) | |
tree | 2d73071bb42fe4496d11d79007eb4930fe5fd673 /Parser/asdl_c.py | |
parent | 212d32f45c91849c17a82750df1ac498d63976be (diff) | |
download | cpython-fd957c124c44441d9c5eaf61f7af8cf266bafcb1.zip cpython-fd957c124c44441d9c5eaf61f7af8cf266bafcb1.tar.gz cpython-fd957c124c44441d9c5eaf61f7af8cf266bafcb1.tar.bz2 |
bpo-41796: Call _PyAST_Fini() earlier to fix a leak (GH-23131)
Call _PyAST_Fini() on all interpreters, not only on the main
interpreter. Also, call it ealier to fix a reference leak.
Python types contain a reference to themselves in in their
PyTypeObject.tp_mro member. _PyAST_Fini() must called before the last
GC collection to destroy AST types.
_PyInterpreterState_Clear() now calls _PyAST_Fini(). It now also
calls _PyWarnings_Fini() on subinterpeters, not only on the main
interpreter.
Add an assertion in AST init_types() to ensure that the _ast module
is no longer used after _PyAST_Fini() has been called.
Diffstat (limited to 'Parser/asdl_c.py')
-rwxr-xr-x | Parser/asdl_c.py | 69 |
1 files changed, 45 insertions, 24 deletions
diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index 9a833e8..9fec7ae 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -1015,18 +1015,35 @@ static int add_ast_fields(struct ast_state *state) """, 0, reflow=False) - self.emit("static int init_types(struct ast_state *state)",0) - self.emit("{", 0) - self.emit("if (state->initialized) return 1;", 1) - self.emit("if (init_identifiers(state) < 0) return 0;", 1) - self.emit("state->AST_type = PyType_FromSpec(&AST_type_spec);", 1) - self.emit("if (!state->AST_type) return 0;", 1) - self.emit("if (add_ast_fields(state) < 0) return 0;", 1) + self.file.write(textwrap.dedent(''' + static int + init_types(struct ast_state *state) + { + // init_types() must not be called after _PyAST_Fini() + // has been called + assert(state->initialized >= 0); + + if (state->initialized) { + return 1; + } + if (init_identifiers(state) < 0) { + return 0; + } + state->AST_type = PyType_FromSpec(&AST_type_spec); + if (!state->AST_type) { + return 0; + } + if (add_ast_fields(state) < 0) { + return 0; + } + ''')) for dfn in mod.dfns: self.visit(dfn) - self.emit("state->initialized = 1;", 1) - self.emit("return 1;", 1); - self.emit("}", 0) + self.file.write(textwrap.dedent(''' + state->initialized = 1; + return 1; + } + ''')) def visitProduct(self, prod, name): if prod.fields: @@ -1353,23 +1370,27 @@ def generate_ast_state(module_state, f): def generate_ast_fini(module_state, f): - f.write(""" -void _PyAST_Fini(PyThreadState *tstate) -{ -#ifdef Py_BUILD_CORE - struct ast_state *state = &tstate->interp->ast; -#else - struct ast_state *state = &global_ast_state; -#endif - -""") + f.write(textwrap.dedent(""" + void _PyAST_Fini(PyInterpreterState *interp) + { + #ifdef Py_BUILD_CORE + struct ast_state *state = &interp->ast; + #else + struct ast_state *state = &global_ast_state; + #endif + + """)) for s in module_state: f.write(" Py_CLEAR(state->" + s + ');\n') - f.write(""" - state->initialized = 0; -} + f.write(textwrap.dedent(""" + #if defined(Py_BUILD_CORE) && !defined(NDEBUG) + state->initialized = -1; + #else + state->initialized = 0; + #endif + } -""") + """)) def generate_module_def(mod, f, internal_h): |