Skip to content

Commit 9ea5a3a

Browse files
[3.6] bpo-20047: Make bytearray methods partition() and rpartition() rejecting (GH-4158) (#4162)
separators that are not bytes-like objects.. (cherry picked from commit a231428)
1 parent 0f1973d commit 9ea5a3a

File tree

7 files changed

+85
-34
lines changed

7 files changed

+85
-34
lines changed

Doc/library/stdtypes.rst

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2564,8 +2564,9 @@ arbitrary binary data.
25642564
bytearray.partition(sep)
25652565

25662566
Split the sequence at the first occurrence of *sep*, and return a 3-tuple
2567-
containing the part before the separator, the separator, and the part
2568-
after the separator. If the separator is not found, return a 3-tuple
2567+
containing the part before the separator, the separator itself or its
2568+
bytearray copy, and the part after the separator.
2569+
If the separator is not found, return a 3-tuple
25692570
containing a copy of the original sequence, followed by two empty bytes or
25702571
bytearray objects.
25712572

@@ -2620,8 +2621,9 @@ arbitrary binary data.
26202621
bytearray.rpartition(sep)
26212622

26222623
Split the sequence at the last occurrence of *sep*, and return a 3-tuple
2623-
containing the part before the separator, the separator, and the part
2624-
after the separator. If the separator is not found, return a 3-tuple
2624+
containing the part before the separator, the separator itself or its
2625+
bytearray copy, and the part after the separator.
2626+
If the separator is not found, return a 3-tuple
26252627
containing a copy of the original sequence, followed by two empty bytes or
26262628
bytearray objects.
26272629

Lib/test/test_bytes.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,16 @@ def test_replace(self):
540540
self.assertEqual(b.replace(b'i', b'a'), b'massassappa')
541541
self.assertEqual(b.replace(b'ss', b'x'), b'mixixippi')
542542

543+
def test_replace_int_error(self):
544+
self.assertRaises(TypeError, self.type2test(b'a b').replace, 32, b'')
545+
543546
def test_split_string_error(self):
544547
self.assertRaises(TypeError, self.type2test(b'a b').split, ' ')
548+
self.assertRaises(TypeError, self.type2test(b'a b').rsplit, ' ')
549+
550+
def test_split_int_error(self):
551+
self.assertRaises(TypeError, self.type2test(b'a b').split, 32)
552+
self.assertRaises(TypeError, self.type2test(b'a b').rsplit, 32)
545553

546554
def test_split_unicodewhitespace(self):
547555
for b in (b'a\x1Cb', b'a\x1Db', b'a\x1Eb', b'a\x1Fb'):
@@ -550,9 +558,6 @@ def test_split_unicodewhitespace(self):
550558
b = self.type2test(b"\x09\x0A\x0B\x0C\x0D\x1C\x1D\x1E\x1F")
551559
self.assertEqual(b.split(), [b'\x1c\x1d\x1e\x1f'])
552560

553-
def test_rsplit_string_error(self):
554-
self.assertRaises(TypeError, self.type2test(b'a b').rsplit, ' ')
555-
556561
def test_rsplit_unicodewhitespace(self):
557562
b = self.type2test(b"\x09\x0A\x0B\x0C\x0D\x1C\x1D\x1E\x1F")
558563
self.assertEqual(b.rsplit(), [b'\x1c\x1d\x1e\x1f'])
@@ -568,6 +573,14 @@ def test_rpartition(self):
568573
self.assertEqual(b.rpartition(b'i'), (b'mississipp', b'i', b''))
569574
self.assertEqual(b.rpartition(b'w'), (b'', b'', b'mississippi'))
570575

576+
def test_partition_string_error(self):
577+
self.assertRaises(TypeError, self.type2test(b'a b').partition, ' ')
578+
self.assertRaises(TypeError, self.type2test(b'a b').rpartition, ' ')
579+
580+
def test_partition_int_error(self):
581+
self.assertRaises(TypeError, self.type2test(b'a b').partition, 32)
582+
self.assertRaises(TypeError, self.type2test(b'a b').rpartition, 32)
583+
571584
def test_pickling(self):
572585
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
573586
for b in b"", b"a", b"abc", b"\xffab\x80", b"\0\0\377\0\0":
@@ -600,9 +613,14 @@ def test_strip_bytearray(self):
600613
self.assertEqual(self.type2test(b'abc').rstrip(memoryview(b'ac')), b'ab')
601614

602615
def test_strip_string_error(self):
603-
self.assertRaises(TypeError, self.type2test(b'abc').strip, 'b')
604-
self.assertRaises(TypeError, self.type2test(b'abc').lstrip, 'b')
605-
self.assertRaises(TypeError, self.type2test(b'abc').rstrip, 'b')
616+
self.assertRaises(TypeError, self.type2test(b'abc').strip, 'ac')
617+
self.assertRaises(TypeError, self.type2test(b'abc').lstrip, 'ac')
618+
self.assertRaises(TypeError, self.type2test(b'abc').rstrip, 'ac')
619+
620+
def test_strip_int_error(self):
621+
self.assertRaises(TypeError, self.type2test(b' abc ').strip, 32)
622+
self.assertRaises(TypeError, self.type2test(b' abc ').lstrip, 32)
623+
self.assertRaises(TypeError, self.type2test(b' abc ').rstrip, 32)
606624

607625
def test_center(self):
608626
# Fill character can be either bytes or bytearray (issue 12380)
@@ -625,6 +643,11 @@ def test_rjust(self):
625643
self.assertEqual(b.rjust(7, fill_type(b'-')),
626644
self.type2test(b'----abc'))
627645

646+
def test_xjust_int_error(self):
647+
self.assertRaises(TypeError, self.type2test(b'abc').center, 7, 32)
648+
self.assertRaises(TypeError, self.type2test(b'abc').ljust, 7, 32)
649+
self.assertRaises(TypeError, self.type2test(b'abc').rjust, 7, 32)
650+
628651
def test_ord(self):
629652
b = self.type2test(b'\0A\x7f\x80\xff')
630653
self.assertEqual([ord(b[i:i+1]) for i in range(len(b))],
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Bytearray methods partition() and rpartition() now accept only bytes-like
2+
objects as separator, as documented. In particular they now raise TypeError
3+
rather of returning a bogus result when an integer is passed as a separator.

Objects/bytearrayobject.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,26 @@ PyByteArray_FromObject(PyObject *input)
102102
input, NULL);
103103
}
104104

105+
static PyObject *
106+
_PyByteArray_FromBufferObject(PyObject *obj)
107+
{
108+
PyObject *result;
109+
Py_buffer view;
110+
111+
if (PyObject_GetBuffer(obj, &view, PyBUF_FULL_RO) < 0) {
112+
return NULL;
113+
}
114+
result = PyByteArray_FromStringAndSize(NULL, view.len);
115+
if (result != NULL &&
116+
PyBuffer_ToContiguous(PyByteArray_AS_STRING(result),
117+
&view, view.len, 'C') < 0)
118+
{
119+
Py_CLEAR(result);
120+
}
121+
PyBuffer_Release(&view);
122+
return result;
123+
}
124+
105125
PyObject *
106126
PyByteArray_FromStringAndSize(const char *bytes, Py_ssize_t size)
107127
{
@@ -534,7 +554,8 @@ bytearray_setslice(PyByteArrayObject *self, Py_ssize_t lo, Py_ssize_t hi,
534554
if (values == (PyObject *)self) {
535555
/* Make a copy and call this function recursively */
536556
int err;
537-
values = PyByteArray_FromObject(values);
557+
values = PyByteArray_FromStringAndSize(PyByteArray_AS_STRING(values),
558+
PyByteArray_GET_SIZE(values));
538559
if (values == NULL)
539560
return -1;
540561
err = bytearray_setslice(self, lo, hi, values);
@@ -1381,19 +1402,19 @@ Partition the bytearray into three parts using the given separator.
13811402
13821403
This will search for the separator sep in the bytearray. If the separator is
13831404
found, returns a 3-tuple containing the part before the separator, the
1384-
separator itself, and the part after it.
1405+
separator itself, and the part after it as new bytearray objects.
13851406
1386-
If the separator is not found, returns a 3-tuple containing the original
1387-
bytearray object and two empty bytearray objects.
1407+
If the separator is not found, returns a 3-tuple containing the copy of the
1408+
original bytearray object and two empty bytearray objects.
13881409
[clinic start generated code]*/
13891410

13901411
static PyObject *
13911412
bytearray_partition(PyByteArrayObject *self, PyObject *sep)
1392-
/*[clinic end generated code: output=45d2525ddd35f957 input=86f89223892b70b5]*/
1413+
/*[clinic end generated code: output=45d2525ddd35f957 input=8f644749ee4fc83a]*/
13931414
{
13941415
PyObject *bytesep, *result;
13951416

1396-
bytesep = PyByteArray_FromObject(sep);
1417+
bytesep = _PyByteArray_FromBufferObject(sep);
13971418
if (! bytesep)
13981419
return NULL;
13991420

@@ -1414,23 +1435,24 @@ bytearray.rpartition
14141435
sep: object
14151436
/
14161437
1417-
Partition the bytes into three parts using the given separator.
1438+
Partition the bytearray into three parts using the given separator.
14181439
1419-
This will search for the separator sep in the bytearray, starting and the end.
1440+
This will search for the separator sep in the bytearray, starting at the end.
14201441
If the separator is found, returns a 3-tuple containing the part before the
1421-
separator, the separator itself, and the part after it.
1442+
separator, the separator itself, and the part after it as new bytearray
1443+
objects.
14221444
14231445
If the separator is not found, returns a 3-tuple containing two empty bytearray
1424-
objects and the original bytearray object.
1446+
objects and the copy of the original bytearray object.
14251447
[clinic start generated code]*/
14261448

14271449
static PyObject *
14281450
bytearray_rpartition(PyByteArrayObject *self, PyObject *sep)
1429-
/*[clinic end generated code: output=440de3c9426115e8 input=5f4094f2de87c8f3]*/
1451+
/*[clinic end generated code: output=440de3c9426115e8 input=7e3df3e6cb8fa0ac]*/
14301452
{
14311453
PyObject *bytesep, *result;
14321454

1433-
bytesep = PyByteArray_FromObject(sep);
1455+
bytesep = _PyByteArray_FromBufferObject(sep);
14341456
if (! bytesep)
14351457
return NULL;
14361458

Objects/bytesobject.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,7 +1832,7 @@ bytes.rpartition
18321832
18331833
Partition the bytes into three parts using the given separator.
18341834
1835-
This will search for the separator sep in the bytes, starting and the end. If
1835+
This will search for the separator sep in the bytes, starting at the end. If
18361836
the separator is found, returns a 3-tuple containing the part before the
18371837
separator, the separator itself, and the part after it.
18381838
@@ -1842,7 +1842,7 @@ objects and the original bytes object.
18421842

18431843
static PyObject *
18441844
bytes_rpartition_impl(PyBytesObject *self, Py_buffer *sep)
1845-
/*[clinic end generated code: output=191b114cbb028e50 input=67f689e63a62d478]*/
1845+
/*[clinic end generated code: output=191b114cbb028e50 input=d78db010c8cfdbe1]*/
18461846
{
18471847
return stringlib_rpartition(
18481848
(PyObject*) self,

Objects/clinic/bytearrayobject.c.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,10 @@ PyDoc_STRVAR(bytearray_partition__doc__,
214214
"\n"
215215
"This will search for the separator sep in the bytearray. If the separator is\n"
216216
"found, returns a 3-tuple containing the part before the separator, the\n"
217-
"separator itself, and the part after it.\n"
217+
"separator itself, and the part after it as new bytearray objects.\n"
218218
"\n"
219-
"If the separator is not found, returns a 3-tuple containing the original\n"
220-
"bytearray object and two empty bytearray objects.");
219+
"If the separator is not found, returns a 3-tuple containing the copy of the\n"
220+
"original bytearray object and two empty bytearray objects.");
221221

222222
#define BYTEARRAY_PARTITION_METHODDEF \
223223
{"partition", (PyCFunction)bytearray_partition, METH_O, bytearray_partition__doc__},
@@ -226,14 +226,15 @@ PyDoc_STRVAR(bytearray_rpartition__doc__,
226226
"rpartition($self, sep, /)\n"
227227
"--\n"
228228
"\n"
229-
"Partition the bytes into three parts using the given separator.\n"
229+
"Partition the bytearray into three parts using the given separator.\n"
230230
"\n"
231-
"This will search for the separator sep in the bytearray, starting and the end.\n"
231+
"This will search for the separator sep in the bytearray, starting at the end.\n"
232232
"If the separator is found, returns a 3-tuple containing the part before the\n"
233-
"separator, the separator itself, and the part after it.\n"
233+
"separator, the separator itself, and the part after it as new bytearray\n"
234+
"objects.\n"
234235
"\n"
235236
"If the separator is not found, returns a 3-tuple containing two empty bytearray\n"
236-
"objects and the original bytearray object.");
237+
"objects and the copy of the original bytearray object.");
237238

238239
#define BYTEARRAY_RPARTITION_METHODDEF \
239240
{"rpartition", (PyCFunction)bytearray_rpartition, METH_O, bytearray_rpartition__doc__},
@@ -711,4 +712,4 @@ bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
711712
{
712713
return bytearray_sizeof_impl(self);
713714
}
714-
/*[clinic end generated code: output=225342a680391b9c input=a9049054013a1b77]*/
715+
/*[clinic end generated code: output=8f022100f059226c input=a9049054013a1b77]*/

Objects/clinic/bytesobject.c.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ PyDoc_STRVAR(bytes_rpartition__doc__,
8686
"\n"
8787
"Partition the bytes into three parts using the given separator.\n"
8888
"\n"
89-
"This will search for the separator sep in the bytes, starting and the end. If\n"
89+
"This will search for the separator sep in the bytes, starting at the end. If\n"
9090
"the separator is found, returns a 3-tuple containing the part before the\n"
9191
"separator, the separator itself, and the part after it.\n"
9292
"\n"
@@ -499,4 +499,4 @@ bytes_fromhex(PyTypeObject *type, PyObject *arg)
499499
exit:
500500
return return_value;
501501
}
502-
/*[clinic end generated code: output=2dc3c93cfd2dc440 input=a9049054013a1b77]*/
502+
/*[clinic end generated code: output=4ac7e35150d47467 input=a9049054013a1b77]*/

0 commit comments

Comments
 (0)