Skip to content

Commit 07185df

Browse files
committed
gh-129813: Check size in PyBytesWriter_FinishWithSize()
Reject size larger than the allocated size. Also, check negative size in PyBytesWriter_FinishWithSize() to always raise ValueError. Previously, the function raised SystemError or ValueError depending on the code path. Replace _PyBytesWriter_GetAllocated() optimization with _PyBytesWriter_ResizeToAllocated() to update the writer size to its allocated size.
1 parent 52ffffe commit 07185df

2 files changed

Lines changed: 42 additions & 14 deletions

File tree

Lib/test/test_capi/test_bytes.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,20 @@ def test_create(self):
317317

318318
def test_finish_with_size(self):
319319
# Test PyBytesWriter_FinishWithSize()
320-
writer = self.create_writer(10, b'abc')
320+
writer = self.create_writer(10, b'abcdef')
321321
self.assertEqual(writer.get_size(), 10)
322322
self.assertEqual(writer.finish_with_size(3), self.result_type(b'abc'))
323323

324+
# Error if the size is negative
324325
writer = self.create_writer(3, b'abc')
325-
with self.assertRaises(SystemError):
326+
with self.assertRaises(ValueError):
326327
writer.finish_with_size(-3)
327328

329+
# Error if the requested size is larger than the allocated size
330+
writer = self.create_writer(3, b'abc')
331+
with self.assertRaises(ValueError):
332+
writer.finish_with_size(4)
333+
328334
def test_write_bytes(self):
329335
# Test PyBytesWriter_WriteBytes()
330336
writer = self.create_writer()

Objects/bytesobject.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class bytes "PyBytesObject *" "&PyBytes_Type"
3131
/* Forward declaration */
3232
static void* _PyBytesWriter_ResizeAndUpdatePointer(PyBytesWriter *writer,
3333
Py_ssize_t size, void *data);
34-
static Py_ssize_t _PyBytesWriter_GetAllocated(PyBytesWriter *writer);
34+
static Py_ssize_t _PyBytesWriter_ResizeToAllocated(PyBytesWriter *writer);
3535

3636

3737
#define CHARACTERS _Py_SINGLETON(bytes_characters)
@@ -2993,8 +2993,8 @@ _PyBytes_FromList(PyObject *x)
29932993
if (writer == NULL) {
29942994
return NULL;
29952995
}
2996+
size = _PyBytesWriter_ResizeToAllocated(writer);
29962997
char *str = PyBytesWriter_GetData(writer);
2997-
size = _PyBytesWriter_GetAllocated(writer);
29982998

29992999
for (Py_ssize_t i = 0; i < PyList_GET_SIZE(x); i++) {
30003000
PyObject *item = _PyList_GetItemRef((PyListObject *)x, i);
@@ -3017,7 +3017,9 @@ _PyBytes_FromList(PyObject *x)
30173017
if (str == NULL) {
30183018
goto error;
30193019
}
3020-
size = _PyBytesWriter_GetAllocated(writer);
3020+
3021+
// Set the writer size to its allocated size
3022+
size = _PyBytesWriter_ResizeToAllocated(writer);
30213023
}
30223024
*str++ = (char) value;
30233025
}
@@ -3075,8 +3077,8 @@ _PyBytes_FromIterator(PyObject *it, PyObject *x)
30753077
if (writer == NULL) {
30763078
return NULL;
30773079
}
3080+
size = _PyBytesWriter_ResizeToAllocated(writer);
30783081
char *str = PyBytesWriter_GetData(writer);
3079-
size = _PyBytesWriter_GetAllocated(writer);
30803082

30813083
/* Run the iterator to exhaustion */
30823084
for (i = 0; ; i++) {
@@ -3110,7 +3112,9 @@ _PyBytes_FromIterator(PyObject *it, PyObject *x)
31103112
if (str == NULL) {
31113113
goto error;
31123114
}
3113-
size = _PyBytesWriter_GetAllocated(writer);
3115+
3116+
// Set the writer size to its allocated size
3117+
size = _PyBytesWriter_ResizeToAllocated(writer);
31143118
}
31153119
*str++ = (char) value;
31163120
}
@@ -3747,6 +3751,19 @@ PyBytesWriter_Discard(PyBytesWriter *writer)
37473751
PyObject*
37483752
PyBytesWriter_FinishWithSize(PyBytesWriter *writer, Py_ssize_t size)
37493753
{
3754+
// Check for negative size here to raise ValueError in all cases, rather
3755+
// than having a different exception depending on the code path. For
3756+
// example, _PyBytes_Resize() raises SystemError on negative size.
3757+
if (size < 0) {
3758+
PyErr_Format(PyExc_ValueError, "size must be positive");
3759+
return NULL;
3760+
}
3761+
3762+
if (size > writer->size) {
3763+
PyErr_SetString(PyExc_ValueError, "size larger than allocated size");
3764+
return NULL;
3765+
}
3766+
37503767
PyObject *result;
37513768
if (size == 0) {
37523769
result = bytes_get_empty();
@@ -3828,13 +3845,6 @@ PyBytesWriter_GetSize(PyBytesWriter *writer)
38283845
}
38293846

38303847

3831-
static Py_ssize_t
3832-
_PyBytesWriter_GetAllocated(PyBytesWriter *writer)
3833-
{
3834-
return byteswriter_allocated(writer);
3835-
}
3836-
3837-
38383848
int
38393849
PyBytesWriter_Resize(PyBytesWriter *writer, Py_ssize_t size)
38403850
{
@@ -3934,3 +3944,15 @@ PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...)
39343944
Py_ssize_t size = buf - byteswriter_data(writer);
39353945
return PyBytesWriter_Resize(writer, size);
39363946
}
3947+
3948+
3949+
// Resize the writer to its allocated size.
3950+
// Return the new size.
3951+
// The function cannot fail.
3952+
static Py_ssize_t
3953+
_PyBytesWriter_ResizeToAllocated(PyBytesWriter *writer)
3954+
{
3955+
Py_ssize_t allocated = byteswriter_allocated(writer);
3956+
writer->size = allocated;
3957+
return allocated;
3958+
}

0 commit comments

Comments
 (0)