diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-12-03-55.gh-issue-151763.K7QfWG.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-12-03-55.gh-issue-151763.K7QfWG.rst new file mode 100644 index 000000000000000..64d0146cb091016 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-23-12-03-55.gh-issue-151763.K7QfWG.rst @@ -0,0 +1,3 @@ +Fix a potential crash in :func:`compile`, :func:`exec`, :func:`eval` and +:func:`ast.parse` when an allocation fails: the parser or compiler could +return without setting an exception. diff --git a/Parser/pegen.c b/Parser/pegen.c index bb222b50fc095f2..165dcb9f9950955 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -940,6 +940,11 @@ _PyPegen_run_parser(Parser *p) { void *res = _PyPegen_parse(p); assert(p->level == 0); + if (res != NULL && PyErr_Occurred()) { + // Discard a result returned with an exception still pending + // (e.g. a MemoryError from a recovered-from allocation failure). + return NULL; + } if (res == NULL) { if ((p->flags & PyPARSE_ALLOW_INCOMPLETE_INPUT) && _is_end_of_source(p)) { PyErr_Clear(); @@ -995,7 +1000,10 @@ _PyPegen_run_parser_from_file_pointer(FILE *fp, int start_rule, PyObject *filena if (tok == NULL) { if (PyErr_Occurred()) { _PyTokenizer_raise_init_error(filename_ob); - return NULL; + } + else { + // The only silent tokenizer init failure is a failed allocation. + PyErr_NoMemory(); } return NULL; } @@ -1054,6 +1062,10 @@ _PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filen if (PyErr_Occurred()) { _PyTokenizer_raise_init_error(filename_ob); } + else { + // The only silent tokenizer init failure is a failed allocation. + PyErr_NoMemory(); + } return NULL; } // This transfers the ownership to the tokenizer diff --git a/Python/compile.c b/Python/compile.c index e223ef42a42e22b..f2c1de5e0c07c63 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -174,6 +174,7 @@ new_compiler(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags, { compiler *c = PyMem_Calloc(1, sizeof(compiler)); if (c == NULL) { + PyErr_NoMemory(); return NULL; } if (compiler_setup(c, mod, filename, pflags, optimize, arena, module) < 0) {