From efbb1eb9f54cad4f7bf5df03eed3a6aba02d99f4 Mon Sep 17 00:00:00 2001 From: colorfulappl Date: Sat, 17 Dec 2022 14:37:44 +0800 Subject: [PATCH] gh-99240: Reset pointer to NULL when the pointed memory is freed in argument parsing (#99890) Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Co-authored-by: Erlend E. Aasland --- Lib/test/test_capi/test_getargs.py | 4 ++++ ...2-11-30-16-39-22.gh-issue-99240.67nAX-.rst | 2 ++ Modules/_testcapi/getargs.c | 19 +++++++++++++++++++ Python/getargs.c | 10 +++++----- 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2022-11-30-16-39-22.gh-issue-99240.67nAX-.rst diff --git a/Lib/test/test_capi/test_getargs.py b/Lib/test/test_capi/test_getargs.py index 1d5c7fbaa1510a..3792d1a6515b44 100644 --- a/Lib/test/test_capi/test_getargs.py +++ b/Lib/test/test_capi/test_getargs.py @@ -1085,6 +1085,10 @@ def test_Z_hash(self): with self.assertWarns(DeprecationWarning): self.assertIsNone(getargs_Z_hash(None)) + def test_gh_99240_clear_args(self): + from _testcapi import gh_99240_clear_args + self.assertRaises(TypeError, gh_99240_clear_args, 'a', '\0b') + class Object_TestCase(unittest.TestCase): def test_S(self): diff --git a/Misc/NEWS.d/next/C API/2022-11-30-16-39-22.gh-issue-99240.67nAX-.rst b/Misc/NEWS.d/next/C API/2022-11-30-16-39-22.gh-issue-99240.67nAX-.rst new file mode 100644 index 00000000000000..9a1bb3cf5a73f0 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-11-30-16-39-22.gh-issue-99240.67nAX-.rst @@ -0,0 +1,2 @@ +In argument parsing, after deallocating newly allocated memory, reset its +pointer to NULL. diff --git a/Modules/_testcapi/getargs.c b/Modules/_testcapi/getargs.c index 25a8e5fe8b605b..aa201319950de7 100644 --- a/Modules/_testcapi/getargs.c +++ b/Modules/_testcapi/getargs.c @@ -854,6 +854,24 @@ getargs_s_hash_int2(PyObject *self, PyObject *args, PyObject *kwargs) Py_RETURN_NONE; } +static PyObject * +gh_99240_clear_args(PyObject *self, PyObject *args) +{ + char *a = NULL; + char *b = NULL; + + if (!PyArg_ParseTuple(args, "eses", "idna", &a, "idna", &b)) { + if (a || b) { + PyErr_Clear(); + PyErr_SetString(PyExc_AssertionError, "Arguments are not cleared."); + } + return NULL; + } + PyMem_Free(a); + PyMem_Free(b); + Py_RETURN_NONE; +} + static PyMethodDef test_methods[] = { {"get_args", get_args, METH_VARARGS}, {"get_kwargs", _PyCFunction_CAST(get_kwargs), METH_VARARGS|METH_KEYWORDS}, @@ -906,6 +924,7 @@ static PyMethodDef test_methods[] = { {"test_empty_argparse", test_empty_argparse, METH_NOARGS}, {"test_k_code", test_k_code, METH_NOARGS}, {"test_s_code", test_s_code, METH_NOARGS}, + {"gh_99240_clear_args", gh_99240_clear_args, METH_VARARGS}, {NULL}, }; diff --git a/Python/getargs.c b/Python/getargs.c index 0167dd753d88f7..66dd90877fe6ff 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -202,9 +202,9 @@ _PyArg_VaParse_SizeT(PyObject *args, const char *format, va_list va) static int cleanup_ptr(PyObject *self, void *ptr) { - if (ptr) { - PyMem_Free(ptr); - } + void **pptr = (void **)ptr; + PyMem_Free(*pptr); + *pptr = NULL; return 0; } @@ -1116,7 +1116,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, PyErr_NoMemory(); RETURN_ERR_OCCURRED; } - if (addcleanup(*buffer, freelist, cleanup_ptr)) { + if (addcleanup(buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr( "(cleanup problem)", @@ -1162,7 +1162,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, PyErr_NoMemory(); RETURN_ERR_OCCURRED; } - if (addcleanup(*buffer, freelist, cleanup_ptr)) { + if (addcleanup(buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr("(cleanup problem)", arg, msgbuf, bufsize);