Skip to content

Commit 31a390e

Browse files
[3.10] gh-94930: skipitem() in getargs.c should return non-NULL on error (GH-94931) (GH-94963)
(cherry picked from commit 067f0da) Co-authored-by: Serhiy Storchaka <[email protected]>
1 parent 374afb4 commit 31a390e

File tree

4 files changed

+37
-8
lines changed

4 files changed

+37
-8
lines changed

Lib/test/test_getargs2.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -878,9 +878,19 @@ def test_s_hash(self):
878878
def test_s_hash_int(self):
879879
# "s#" without PY_SSIZE_T_CLEAN defined.
880880
from _testcapi import getargs_s_hash_int
881-
self.assertRaises(SystemError, getargs_s_hash_int, "abc")
882-
self.assertRaises(SystemError, getargs_s_hash_int, x=42)
883-
# getargs_s_hash_int() don't raise SystemError because skipitem() is not called.
881+
from _testcapi import getargs_s_hash_int2
882+
buf = bytearray([1, 2])
883+
self.assertRaises(SystemError, getargs_s_hash_int, buf, "abc")
884+
self.assertRaises(SystemError, getargs_s_hash_int, buf, x=42)
885+
self.assertRaises(SystemError, getargs_s_hash_int, buf, x="abc")
886+
self.assertRaises(SystemError, getargs_s_hash_int2, buf, ("abc",))
887+
self.assertRaises(SystemError, getargs_s_hash_int2, buf, x=42)
888+
self.assertRaises(SystemError, getargs_s_hash_int2, buf, x="abc")
889+
buf.append(3) # still mutable -- not locked by a buffer export
890+
# getargs_s_hash_int(buf) may not raise SystemError because skipitem()
891+
# is not called. But it is an implementation detail.
892+
# getargs_s_hash_int(buf)
893+
# getargs_s_hash_int2(buf)
884894

885895
def test_z(self):
886896
from _testcapi import getargs_z
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix ``SystemError`` raised when :c:func:`PyArg_ParseTupleAndKeywords` is
2+
used with ``#`` in ``(...)`` but without ``PY_SSIZE_T_CLEAN`` defined.

Modules/_testcapimodule.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5634,6 +5634,7 @@ test_fatal_error(PyObject *self, PyObject *args)
56345634

56355635
static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
56365636
static PyObject *getargs_s_hash_int(PyObject *, PyObject *, PyObject*);
5637+
static PyObject *getargs_s_hash_int2(PyObject *, PyObject *, PyObject*);
56375638

56385639
static PyMethodDef TestMethods[] = {
56395640
{"raise_exception", raise_exception, METH_VARARGS},
@@ -5745,6 +5746,8 @@ static PyMethodDef TestMethods[] = {
57455746
{"getargs_s_hash", getargs_s_hash, METH_VARARGS},
57465747
{"getargs_s_hash_int", (PyCFunction)(void(*)(void))getargs_s_hash_int,
57475748
METH_VARARGS|METH_KEYWORDS},
5749+
{"getargs_s_hash_int2", (PyCFunction)(void(*)(void))getargs_s_hash_int2,
5750+
METH_VARARGS|METH_KEYWORDS},
57485751
{"getargs_z", getargs_z, METH_VARARGS},
57495752
{"getargs_z_star", getargs_z_star, METH_VARARGS},
57505753
{"getargs_z_hash", getargs_z_hash, METH_VARARGS},
@@ -7435,11 +7438,27 @@ PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
74357438
static PyObject *
74367439
getargs_s_hash_int(PyObject *self, PyObject *args, PyObject *kwargs)
74377440
{
7438-
static char *keywords[] = {"", "x", NULL};
7441+
static char *keywords[] = {"", "", "x", NULL};
7442+
Py_buffer buf = {NULL};
7443+
const char *s;
7444+
int len;
7445+
int i = 0;
7446+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "w*|s#i", keywords, &buf, &s, &len, &i))
7447+
return NULL;
7448+
PyBuffer_Release(&buf);
7449+
Py_RETURN_NONE;
7450+
}
7451+
7452+
static PyObject *
7453+
getargs_s_hash_int2(PyObject *self, PyObject *args, PyObject *kwargs)
7454+
{
7455+
static char *keywords[] = {"", "", "x", NULL};
7456+
Py_buffer buf = {NULL};
74397457
const char *s;
74407458
int len;
74417459
int i = 0;
7442-
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s#i", keywords, &s, &len, &i))
7460+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "w*|(s#)i", keywords, &buf, &s, &len, &i))
74437461
return NULL;
7462+
PyBuffer_Release(&buf);
74447463
Py_RETURN_NONE;
74457464
}

Python/getargs.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,9 +2533,7 @@ skipitem(const char **p_format, va_list *p_va, int flags)
25332533
if (*format == '#') {
25342534
if (p_va != NULL) {
25352535
if (!(flags & FLAG_SIZE_T)) {
2536-
PyErr_SetString(PyExc_SystemError,
2537-
"PY_SSIZE_T_CLEAN macro must be defined for '#' formats");
2538-
return NULL;
2536+
return "PY_SSIZE_T_CLEAN macro must be defined for '#' formats";
25392537
}
25402538
(void) va_arg(*p_va, Py_ssize_t *);
25412539
}

0 commit comments

Comments
 (0)