Skip to content

Commit 89057e8

Browse files
committed
gh-156939: Clear newly allocated bytes in PyBytesWriter_Resize()
Adjust the logic to set newly allocated bytes to a known pattern (PyBytesWrite_NEW_BYTE). Only copy 'size' bytes from the small buffer to the new bytes/bytearray object.
1 parent fb46c67 commit 89057e8

2 files changed

Lines changed: 37 additions & 32 deletions

File tree

Lib/test/test_capi/test_bytes.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ def test_get_data(self):
366366
writer.write(0, b's' * small)
367367
self.assertEqual(writer.get_data(), b's' * small)
368368
writer.resize(large)
369-
self.assertEqual(writer.get_data(), b's' * small + CANARY_BYTE + NEW_BYTE * (large - small - 1))
369+
self.assertEqual(writer.get_data(), b's' * small + NEW_BYTE * (large - small))
370370
writer.write(small, b'L' * (large - small))
371371
self.assertEqual(writer.get_data(), b's' * small + b'L' * (large - small))
372372

@@ -455,6 +455,7 @@ def test_resize(self):
455455
@unittest.skipUnless(support.Py_DEBUG, 'need debug build')
456456
def test_resize_canary(self):
457457
CANARY_BYTE = self.CANARY_BYTE
458+
458459
for size in (self.SMALL_BUFFER, self.LARGE_BUFFER):
459460
with self.subTest(size=size):
460461
# Truncate the last byte
@@ -470,7 +471,7 @@ def test_resize_canary(self):
470471
writer = self.create_writer(size)
471472
writer.write(0, data)
472473
writer.resize(0)
473-
self.assertEqual(writer.get_data(), b'')
474+
self.assertEqual(get_data_canary(writer), CANARY_BYTE)
474475
self.assertEqual(writer.finish(), b'')
475476

476477
@support.nomemtest

Objects/bytesobject.c

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3677,25 +3677,26 @@ byteswriter_write_canary_byte(PyBytesWriter *writer)
36773677
#endif
36783678

36793679
static inline int
3680-
byteswriter_resize(PyBytesWriter *writer, Py_ssize_t size, int resize)
3680+
byteswriter_resize(PyBytesWriter *writer, Py_ssize_t new_size, int resize)
36813681
{
3682-
assert(size >= 0);
3682+
assert(new_size >= 0);
36833683

36843684
Py_ssize_t old_allocated = byteswriter_allocated(writer);
3685-
if (size <= old_allocated) {
3685+
if (new_size <= old_allocated) {
36863686
// Do not shrink the buffer before PyBytesWriter_FinishWithSize()
36873687
return 0;
36883688
}
36893689

3690+
Py_ssize_t alloc = new_size;
36903691
if (resize && writer->overallocate) {
3691-
if (size <= (PY_SSIZE_T_MAX - size / OVERALLOCATE_FACTOR)) {
3692-
size += size / OVERALLOCATE_FACTOR;
3692+
if (alloc <= (PY_SSIZE_T_MAX - alloc / OVERALLOCATE_FACTOR)) {
3693+
alloc += alloc / OVERALLOCATE_FACTOR;
36933694
}
36943695
}
36953696

36963697
if (writer->obj != NULL) {
36973698
if (writer->use_bytearray) {
3698-
if (PyByteArray_Resize(writer->obj, size)) {
3699+
if (PyByteArray_Resize(writer->obj, alloc)) {
36993700
#ifdef Py_DEBUG
37003701
// bytearray can override the canary byte on error
37013702
byteswriter_write_canary_byte(writer);
@@ -3705,45 +3706,48 @@ byteswriter_resize(PyBytesWriter *writer, Py_ssize_t size, int resize)
37053706
}
37063707
else {
37073708
// Can raise MemoryError or OverflowError
3708-
if (_PyBytes_ResizeKeepOnError(&writer->obj, size)) {
3709+
if (_PyBytes_ResizeKeepOnError(&writer->obj, alloc)) {
37093710
assert(writer->obj != NULL);
37103711
return -1;
37113712
}
37123713
assert(_PyBytes_IsMutable(writer->obj));
37133714
}
37143715
assert(writer->obj != NULL);
37153716
}
3716-
else if (writer->use_bytearray) {
3717-
writer->obj = PyByteArray_FromStringAndSize(NULL, size);
3718-
if (writer->obj == NULL) {
3719-
return -1;
3720-
}
3721-
if (resize) {
3722-
assert((size_t)size > sizeof(writer->small_buffer));
3723-
memcpy(PyByteArray_AS_STRING(writer->obj),
3724-
writer->small_buffer,
3725-
sizeof(writer->small_buffer));
3726-
}
3727-
}
37283717
else {
3729-
writer->obj = PyBytes_FromStringAndSize(NULL, size);
3730-
if (writer->obj == NULL) {
3731-
return -1;
3718+
char *data;
3719+
if (writer->use_bytearray) {
3720+
writer->obj = PyByteArray_FromStringAndSize(NULL, alloc);
3721+
if (writer->obj == NULL) {
3722+
return -1;
3723+
}
3724+
data = PyByteArray_AS_STRING(writer->obj);
3725+
}
3726+
else {
3727+
writer->obj = PyBytes_FromStringAndSize(NULL, alloc);
3728+
if (writer->obj == NULL) {
3729+
return -1;
3730+
}
3731+
assert(_PyBytes_IsMutable(writer->obj));
3732+
data = PyBytes_AS_STRING(writer->obj);
37323733
}
3734+
37333735
if (resize) {
3734-
assert((size_t)size > sizeof(writer->small_buffer));
3735-
memcpy(PyBytes_AS_STRING(writer->obj),
3736-
writer->small_buffer,
3737-
sizeof(writer->small_buffer));
3736+
// Copy data from the small buffer
3737+
Py_ssize_t old_size = writer->size;
3738+
assert((size_t)old_size <= sizeof(writer->small_buffer));
3739+
assert(old_size <= alloc);
3740+
memcpy(data, writer->small_buffer, old_size);
37383741
}
3739-
assert(_PyBytes_IsMutable(writer->obj));
37403742
}
37413743

37423744
#ifdef Py_DEBUG
37433745
Py_ssize_t allocated = byteswriter_allocated(writer);
3744-
if (resize && allocated > old_allocated) {
3745-
memset(byteswriter_data(writer) + old_allocated, PyBytesWrite_NEW_BYTE,
3746-
allocated - old_allocated);
3746+
if (resize) {
3747+
Py_ssize_t old_size = writer->size;
3748+
assert(allocated > old_size);
3749+
memset(byteswriter_data(writer) + old_size, PyBytesWrite_NEW_BYTE,
3750+
allocated - old_size);
37473751
}
37483752
#endif
37493753

0 commit comments

Comments
 (0)