Original file line numberDiff line numberDiff line change@@ -0,0 +1,3 @@
1+Fix a potential crash in :func:`compile`, :func:`exec`, :func:`eval` and
2+:func:`ast.parse` when an allocation fails: the parser or compiler could
3+return without setting an exception.
Original file line numberDiff line numberDiff line change@@ -940,6 +940,11 @@ _PyPegen_run_parser(Parser *p)
940940{
941941void*res=_PyPegen_parse(p);
942942assert(p->level==0);
943+if (res!=NULL&&PyErr_Occurred()) {
944+// Discard a result returned with an exception still pending
945+// (e.g. a MemoryError from a recovered-from allocation failure).
946+returnNULL;
947+ }
943948if (res==NULL) {
944949if ((p->flags&PyPARSE_ALLOW_INCOMPLETE_INPUT) &&_is_end_of_source(p)) {
945950PyErr_Clear();
@@ -995,7 +1000,10 @@ _PyPegen_run_parser_from_file_pointer(FILE *fp, int start_rule, PyObject *filena
9951000if (tok==NULL) {
9961001if (PyErr_Occurred()) {
9971002_PyTokenizer_raise_init_error(filename_ob);
998-returnNULL;
1003+ }
1004+else {
1005+// The only silent tokenizer init failure is a failed allocation.
1006+PyErr_NoMemory();
9991007 }
10001008returnNULL;
10011009 }
@@ -1054,6 +1062,10 @@ _PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filen
10541062if (PyErr_Occurred()) {
10551063_PyTokenizer_raise_init_error(filename_ob);
10561064 }
1065+else {
1066+// The only silent tokenizer init failure is a failed allocation.
1067+PyErr_NoMemory();
1068+ }
10571069returnNULL;
10581070 }
10591071// This transfers the ownership to the tokenizer
Original file line numberDiff line numberDiff line change@@ -174,6 +174,7 @@ new_compiler(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags,
174174{
175175compiler*c=PyMem_Calloc(1, sizeof(compiler));
176176if (c==NULL) {
177+PyErr_NoMemory();
177178returnNULL;
178179 }
179180if (compiler_setup(c, mod, filename, pflags, optimize, arena, module) <0) {