From 28d0bcac8b7e6dbd28311f1283dabb6a4d649fcb Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 2 Mar 2020 08:42:39 +0200 Subject: bpo-38913: Fix segfault in Py_BuildValue("(s#O)", ...) if entered with exception raised. (GH-18656) --- .../C API/2020-02-25-20-10-34.bpo-38913.siF1lS.rst | 2 + Modules/_testcapimodule.c | 43 ++++++++++++++++++++++ Python/modsupport.c | 6 +-- 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2020-02-25-20-10-34.bpo-38913.siF1lS.rst diff --git a/Misc/NEWS.d/next/C API/2020-02-25-20-10-34.bpo-38913.siF1lS.rst b/Misc/NEWS.d/next/C API/2020-02-25-20-10-34.bpo-38913.siF1lS.rst new file mode 100644 index 0000000..0e4d121 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-02-25-20-10-34.bpo-38913.siF1lS.rst @@ -0,0 +1,2 @@ +Fixed segfault in ``Py_BuildValue()`` called with a format containing "#" +and undefined PY_SSIZE_T_CLEAN whwn an exception is set. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index eb31a0e..23a27e3 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5258,6 +5258,9 @@ meth_fastcall_keywords(PyObject* self, PyObject* const* args, return Py_BuildValue("NNN", _null_to_none(self), pyargs, pykwargs); } + +static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); + static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, {"raise_memoryerror", raise_memoryerror, METH_NOARGS}, @@ -5322,6 +5325,7 @@ static PyMethodDef TestMethods[] = { {"getbuffer_with_null_view", getbuffer_with_null_view, METH_O}, {"PyBuffer_SizeFromFormat", test_PyBuffer_SizeFromFormat, METH_VARARGS}, {"test_buildvalue_N", test_buildvalue_N, METH_NOARGS}, + {"test_buildvalue_issue38913", test_buildvalue_issue38913, METH_NOARGS}, {"get_args", get_args, METH_VARARGS}, {"get_kwargs", (PyCFunction)(void(*)(void))get_kwargs, METH_VARARGS|METH_KEYWORDS}, {"getargs_tuple", getargs_tuple, METH_VARARGS}, @@ -6791,3 +6795,42 @@ PyInit__testcapi(void) PyState_AddModule(m, &_testcapimodule); return m; } + + +/* Test the C API exposed when PY_SSIZE_T_CLEAN is not defined */ + +#undef Py_BuildValue +PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...); + +static PyObject * +test_buildvalue_issue38913(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *res; + const char str[] = "string"; + const Py_UNICODE unicode[] = L"unicode"; + PyErr_SetNone(PyExc_ZeroDivisionError); + + res = Py_BuildValue("(s#O)", str, 1, Py_None); + assert(res == NULL); + if (!PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) { + return NULL; + } + res = Py_BuildValue("(z#O)", str, 1, Py_None); + assert(res == NULL); + if (!PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) { + return NULL; + } + res = Py_BuildValue("(y#O)", str, 1, Py_None); + assert(res == NULL); + if (!PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) { + return NULL; + } + res = Py_BuildValue("(u#O)", unicode, 1, Py_None); + assert(res == NULL); + if (!PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) { + return NULL; + } + + PyErr_Clear(); + Py_RETURN_NONE; +} diff --git a/Python/modsupport.c b/Python/modsupport.c index 6255822..7271af3 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -343,11 +343,11 @@ do_mkvalue(const char **p_format, va_list *p_va, int flags) if (flags & FLAG_SIZE_T) n = va_arg(*p_va, Py_ssize_t); else { + n = va_arg(*p_va, int); if (PyErr_WarnEx(PyExc_DeprecationWarning, "PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) { return NULL; } - n = va_arg(*p_va, int); } } else @@ -396,11 +396,11 @@ do_mkvalue(const char **p_format, va_list *p_va, int flags) if (flags & FLAG_SIZE_T) n = va_arg(*p_va, Py_ssize_t); else { + n = va_arg(*p_va, int); if (PyErr_WarnEx(PyExc_DeprecationWarning, "PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) { return NULL; } - n = va_arg(*p_va, int); } } else @@ -434,11 +434,11 @@ do_mkvalue(const char **p_format, va_list *p_va, int flags) if (flags & FLAG_SIZE_T) n = va_arg(*p_va, Py_ssize_t); else { + n = va_arg(*p_va, int); if (PyErr_WarnEx(PyExc_DeprecationWarning, "PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) { return NULL; } - n = va_arg(*p_va, int); } } else -- cgit v0.12