mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-50333: Deprecate support of non-tuple sequences in PyArg_ParseTuple() (GH-128374)
Non-tuple sequences are deprecated as argument for the "(items)" format unit in PyArg_ParseTuple() and other argument parsing functions if items contains format units which store borrowed buffer or reference (e.g. "s" and "O"). str and bytearray are no longer accepted as valid sequences.
This commit is contained in:
parent
0f04f2456a
commit
0e4cf9ce7c
5 changed files with 150 additions and 29 deletions
|
@ -466,6 +466,8 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
|
|||
const char *format = *p_format;
|
||||
int i;
|
||||
Py_ssize_t len;
|
||||
int istuple = PyTuple_Check(arg);
|
||||
int mustbetuple = istuple;
|
||||
|
||||
for (;;) {
|
||||
int c = *format++;
|
||||
|
@ -481,51 +483,104 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
|
|||
}
|
||||
else if (c == ':' || c == ';' || c == '\0')
|
||||
break;
|
||||
else if (level == 0 && Py_ISALPHA(c) && c != 'e')
|
||||
n++;
|
||||
else {
|
||||
if (level == 0 && Py_ISALPHA(c)) {
|
||||
n++;
|
||||
}
|
||||
if (c == 'e' && (*format == 's' || *format == 't')) {
|
||||
format++;
|
||||
continue;
|
||||
}
|
||||
if (!mustbetuple) {
|
||||
switch (c) {
|
||||
case 'y':
|
||||
case 's':
|
||||
case 'z':
|
||||
if (*format != '*') {
|
||||
mustbetuple = 1;
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
case 'Y':
|
||||
case 'U':
|
||||
mustbetuple = 1;
|
||||
break;
|
||||
case 'O':
|
||||
if (*format != '&') {
|
||||
mustbetuple = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!PySequence_Check(arg) || PyBytes_Check(arg)) {
|
||||
if (istuple) {
|
||||
/* fallthrough */
|
||||
}
|
||||
else if (!PySequence_Check(arg) ||
|
||||
PyUnicode_Check(arg) || PyBytes_Check(arg) || PyByteArray_Check(arg))
|
||||
{
|
||||
levels[0] = 0;
|
||||
PyOS_snprintf(msgbuf, bufsize,
|
||||
"must be %d-item sequence, not %.50s",
|
||||
"must be %d-item tuple, not %.50s",
|
||||
n,
|
||||
arg == Py_None ? "None" : Py_TYPE(arg)->tp_name);
|
||||
return msgbuf;
|
||||
}
|
||||
else {
|
||||
if (mustbetuple) {
|
||||
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 0,
|
||||
"argument must be %d-item tuple, not %T", n, arg))
|
||||
{
|
||||
return msgbuf;
|
||||
}
|
||||
}
|
||||
len = PySequence_Size(arg);
|
||||
if (len != n) {
|
||||
levels[0] = 0;
|
||||
PyOS_snprintf(msgbuf, bufsize,
|
||||
"must be %s of length %d, not %zd",
|
||||
mustbetuple ? "tuple" : "sequence", n, len);
|
||||
return msgbuf;
|
||||
}
|
||||
arg = PySequence_Tuple(arg);
|
||||
if (arg == NULL) {
|
||||
return msgbuf;
|
||||
}
|
||||
}
|
||||
|
||||
len = PySequence_Size(arg);
|
||||
len = PyTuple_GET_SIZE(arg);
|
||||
if (len != n) {
|
||||
levels[0] = 0;
|
||||
PyOS_snprintf(msgbuf, bufsize,
|
||||
"must be sequence of length %d, not %zd",
|
||||
"must be tuple of length %d, not %zd",
|
||||
n, len);
|
||||
if (!istuple) {
|
||||
Py_DECREF(arg);
|
||||
}
|
||||
return msgbuf;
|
||||
}
|
||||
|
||||
format = *p_format;
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *msg;
|
||||
PyObject *item;
|
||||
item = PySequence_GetItem(arg, i);
|
||||
if (item == NULL) {
|
||||
PyErr_Clear();
|
||||
levels[0] = i+1;
|
||||
levels[1] = 0;
|
||||
strncpy(msgbuf, "is not retrievable", bufsize);
|
||||
return msgbuf;
|
||||
}
|
||||
PyObject *item = PyTuple_GET_ITEM(arg, i);
|
||||
msg = convertitem(item, &format, p_va, flags, levels+1,
|
||||
msgbuf, bufsize, freelist);
|
||||
/* PySequence_GetItem calls tp->sq_item, which INCREFs */
|
||||
Py_XDECREF(item);
|
||||
if (msg != NULL) {
|
||||
levels[0] = i+1;
|
||||
if (!istuple) {
|
||||
Py_DECREF(arg);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
*p_format = format;
|
||||
if (!istuple) {
|
||||
Py_DECREF(arg);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue