@@ -1057,6 +1057,17 @@ def visitModule(self, mod):
10571057 self .emit ("astmodule_exec(PyObject *m)" , 0 )
10581058 self .emit ("{" , 0 )
10591059 self .emit ('astmodulestate *state = get_ast_state(m);' , 1 )
1060+ self .emit ("if (state == NULL) {" , 1 )
1061+ self .emit ("return -1;" , 2 )
1062+ self .emit ("}" , 1 )
1063+ self .emit ("#ifndef Py_BUILD_CORE" , 0 )
1064+ self .emit ('if (state->initialized) {' , 1 )
1065+ self .emit ('PyErr_SetString(' , 2 )
1066+ self .emit ('PyExc_ImportError,' , 3 )
1067+ self .emit ('"cannot load non-core _ast module more than once per process");' , 3 )
1068+ self .emit ("return -1;" , 2 )
1069+ self .emit ('}' , 1 )
1070+ self .emit ("#endif" , 0 )
10601071 self .emit ("" , 0 )
10611072
10621073 self .emit ("if (!init_types(state)) {" , 1 )
@@ -1089,7 +1100,7 @@ def visitModule(self, mod):
10891100static struct PyModuleDef _astmodule = {
10901101 PyModuleDef_HEAD_INIT,
10911102 .m_name = "_ast",
1092- // The _ast module uses a global state (global_ast_state).
1103+ // The _ast module uses a per-interpreter state (see get_global_ast_state)
10931104 .m_size = 0,
10941105 .m_slots = astmodule_slots,
10951106};
@@ -1366,17 +1377,59 @@ def generate_module_def(f, mod):
13661377 module_state .add (tp )
13671378 state_strings = sorted (state_strings )
13681379 module_state = sorted (module_state )
1369- f .write ('typedef struct {\n ' )
1380+ f .write ('typedef struct _Py_ast_state {\n ' )
13701381 f .write (' int initialized;\n ' )
13711382 for s in module_state :
13721383 f .write (' PyObject *' + s + ';\n ' )
13731384 f .write ('} astmodulestate;\n \n ' )
13741385 f .write ("""
13751386// Forward declaration
13761387static int init_types(astmodulestate *state);
1388+ static void fini_types(astmodulestate *state);
13771389
1378- // bpo-41194, bpo-41261, bpo-41631: The _ast module uses a global state.
1379- static astmodulestate global_ast_state = {0};
1390+ #ifdef Py_BUILD_CORE
1391+
1392+ // bpo-41194, bpo-41261, bpo-41631: The _ast module uses a per-interpreter
1393+ // state; if several _ast module objects are created, they share the state
1394+ // including all AST types.
1395+ // The state is allocated and initialized on demand.
1396+
1397+ static astmodulestate*
1398+ get_global_ast_state(void)
1399+ {
1400+ PyInterpreterState* interp = _PyInterpreterState_Get();
1401+ if (interp->ast_state == NULL) {
1402+ interp->ast_state = (astmodulestate*)PyMem_Calloc(1, sizeof(astmodulestate));
1403+ }
1404+ if (interp->ast_state == NULL) {
1405+ PyErr_NoMemory();
1406+ return NULL;
1407+ }
1408+ if (!init_types(interp->ast_state)) {
1409+ PyMem_Free(interp->ast_state);
1410+ interp->ast_state = NULL;
1411+ return NULL;
1412+ }
1413+ return interp->ast_state;
1414+ }
1415+
1416+ void
1417+ _PyAST_Fini(PyThreadState *tstate)
1418+ {
1419+ PyInterpreterState* interp = tstate->interp;
1420+ fini_types(interp->ast_state);
1421+ PyMem_Free(interp->ast_state);
1422+ interp->ast_state = NULL;
1423+ }
1424+
1425+ #else
1426+
1427+ // HACK: If we're not building CPython core (as happens in pegen tests),
1428+ // we use a static global module state object.
1429+ // In astmodule_exec, we limit such modules to be only importable once
1430+ // per process, so the state doesn't end up shared across interpreters.
1431+
1432+ static astmodulestate global_ast_state;
13801433
13811434static astmodulestate*
13821435get_global_ast_state(void)
@@ -1388,6 +1441,14 @@ def generate_module_def(f, mod):
13881441 return state;
13891442}
13901443
1444+ void
1445+ _PyAST_Fini(PyThreadState *tstate)
1446+ {
1447+ fini_types(&global_ast_state);
1448+ }
1449+
1450+ #endif
1451+
13911452static astmodulestate*
13921453get_ast_state(PyObject* Py_UNUSED(module))
13931454{
@@ -1398,9 +1459,12 @@ def generate_module_def(f, mod):
13981459 return state;
13991460}
14001461
1401- void _PyAST_Fini(PyThreadState *tstate)
1462+ static void
1463+ fini_types(astmodulestate* state)
14021464{
1403- astmodulestate* state = &global_ast_state;
1465+ if (state == NULL || !state->initialized) {
1466+ return;
1467+ }
14041468""" )
14051469 for s in module_state :
14061470 f .write (" Py_CLEAR(state->" + s + ');\n ' )
@@ -1452,6 +1516,9 @@ def write_source(f, mod):
14521516 f .write ('#include "Python.h"\n ' )
14531517 f .write ('#include "%s-ast.h"\n ' % mod .name )
14541518 f .write ('#include "structmember.h" // PyMemberDef\n ' )
1519+ f .write ('#if Py_BUILD_CORE\n ' )
1520+ f .write ('#include "pycore_interp.h" // _PyInterpreterState.ast_state\n ' )
1521+ f .write ('#endif\n ' )
14551522 f .write ('\n ' )
14561523
14571524 generate_module_def (f , mod )
0 commit comments