From 622453192f7c385e79a1560fdb7fa6e2899cdd64 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 11 Jul 2018 11:18:35 +0200 Subject: [PATCH 1/2] bpo-34080: Fix memory leak on parsing error * bpo-34080, bpo-34084: err_free() now always releases 'text' memory allocated by PyObject_Malloc() to fix a memory leak on parsing error. Previously, err->text was not released (by err_input()) on E_ERROR error. * Remove also "with Barry as BDFL, use '<>' instead of '!='" static string error message (previously set to err_ret->text) because in practice, err_ret->text is always set later. Add also an assertion to make sure that err_ret->text is only set once. * Replace old PyObject_MALLOC() and PyObject_FREE() aliases with PyObject_Malloc() and PyObject_Free() function calls. Co-Authored-By: Serhiy Storchaka Co-Authored-By: Xiang Zhang --- .../2018-07-11-11-20-12.bpo-34080.8t7PtO.rst | 2 ++ Parser/parsetok.c | 7 ++++--- Python/pythonrun.c | 4 +++- 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2018-07-11-11-20-12.bpo-34080.8t7PtO.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-07-11-11-20-12.bpo-34080.8t7PtO.rst b/Misc/NEWS.d/next/Core and Builtins/2018-07-11-11-20-12.bpo-34080.8t7PtO.rst new file mode 100644 index 00000000000000..cfc53cca487907 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-07-11-11-20-12.bpo-34080.8t7PtO.rst @@ -0,0 +1,2 @@ +Fixed a memory leak in the compiler when it raised some uncommon errors +during tokenizing. diff --git a/Parser/parsetok.c b/Parser/parsetok.c index 1f467d63c41e24..33301c47c2f726 100644 --- a/Parser/parsetok.c +++ b/Parser/parsetok.c @@ -246,8 +246,6 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, else if ((ps->p_flags & CO_FUTURE_BARRY_AS_BDFL) && strcmp(str, "<>")) { PyObject_FREE(str); - err_ret->text = "with Barry as BDFL, use '<>' " - "instead of '!='"; err_ret->error = E_SYNTAX; break; } @@ -322,7 +320,10 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, assert(tok->cur - tok->buf < INT_MAX); err_ret->offset = (int)(tok->cur - tok->buf); len = tok->inp - tok->buf; - err_ret->text = (char *) PyObject_MALLOC(len + 1); + /* make sure that we don't leak memory if text has been + set previously */ + assert(err_ret->text == NULL); + err_ret->text = (char *) PyObject_Malloc(len + 1); if (err_ret->text != NULL) { if (len > 0) strncpy(err_ret->text, tok->buf, len); diff --git a/Python/pythonrun.c b/Python/pythonrun.c index bcd1ca931d03d3..006082414f4043 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1324,6 +1324,8 @@ static void err_free(perrdetail *err) { Py_CLEAR(err->filename); + PyObject_Free(err->text); + err->text = NULL; } /* Set the error appropriate to the given input error code (see errcode.h) */ @@ -1446,7 +1448,7 @@ err_input(perrdetail *err) cleanup: Py_XDECREF(msg_obj); if (err->text != NULL) { - PyObject_FREE(err->text); + PyObject_Free(err->text); err->text = NULL; } } From fdf73c9036aad00b0ca5a309734cd2a62329bab8 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 11 Jul 2018 14:18:55 +0200 Subject: [PATCH 2/2] Only clear err->text in err_free() --- Python/pythonrun.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 006082414f4043..73376ec763e376 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -63,7 +63,7 @@ static PyObject *run_mod(mod_ty, PyObject *, PyObject *, PyObject *, PyCompilerFlags *, PyArena *); static PyObject *run_pyc_file(FILE *, const char *, PyObject *, PyObject *, PyCompilerFlags *); -static void err_input(perrdetail *); +static void err_input(const perrdetail *); static void err_free(perrdetail *); static int PyRun_InteractiveOneObjectEx(FILE *, PyObject *, PyCompilerFlags *); @@ -1331,7 +1331,7 @@ err_free(perrdetail *err) /* Set the error appropriate to the given input error code (see errcode.h) */ static void -err_input(perrdetail *err) +err_input(const perrdetail *err) { PyObject *v, *w, *errtype, *errtext; PyObject *msg_obj = NULL; @@ -1447,10 +1447,6 @@ err_input(perrdetail *err) Py_XDECREF(w); cleanup: Py_XDECREF(msg_obj); - if (err->text != NULL) { - PyObject_Free(err->text); - err->text = NULL; - } }