mirror of https://github.com/python/cpython
gh-68114: Fix handling for removed PyArg_ParseTuple 'w' formatters (GH-8204)
Co-authored-by: Joe Jevnik <joe@quantopian.com> Co-authored-by: Petr Viktorin <encukou@gmail.com>
This commit is contained in:
parent
e17cd1fbfd
commit
eb927e9fc8
|
@ -856,20 +856,24 @@ class Bytes_TestCase(unittest.TestCase):
|
||||||
|
|
||||||
def test_w_star(self):
|
def test_w_star(self):
|
||||||
# getargs_w_star() modifies first and last byte
|
# getargs_w_star() modifies first and last byte
|
||||||
from _testcapi import getargs_w_star
|
# getargs_w_star_opt() takes additional optional args: with one
|
||||||
self.assertRaises(TypeError, getargs_w_star, 'abc\xe9')
|
# argument it should behave the same as getargs_w_star
|
||||||
self.assertRaises(TypeError, getargs_w_star, b'bytes')
|
from _testcapi import getargs_w_star, getargs_w_star_opt
|
||||||
self.assertRaises(TypeError, getargs_w_star, b'nul:\0')
|
for func in (getargs_w_star, getargs_w_star_opt):
|
||||||
self.assertRaises(TypeError, getargs_w_star, memoryview(b'bytes'))
|
with self.subTest(func=func):
|
||||||
|
self.assertRaises(TypeError, func, 'abc\xe9')
|
||||||
|
self.assertRaises(TypeError, func, b'bytes')
|
||||||
|
self.assertRaises(TypeError, func, b'nul:\0')
|
||||||
|
self.assertRaises(TypeError, func, memoryview(b'bytes'))
|
||||||
buf = bytearray(b'bytearray')
|
buf = bytearray(b'bytearray')
|
||||||
self.assertEqual(getargs_w_star(buf), b'[ytearra]')
|
self.assertEqual(func(buf), b'[ytearra]')
|
||||||
self.assertEqual(buf, bytearray(b'[ytearra]'))
|
self.assertEqual(buf, bytearray(b'[ytearra]'))
|
||||||
buf = bytearray(b'memoryview')
|
buf = bytearray(b'memoryview')
|
||||||
self.assertEqual(getargs_w_star(memoryview(buf)), b'[emoryvie]')
|
self.assertEqual(func(memoryview(buf)), b'[emoryvie]')
|
||||||
self.assertEqual(buf, bytearray(b'[emoryvie]'))
|
self.assertEqual(buf, bytearray(b'[emoryvie]'))
|
||||||
self.assertRaises(TypeError, getargs_w_star, None)
|
self.assertRaises(TypeError, func, None)
|
||||||
self.assertRaises(TypeError, getargs_w_star, NONCONTIG_WRITABLE)
|
self.assertRaises(TypeError, func, NONCONTIG_WRITABLE)
|
||||||
self.assertRaises(TypeError, getargs_w_star, NONCONTIG_READONLY)
|
self.assertRaises(TypeError, func, NONCONTIG_READONLY)
|
||||||
|
|
||||||
def test_getargs_empty(self):
|
def test_getargs_empty(self):
|
||||||
from _testcapi import getargs_empty
|
from _testcapi import getargs_empty
|
||||||
|
@ -1112,9 +1116,9 @@ class SkipitemTest(unittest.TestCase):
|
||||||
c = chr(i)
|
c = chr(i)
|
||||||
|
|
||||||
# skip parentheses, the error reporting is inconsistent about them
|
# skip parentheses, the error reporting is inconsistent about them
|
||||||
# skip 'e', it's always a two-character code
|
# skip 'e' and 'w', they're always two-character codes
|
||||||
# skip '|' and '$', they don't represent arguments anyway
|
# skip '|' and '$', they don't represent arguments anyway
|
||||||
if c in '()e|$':
|
if c in '()ew|$':
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# test the format unit when not skipped
|
# test the format unit when not skipped
|
||||||
|
@ -1152,7 +1156,7 @@ class SkipitemTest(unittest.TestCase):
|
||||||
dict_b = {'b':1}
|
dict_b = {'b':1}
|
||||||
keywords = ["a", "b"]
|
keywords = ["a", "b"]
|
||||||
|
|
||||||
supported = ('s#', 's*', 'z#', 'z*', 'y#', 'y*', 'w#', 'w*')
|
supported = ('s#', 's*', 'z#', 'z*', 'y#', 'y*', 'w*')
|
||||||
for c in string.ascii_letters:
|
for c in string.ascii_letters:
|
||||||
for c2 in '#*':
|
for c2 in '#*':
|
||||||
f = c + c2
|
f = c + c2
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fixed skipitem()'s handling of the old 'w' and 'w#' formatters. These are
|
||||||
|
no longer supported and now raise an exception if used.
|
|
@ -141,6 +141,122 @@ getargs_w_star(PyObject *self, PyObject *args)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
getargs_w_star_opt(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
Py_buffer buffer;
|
||||||
|
Py_buffer buf2;
|
||||||
|
int number = 1;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "w*|w*i:getargs_w_star",
|
||||||
|
&buffer, &buf2, &number)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (2 <= buffer.len) {
|
||||||
|
char *str = buffer.buf;
|
||||||
|
str[0] = '[';
|
||||||
|
str[buffer.len-1] = ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *result = PyBytes_FromStringAndSize(buffer.buf, buffer.len);
|
||||||
|
PyBuffer_Release(&buffer);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test the old w and w# codes that no longer work */
|
||||||
|
static PyObject *
|
||||||
|
test_w_code_invalid(PyObject *self, PyObject *arg)
|
||||||
|
{
|
||||||
|
static const char * const keywords[] = {"a", "b", "c", "d", NULL};
|
||||||
|
char *formats_3[] = {"O|w#$O",
|
||||||
|
"O|w$O",
|
||||||
|
"O|w#O",
|
||||||
|
"O|wO",
|
||||||
|
NULL};
|
||||||
|
char *formats_4[] = {"O|w#O$O",
|
||||||
|
"O|wO$O",
|
||||||
|
"O|Ow#O",
|
||||||
|
"O|OwO",
|
||||||
|
"O|Ow#$O",
|
||||||
|
"O|Ow$O",
|
||||||
|
NULL};
|
||||||
|
size_t n;
|
||||||
|
PyObject *args;
|
||||||
|
PyObject *kwargs;
|
||||||
|
PyObject *tmp;
|
||||||
|
|
||||||
|
if (!(args = PyTuple_Pack(1, Py_None))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
kwargs = PyDict_New();
|
||||||
|
if (!kwargs) {
|
||||||
|
Py_DECREF(args);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyDict_SetItemString(kwargs, "c", Py_None)) {
|
||||||
|
Py_DECREF(args);
|
||||||
|
Py_XDECREF(kwargs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n = 0; formats_3[n]; ++n) {
|
||||||
|
if (PyArg_ParseTupleAndKeywords(args, kwargs, formats_3[n],
|
||||||
|
(char**) keywords,
|
||||||
|
&tmp, &tmp, &tmp)) {
|
||||||
|
Py_DECREF(args);
|
||||||
|
Py_DECREF(kwargs);
|
||||||
|
PyErr_Format(PyExc_AssertionError,
|
||||||
|
"test_w_code_invalid_suffix: %s",
|
||||||
|
formats_3[n]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!PyErr_ExceptionMatches(PyExc_SystemError)) {
|
||||||
|
Py_DECREF(args);
|
||||||
|
Py_DECREF(kwargs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyDict_DelItemString(kwargs, "c") ||
|
||||||
|
PyDict_SetItemString(kwargs, "d", Py_None)) {
|
||||||
|
|
||||||
|
Py_DECREF(kwargs);
|
||||||
|
Py_DECREF(args);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n = 0; formats_4[n]; ++n) {
|
||||||
|
if (PyArg_ParseTupleAndKeywords(args, kwargs, formats_4[n],
|
||||||
|
(char**) keywords,
|
||||||
|
&tmp, &tmp, &tmp, &tmp)) {
|
||||||
|
Py_DECREF(args);
|
||||||
|
Py_DECREF(kwargs);
|
||||||
|
PyErr_Format(PyExc_AssertionError,
|
||||||
|
"test_w_code_invalid_suffix: %s",
|
||||||
|
formats_4[n]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!PyErr_ExceptionMatches(PyExc_SystemError)) {
|
||||||
|
Py_DECREF(args);
|
||||||
|
Py_DECREF(kwargs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_DECREF(args);
|
||||||
|
Py_DECREF(kwargs);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
getargs_empty(PyObject *self, PyObject *args, PyObject *kwargs)
|
getargs_empty(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
|
@ -684,6 +800,7 @@ static PyMethodDef test_methods[] = {
|
||||||
{"getargs_s_star", getargs_s_star, METH_VARARGS},
|
{"getargs_s_star", getargs_s_star, METH_VARARGS},
|
||||||
{"getargs_tuple", getargs_tuple, METH_VARARGS},
|
{"getargs_tuple", getargs_tuple, METH_VARARGS},
|
||||||
{"getargs_w_star", getargs_w_star, METH_VARARGS},
|
{"getargs_w_star", getargs_w_star, METH_VARARGS},
|
||||||
|
{"getargs_w_star_opt", getargs_w_star_opt, METH_VARARGS},
|
||||||
{"getargs_empty", _PyCFunction_CAST(getargs_empty), METH_VARARGS|METH_KEYWORDS},
|
{"getargs_empty", _PyCFunction_CAST(getargs_empty), METH_VARARGS|METH_KEYWORDS},
|
||||||
{"getargs_y", getargs_y, METH_VARARGS},
|
{"getargs_y", getargs_y, METH_VARARGS},
|
||||||
{"getargs_y_hash", getargs_y_hash, METH_VARARGS},
|
{"getargs_y_hash", getargs_y_hash, METH_VARARGS},
|
||||||
|
@ -693,6 +810,7 @@ static PyMethodDef test_methods[] = {
|
||||||
{"getargs_z_star", getargs_z_star, METH_VARARGS},
|
{"getargs_z_star", getargs_z_star, METH_VARARGS},
|
||||||
{"parse_tuple_and_keywords", parse_tuple_and_keywords, METH_VARARGS},
|
{"parse_tuple_and_keywords", parse_tuple_and_keywords, METH_VARARGS},
|
||||||
{"gh_99240_clear_args", gh_99240_clear_args, METH_VARARGS},
|
{"gh_99240_clear_args", gh_99240_clear_args, METH_VARARGS},
|
||||||
|
{"test_w_code_invalid", test_w_code_invalid, METH_NOARGS},
|
||||||
{NULL},
|
{NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2641,6 +2641,11 @@ skipitem(const char **p_format, va_list *p_va, int flags)
|
||||||
if (p_va != NULL) {
|
if (p_va != NULL) {
|
||||||
(void) va_arg(*p_va, char **);
|
(void) va_arg(*p_va, char **);
|
||||||
}
|
}
|
||||||
|
if (c == 'w' && *format != '*')
|
||||||
|
{
|
||||||
|
/* after 'w', only '*' is allowed */
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
if (*format == '#') {
|
if (*format == '#') {
|
||||||
if (p_va != NULL) {
|
if (p_va != NULL) {
|
||||||
(void) va_arg(*p_va, Py_ssize_t *);
|
(void) va_arg(*p_va, Py_ssize_t *);
|
||||||
|
|
Loading…
Reference in New Issue