Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 06e49dd

Browse files
author
Victor Stinner
committed
Issue #8592: PyArg_Parse*() functions raise a TypeError for "y", "u" and "Z"
formats if the string contains a null byte/character. Write unit tests for string formats.
1 parent edc5d20 commit 06e49dd

5 files changed

Lines changed: 317 additions & 5 deletions

File tree

Doc/c-api/arg.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ Unless otherwise stated, buffers are not NUL-terminated.
125125
pointer variable, which will be filled with the pointer to an existing
126126
Unicode buffer. Please note that the width of a :ctype:`Py_UNICODE`
127127
character depends on compilation options (it is either 16 or 32 bits).
128+
The Python string must not contain embedded NUL characters; if it does,
129+
a :exc:`TypeError` exception is raised.
128130

129131
.. note::
130132
Since ``u`` doesn't give you back the length of the string, and it

Lib/test/test_getargs2.py

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,136 @@ def test_surrogate_keyword(self):
293293
else:
294294
self.fail('TypeError should have been raised')
295295

296+
class Bytes_TestCase(unittest.TestCase):
297+
def test_s(self):
298+
from _testcapi import getargs_s
299+
self.assertEqual(getargs_s('abc\xe9'), b'abc\xc3\xa9')
300+
self.assertRaises(TypeError, getargs_s, 'nul:\0')
301+
self.assertRaises(TypeError, getargs_s, b'bytes')
302+
self.assertRaises(TypeError, getargs_s, bytearray(b'bytearray'))
303+
self.assertRaises(TypeError, getargs_s, memoryview(b'memoryview'))
304+
self.assertRaises(TypeError, getargs_s, None)
305+
306+
def test_s_star(self):
307+
from _testcapi import getargs_s_star
308+
self.assertEqual(getargs_s_star('abc\xe9'), b'abc\xc3\xa9')
309+
self.assertEqual(getargs_s_star('nul:\0'), b'nul:\0')
310+
self.assertEqual(getargs_s_star(b'bytes'), b'bytes')
311+
self.assertEqual(getargs_s_star(bytearray(b'bytearray')), b'bytearray')
312+
self.assertEqual(getargs_s_star(memoryview(b'memoryview')), b'memoryview')
313+
self.assertRaises(TypeError, getargs_s_star, None)
314+
315+
def test_s_hash(self):
316+
from _testcapi import getargs_s_hash
317+
self.assertEqual(getargs_s_hash('abc\xe9'), b'abc\xc3\xa9')
318+
self.assertEqual(getargs_s_hash('nul:\0'), b'nul:\0')
319+
self.assertEqual(getargs_s_hash(b'bytes'), b'bytes')
320+
self.assertRaises(TypeError, getargs_s_hash, bytearray(b'bytearray'))
321+
self.assertRaises(TypeError, getargs_s_hash, memoryview(b'memoryview'))
322+
self.assertRaises(TypeError, getargs_s_hash, None)
323+
324+
def test_z(self):
325+
from _testcapi import getargs_z
326+
self.assertEqual(getargs_z('abc\xe9'), b'abc\xc3\xa9')
327+
self.assertRaises(TypeError, getargs_z, 'nul:\0')
328+
self.assertEqual(getargs_z(b'bytes'), b'bytes')
329+
self.assertRaises(TypeError, getargs_z, bytearray(b'bytearray'))
330+
self.assertRaises(TypeError, getargs_z, memoryview(b'memoryview'))
331+
self.assertIsNone(getargs_z(None))
332+
333+
def test_z_star(self):
334+
from _testcapi import getargs_z_star
335+
self.assertEqual(getargs_z_star('abc\xe9'), b'abc\xc3\xa9')
336+
self.assertEqual(getargs_z_star('nul:\0'), b'nul:\0')
337+
self.assertEqual(getargs_z_star(b'bytes'), b'bytes')
338+
self.assertEqual(getargs_z_star(bytearray(b'bytearray')), b'bytearray')
339+
self.assertEqual(getargs_z_star(memoryview(b'memoryview')), b'memoryview')
340+
self.assertIsNone(getargs_z_star(None))
341+
342+
def test_z_hash(self):
343+
from _testcapi import getargs_z_hash
344+
self.assertEqual(getargs_z_hash('abc\xe9'), b'abc\xc3\xa9')
345+
self.assertEqual(getargs_z_hash('nul:\0'), b'nul:\0')
346+
self.assertEqual(getargs_z_hash(b'bytes'), b'bytes')
347+
self.assertRaises(TypeError, getargs_z_hash, bytearray(b'bytearray'))
348+
self.assertRaises(TypeError, getargs_z_hash, memoryview(b'memoryview'))
349+
self.assertIsNone(getargs_z_hash(None))
350+
351+
def test_y(self):
352+
from _testcapi import getargs_y
353+
self.assertRaises(TypeError, getargs_y, 'abc\xe9')
354+
self.assertEqual(getargs_y(b'bytes'), b'bytes')
355+
self.assertRaises(TypeError, getargs_y, b'nul:\0')
356+
self.assertRaises(TypeError, getargs_y, bytearray(b'bytearray'))
357+
self.assertRaises(TypeError, getargs_y, memoryview(b'memoryview'))
358+
self.assertRaises(TypeError, getargs_y, None)
359+
360+
def test_y_star(self):
361+
from _testcapi import getargs_y_star
362+
self.assertRaises(TypeError, getargs_y_star, 'abc\xe9')
363+
self.assertEqual(getargs_y_star(b'bytes'), b'bytes')
364+
self.assertEqual(getargs_y_star(b'nul:\0'), b'nul:\0')
365+
self.assertEqual(getargs_y_star(bytearray(b'bytearray')), b'bytearray')
366+
self.assertEqual(getargs_y_star(memoryview(b'memoryview')), b'memoryview')
367+
self.assertRaises(TypeError, getargs_y_star, None)
368+
369+
def test_y_hash(self):
370+
from _testcapi import getargs_y_hash
371+
self.assertRaises(TypeError, getargs_y_hash, 'abc\xe9')
372+
self.assertEqual(getargs_y_hash(b'bytes'), b'bytes')
373+
self.assertEqual(getargs_y_hash(b'nul:\0'), b'nul:\0')
374+
self.assertRaises(TypeError, getargs_y_hash, bytearray(b'bytearray'))
375+
self.assertRaises(TypeError, getargs_y_hash, memoryview(b'memoryview'))
376+
self.assertRaises(TypeError, getargs_y_hash, None)
377+
378+
379+
class Unicode_TestCase(unittest.TestCase):
380+
def test_u(self):
381+
from _testcapi import getargs_u
382+
self.assertEqual(getargs_u('abc\xe9'), 'abc\xe9')
383+
self.assertRaises(TypeError, getargs_u, 'nul:\0')
384+
self.assertRaises(TypeError, getargs_u, b'bytes')
385+
self.assertRaises(TypeError, getargs_u, bytearray(b'bytearray'))
386+
self.assertRaises(TypeError, getargs_u, memoryview(b'memoryview'))
387+
self.assertRaises(TypeError, getargs_u, None)
388+
389+
def test_u_hash(self):
390+
from _testcapi import getargs_u_hash
391+
self.assertEqual(getargs_u_hash('abc\xe9'), 'abc\xe9')
392+
self.assertEqual(getargs_u_hash('nul:\0'), 'nul:\0')
393+
self.assertRaises(TypeError, getargs_u_hash, b'bytes')
394+
self.assertRaises(TypeError, getargs_u_hash, bytearray(b'bytearray'))
395+
self.assertRaises(TypeError, getargs_u_hash, memoryview(b'memoryview'))
396+
self.assertRaises(TypeError, getargs_u_hash, None)
397+
398+
def test_Z(self):
399+
from _testcapi import getargs_Z
400+
self.assertEqual(getargs_Z('abc\xe9'), 'abc\xe9')
401+
self.assertRaises(TypeError, getargs_Z, 'nul:\0')
402+
self.assertRaises(TypeError, getargs_Z, b'bytes')
403+
self.assertRaises(TypeError, getargs_Z, bytearray(b'bytearray'))
404+
self.assertRaises(TypeError, getargs_Z, memoryview(b'memoryview'))
405+
self.assertIsNone(getargs_Z(None))
406+
407+
def test_Z_hash(self):
408+
from _testcapi import getargs_Z_hash
409+
self.assertEqual(getargs_Z_hash('abc\xe9'), 'abc\xe9')
410+
self.assertEqual(getargs_Z_hash('nul:\0'), 'nul:\0')
411+
self.assertRaises(TypeError, getargs_Z_hash, b'bytes')
412+
self.assertRaises(TypeError, getargs_Z_hash, bytearray(b'bytearray'))
413+
self.assertRaises(TypeError, getargs_Z_hash, memoryview(b'memoryview'))
414+
self.assertIsNone(getargs_Z_hash(None))
415+
416+
296417
def test_main():
297-
tests = [Signed_TestCase, Unsigned_TestCase, Tuple_TestCase, Keywords_TestCase]
418+
tests = [
419+
Signed_TestCase,
420+
Unsigned_TestCase,
421+
Tuple_TestCase,
422+
Keywords_TestCase,
423+
Bytes_TestCase,
424+
Unicode_TestCase,
425+
]
298426
try:
299427
from _testcapi import getargs_L, getargs_K
300428
except ImportError:

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ What's New in Python 3.2 Alpha 1?
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #8592: PyArg_Parse*() functions raise a TypeError for "y", "u" and "Z"
16+
formats if the string contains a null byte/character. Write unit tests for
17+
string formats.
18+
1519
- Issue #7490: to facilitate sharing of doctests between 2.x and 3.x test
1620
suites, the IGNORE_EXCEPTION_DETAIL directive now also ignores the module
1721
location of the raised exception.

Modules/_testcapimodule.c

Lines changed: 165 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1011,6 +1011,157 @@ test_k_code(PyObject *self)
10111011
return Py_None;
10121012
}
10131013

1014+
static PyObject *
1015+
getargs_s(PyObject *self, PyObject *args)
1016+
{
1017+
char *str;
1018+
if (!PyArg_ParseTuple(args, "s", &str))
1019+
return NULL;
1020+
return PyBytes_FromString(str);
1021+
}
1022+
1023+
static PyObject *
1024+
getargs_s_star(PyObject *self, PyObject *args)
1025+
{
1026+
Py_buffer buffer;
1027+
PyObject *bytes;
1028+
if (!PyArg_ParseTuple(args, "s*", &buffer))
1029+
return NULL;
1030+
bytes = PyBytes_FromStringAndSize(buffer.buf, buffer.len);
1031+
PyBuffer_Release(&buffer);
1032+
return bytes;
1033+
}
1034+
1035+
static PyObject *
1036+
getargs_s_hash(PyObject *self, PyObject *args)
1037+
{
1038+
char *str;
1039+
Py_ssize_t size;
1040+
if (!PyArg_ParseTuple(args, "s#", &str, &size))
1041+
return NULL;
1042+
return PyBytes_FromStringAndSize(str, size);
1043+
}
1044+
1045+
static PyObject *
1046+
getargs_z(PyObject *self, PyObject *args)
1047+
{
1048+
char *str;
1049+
if (!PyArg_ParseTuple(args, "z", &str))
1050+
return NULL;
1051+
if (str != NULL)
1052+
return PyBytes_FromString(str);
1053+
else
1054+
Py_RETURN_NONE;
1055+
}
1056+
1057+
static PyObject *
1058+
getargs_z_star(PyObject *self, PyObject *args)
1059+
{
1060+
Py_buffer buffer;
1061+
PyObject *bytes;
1062+
if (!PyArg_ParseTuple(args, "z*", &buffer))
1063+
return NULL;
1064+
if (buffer.buf != NULL)
1065+
bytes = PyBytes_FromStringAndSize(buffer.buf, buffer.len);
1066+
else {
1067+
Py_INCREF(Py_None);
1068+
bytes = Py_None;
1069+
}
1070+
PyBuffer_Release(&buffer);
1071+
return bytes;
1072+
}
1073+
1074+
static PyObject *
1075+
getargs_z_hash(PyObject *self, PyObject *args)
1076+
{
1077+
char *str;
1078+
Py_ssize_t size;
1079+
if (!PyArg_ParseTuple(args, "z#", &str, &size))
1080+
return NULL;
1081+
if (str != NULL)
1082+
return PyBytes_FromStringAndSize(str, size);
1083+
else
1084+
Py_RETURN_NONE;
1085+
}
1086+
1087+
static PyObject *
1088+
getargs_y(PyObject *self, PyObject *args)
1089+
{
1090+
char *str;
1091+
if (!PyArg_ParseTuple(args, "y", &str))
1092+
return NULL;
1093+
return PyBytes_FromString(str);
1094+
}
1095+
1096+
static PyObject *
1097+
getargs_y_star(PyObject *self, PyObject *args)
1098+
{
1099+
Py_buffer buffer;
1100+
PyObject *bytes;
1101+
if (!PyArg_ParseTuple(args, "y*", &buffer))
1102+
return NULL;
1103+
bytes = PyBytes_FromStringAndSize(buffer.buf, buffer.len);
1104+
PyBuffer_Release(&buffer);
1105+
return bytes;
1106+
}
1107+
1108+
static PyObject *
1109+
getargs_y_hash(PyObject *self, PyObject *args)
1110+
{
1111+
char *str;
1112+
Py_ssize_t size;
1113+
if (!PyArg_ParseTuple(args, "y#", &str, &size))
1114+
return NULL;
1115+
return PyBytes_FromStringAndSize(str, size);
1116+
}
1117+
1118+
static PyObject *
1119+
getargs_u(PyObject *self, PyObject *args)
1120+
{
1121+
Py_UNICODE *str;
1122+
Py_ssize_t size;
1123+
if (!PyArg_ParseTuple(args, "u", &str))
1124+
return NULL;
1125+
size = Py_UNICODE_strlen(str);
1126+
return PyUnicode_FromUnicode(str, size);
1127+
}
1128+
1129+
static PyObject *
1130+
getargs_u_hash(PyObject *self, PyObject *args)
1131+
{
1132+
Py_UNICODE *str;
1133+
Py_ssize_t size;
1134+
if (!PyArg_ParseTuple(args, "u#", &str, &size))
1135+
return NULL;
1136+
return PyUnicode_FromUnicode(str, size);
1137+
}
1138+
1139+
static PyObject *
1140+
getargs_Z(PyObject *self, PyObject *args)
1141+
{
1142+
Py_UNICODE *str;
1143+
Py_ssize_t size;
1144+
if (!PyArg_ParseTuple(args, "Z", &str))
1145+
return NULL;
1146+
if (str != NULL) {
1147+
size = Py_UNICODE_strlen(str);
1148+
return PyUnicode_FromUnicode(str, size);
1149+
} else
1150+
Py_RETURN_NONE;
1151+
}
1152+
1153+
static PyObject *
1154+
getargs_Z_hash(PyObject *self, PyObject *args)
1155+
{
1156+
Py_UNICODE *str;
1157+
Py_ssize_t size;
1158+
if (!PyArg_ParseTuple(args, "Z#", &str, &size))
1159+
return NULL;
1160+
if (str != NULL)
1161+
return PyUnicode_FromUnicode(str, size);
1162+
else
1163+
Py_RETURN_NONE;
1164+
}
10141165

10151166
/* Test the s and z codes for PyArg_ParseTuple.
10161167
*/
@@ -2062,11 +2213,24 @@ static PyMethodDef TestMethods[] = {
20622213
{"test_long_long_and_overflow",
20632214
(PyCFunction)test_long_long_and_overflow, METH_NOARGS},
20642215
{"test_L_code", (PyCFunction)test_L_code, METH_NOARGS},
2216+
#endif
2217+
{"getargs_s", getargs_s, METH_VARARGS},
2218+
{"getargs_s_star", getargs_s_star, METH_VARARGS},
2219+
{"getargs_s_hash", getargs_s_hash, METH_VARARGS},
2220+
{"getargs_z", getargs_z, METH_VARARGS},
2221+
{"getargs_z_star", getargs_z_star, METH_VARARGS},
2222+
{"getargs_z_hash", getargs_z_hash, METH_VARARGS},
2223+
{"getargs_y", getargs_y, METH_VARARGS},
2224+
{"getargs_y_star", getargs_y_star, METH_VARARGS},
2225+
{"getargs_y_hash", getargs_y_hash, METH_VARARGS},
2226+
{"getargs_u", getargs_u, METH_VARARGS},
2227+
{"getargs_u_hash", getargs_u_hash, METH_VARARGS},
2228+
{"getargs_Z", getargs_Z, METH_VARARGS},
2229+
{"getargs_Z_hash", getargs_Z_hash, METH_VARARGS},
20652230
{"codec_incrementalencoder",
20662231
(PyCFunction)codec_incrementalencoder, METH_VARARGS},
20672232
{"codec_incrementaldecoder",
20682233
(PyCFunction)codec_incrementaldecoder, METH_VARARGS},
2069-
#endif
20702234
{"test_s_code", (PyCFunction)test_s_code, METH_NOARGS},
20712235
{"test_u_code", (PyCFunction)test_u_code, METH_NOARGS},
20722236
{"test_Z_code", (PyCFunction)test_Z_code, METH_NOARGS},

Python/getargs.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -935,10 +935,15 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
935935
count = convertbuffer(arg, p, &buf);
936936
if (count < 0)
937937
return converterr(buf, arg, msgbuf, bufsize);
938-
else if (*format == '#') {
938+
if (*format == '#') {
939939
FETCH_SIZE;
940940
STORE_SIZE(count);
941941
format++;
942+
} else {
943+
if (strlen(*p) != count)
944+
return converterr(
945+
"bytes without null bytes",
946+
arg, msgbuf, bufsize);
942947
}
943948
break;
944949
}
@@ -1045,9 +1050,13 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
10451050

10461051
if (arg == Py_None)
10471052
*p = 0;
1048-
else if (PyUnicode_Check(arg))
1053+
else if (PyUnicode_Check(arg)) {
10491054
*p = PyUnicode_AS_UNICODE(arg);
1050-
else
1055+
if (Py_UNICODE_strlen(*p) != PyUnicode_GET_SIZE(arg))
1056+
return converterr(
1057+
"str without null character or None",
1058+
arg, msgbuf, bufsize);
1059+
} else
10511060
return converterr("str or None", arg, msgbuf, bufsize);
10521061
}
10531062
break;
@@ -1227,6 +1236,11 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
12271236
FETCH_SIZE;
12281237
STORE_SIZE(PyUnicode_GET_SIZE(arg));
12291238
format++;
1239+
} else {
1240+
if (Py_UNICODE_strlen(*p) != PyUnicode_GET_SIZE(arg))
1241+
return converterr(
1242+
"str without null character",
1243+
arg, msgbuf, bufsize);
12301244
}
12311245
break;
12321246
}

0 commit comments

Comments
 (0)