Skip to content

Commit 28d0bca

Browse files
bpo-38913: Fix segfault in Py_BuildValue("(s#O)", ...) if entered with exception raised. (GH-18656)
1 parent 2565ede commit 28d0bca

File tree

3 files changed

+48
-3
lines changed

3 files changed

+48
-3
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed segfault in ``Py_BuildValue()`` called with a format containing "#"
2+
and undefined PY_SSIZE_T_CLEAN whwn an exception is set.

Modules/_testcapimodule.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5258,6 +5258,9 @@ meth_fastcall_keywords(PyObject* self, PyObject* const* args,
52585258
return Py_BuildValue("NNN", _null_to_none(self), pyargs, pykwargs);
52595259
}
52605260

5261+
5262+
static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
5263+
52615264
static PyMethodDef TestMethods[] = {
52625265
{"raise_exception", raise_exception, METH_VARARGS},
52635266
{"raise_memoryerror", raise_memoryerror, METH_NOARGS},
@@ -5322,6 +5325,7 @@ static PyMethodDef TestMethods[] = {
53225325
{"getbuffer_with_null_view", getbuffer_with_null_view, METH_O},
53235326
{"PyBuffer_SizeFromFormat", test_PyBuffer_SizeFromFormat, METH_VARARGS},
53245327
{"test_buildvalue_N", test_buildvalue_N, METH_NOARGS},
5328+
{"test_buildvalue_issue38913", test_buildvalue_issue38913, METH_NOARGS},
53255329
{"get_args", get_args, METH_VARARGS},
53265330
{"get_kwargs", (PyCFunction)(void(*)(void))get_kwargs, METH_VARARGS|METH_KEYWORDS},
53275331
{"getargs_tuple", getargs_tuple, METH_VARARGS},
@@ -6791,3 +6795,42 @@ PyInit__testcapi(void)
67916795
PyState_AddModule(m, &_testcapimodule);
67926796
return m;
67936797
}
6798+
6799+
6800+
/* Test the C API exposed when PY_SSIZE_T_CLEAN is not defined */
6801+
6802+
#undef Py_BuildValue
6803+
PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...);
6804+
6805+
static PyObject *
6806+
test_buildvalue_issue38913(PyObject *self, PyObject *Py_UNUSED(ignored))
6807+
{
6808+
PyObject *res;
6809+
const char str[] = "string";
6810+
const Py_UNICODE unicode[] = L"unicode";
6811+
PyErr_SetNone(PyExc_ZeroDivisionError);
6812+
6813+
res = Py_BuildValue("(s#O)", str, 1, Py_None);
6814+
assert(res == NULL);
6815+
if (!PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) {
6816+
return NULL;
6817+
}
6818+
res = Py_BuildValue("(z#O)", str, 1, Py_None);
6819+
assert(res == NULL);
6820+
if (!PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) {
6821+
return NULL;
6822+
}
6823+
res = Py_BuildValue("(y#O)", str, 1, Py_None);
6824+
assert(res == NULL);
6825+
if (!PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) {
6826+
return NULL;
6827+
}
6828+
res = Py_BuildValue("(u#O)", unicode, 1, Py_None);
6829+
assert(res == NULL);
6830+
if (!PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) {
6831+
return NULL;
6832+
}
6833+
6834+
PyErr_Clear();
6835+
Py_RETURN_NONE;
6836+
}

Python/modsupport.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -343,11 +343,11 @@ do_mkvalue(const char **p_format, va_list *p_va, int flags)
343343
if (flags & FLAG_SIZE_T)
344344
n = va_arg(*p_va, Py_ssize_t);
345345
else {
346+
n = va_arg(*p_va, int);
346347
if (PyErr_WarnEx(PyExc_DeprecationWarning,
347348
"PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) {
348349
return NULL;
349350
}
350-
n = va_arg(*p_va, int);
351351
}
352352
}
353353
else
@@ -396,11 +396,11 @@ do_mkvalue(const char **p_format, va_list *p_va, int flags)
396396
if (flags & FLAG_SIZE_T)
397397
n = va_arg(*p_va, Py_ssize_t);
398398
else {
399+
n = va_arg(*p_va, int);
399400
if (PyErr_WarnEx(PyExc_DeprecationWarning,
400401
"PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) {
401402
return NULL;
402403
}
403-
n = va_arg(*p_va, int);
404404
}
405405
}
406406
else
@@ -434,11 +434,11 @@ do_mkvalue(const char **p_format, va_list *p_va, int flags)
434434
if (flags & FLAG_SIZE_T)
435435
n = va_arg(*p_va, Py_ssize_t);
436436
else {
437+
n = va_arg(*p_va, int);
437438
if (PyErr_WarnEx(PyExc_DeprecationWarning,
438439
"PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) {
439440
return NULL;
440441
}
441-
n = va_arg(*p_va, int);
442442
}
443443
}
444444
else

0 commit comments

Comments
 (0)