bpo-30696: Fix the REPL looping endlessly when no memory (GH-4160) · python/cpython@e0582a3
@@ -65,6 +65,7 @@ static PyObject *run_pyc_file(FILE *, const char *, PyObject *, PyObject *,
6565PyCompilerFlags *);
6666static void err_input(perrdetail *);
6767static void err_free(perrdetail *);
68+static int PyRun_InteractiveOneObjectEx(FILE *, PyObject *, PyCompilerFlags *);
68696970/* Parse input from a file and execute it */
7071int
@@ -89,6 +90,7 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename_str, PyCompilerFlags *
8990PyObject *filename, *v;
9091int ret, err;
9192PyCompilerFlags local_flags;
93+int nomem_count = 0;
92949395filename = PyUnicode_DecodeFSDefault(filename_str);
9496if (filename == NULL) {
@@ -110,22 +112,32 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename_str, PyCompilerFlags *
110112_PySys_SetObjectId(&PyId_ps2, v = PyUnicode_FromString("... "));
111113Py_XDECREF(v);
112114 }
113-err = -1;
114-for (;;) {
115-ret = PyRun_InteractiveOneObject(fp, filename, flags);
115+err = 0;
116+do {
117+ret = PyRun_InteractiveOneObjectEx(fp, filename, flags);
118+if (ret == -1 && PyErr_Occurred()) {
119+/* Prevent an endless loop after multiple consecutive MemoryErrors
120+ * while still allowing an interactive command to fail with a
121+ * MemoryError. */
122+if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
123+if (++nomem_count > 16) {
124+PyErr_Clear();
125+err = -1;
126+break;
127+ }
128+ } else {
129+nomem_count = 0;
130+ }
131+PyErr_Print();
132+flush_io();
133+ } else {
134+nomem_count = 0;
135+ }
116136#ifdef Py_REF_DEBUG
117137if (_PyDebug_XOptionShowRefCount() == Py_True)
118138_PyDebug_PrintTotalRefs();
119139#endif
120-if (ret == E_EOF) {
121-err = 0;
122-break;
123- }
124-/*
125- if (ret == E_NOMEM)
126- break;
127- */
128- }
140+ } while (ret != E_EOF);
129141Py_DECREF(filename);
130142return err;
131143}
@@ -154,8 +166,11 @@ static int PARSER_FLAGS(PyCompilerFlags *flags)
154166 PyPARSE_WITH_IS_KEYWORD : 0)) : 0)
155167#endif
156168157-int
158-PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags)
169+/* A PyRun_InteractiveOneObject() auxiliary function that does not print the
170+ * error on failure. */
171+static int
172+PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename,
173+PyCompilerFlags *flags)
159174{
160175PyObject *m, *d, *v, *w, *oenc = NULL, *mod_name;
161176mod_ty mod;
@@ -167,7 +182,6 @@ PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags)
167182168183mod_name = _PyUnicode_FromId(&PyId___main__); /* borrowed */
169184if (mod_name == NULL) {
170-PyErr_Print();
171185return -1;
172186 }
173187@@ -227,7 +241,6 @@ PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags)
227241PyErr_Clear();
228242return E_EOF;
229243 }
230-PyErr_Print();
231244return -1;
232245 }
233246m = PyImport_AddModuleObject(mod_name);
@@ -239,15 +252,26 @@ PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags)
239252v = run_mod(mod, filename, d, d, flags, arena);
240253PyArena_Free(arena);
241254if (v == NULL) {
242-PyErr_Print();
243-flush_io();
244255return -1;
245256 }
246257Py_DECREF(v);
247258flush_io();
248259return 0;
249260}
250261262+int
263+PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags)
264+{
265+int res;
266+267+res = PyRun_InteractiveOneObjectEx(fp, filename, flags);
268+if (res == -1) {
269+PyErr_Print();
270+flush_io();
271+ }
272+return res;
273+}
274+251275int
252276PyRun_InteractiveOneFlags(FILE *fp, const char *filename_str, PyCompilerFlags *flags)
253277{