Skip to content

Commit 3b1057d

Browse files
authored
gh-156939: Clear newly allocated bytes in PyBytesWriter_Resize() (#157455)
Adjust the logic to set newly allocated bytes to a known byte pattern (PyBytesWrite_NEW_BYTE). Only copy 'size' bytes from the small buffer to the new bytes/bytearray object.
1 parent 2d1007f commit 3b1057d

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
@@ -386,7 +386,7 @@ def test_get_data(self):
386386
writer.write(0, b's' * small)
387387
self.assertEqual(writer.get_data(), b's' * small)
388388
writer.resize(large)
389-
self.assertEqual(writer.get_data(), b's' * small + CANARY_BYTE + NEW_BYTE * (large - small - 1))
389+
self.assertEqual(writer.get_data(), b's' * small + NEW_BYTE * (large - small))
390390
writer.write(small, b'L' * (large - small))
391391
self.assertEqual(writer.get_data(), b's' * small + b'L' * (large - small))
392392

@@ -475,6 +475,7 @@ def test_resize(self):
475475
@unittest.skipUnless(support.Py_DEBUG, 'need debug build')
476476
def test_resize_canary(self):
477477
CANARY_BYTE = self.CANARY_BYTE
478+
478479
for size in (self.SMALL_BUFFER, self.LARGE_BUFFER):
479480
with self.subTest(size=size):
480481
# Truncate the last byte
@@ -490,7 +491,7 @@ def test_resize_canary(self):
490491
writer = self.create_writer(size)
491492
writer.write(0, data)
492493
writer.resize(0)
493-
self.assertEqual(writer.get_data(), b'')
494+
self.assertEqual(get_data_canary(writer), CANARY_BYTE)
494495
self.assertEqual(writer.finish(), b'')
495496

496497
@support.nomemtest

Objects/bytesobject.c

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3719,25 +3719,26 @@ byteswriter_reset_trailing_byte(PyBytesWriter *writer)
37193719
#endif
37203720

37213721
static inline int
3722-
byteswriter_resize(PyBytesWriter *writer, Py_ssize_t size, int resize)
3722+
byteswriter_resize(PyBytesWriter *writer, Py_ssize_t new_size, int resize)
37233723
{
3724-
assert(size >= 0);
3724+
assert(new_size >= 0);
37253725

37263726
Py_ssize_t old_allocated = byteswriter_allocated(writer);
3727-
if (size <= old_allocated) {
3727+
if (new_size <= old_allocated) {
37283728
// Do not shrink the buffer before PyBytesWriter_FinishWithSize()
37293729
return 0;
37303730
}
37313731

3732+
Py_ssize_t alloc = new_size;
37323733
if (resize && writer->overallocate) {
3733-
if (size <= (PY_SSIZE_T_MAX - size / OVERALLOCATE_FACTOR)) {
3734-
size += size / OVERALLOCATE_FACTOR;
3734+
if (alloc <= (PY_SSIZE_T_MAX - alloc / OVERALLOCATE_FACTOR)) {
3735+
alloc += alloc / OVERALLOCATE_FACTOR;
37353736
}
37363737
}
37373738

37383739
if (writer->obj != NULL) {
37393740
if (writer->use_bytearray) {
3740-
if (PyByteArray_Resize(writer->obj, size)) {
3741+
if (PyByteArray_Resize(writer->obj, alloc)) {
37413742
#ifdef Py_DEBUG
37423743
// bytearray can override the canary byte on error
37433744
byteswriter_write_canary_byte(writer);
@@ -3747,45 +3748,48 @@ byteswriter_resize(PyBytesWriter *writer, Py_ssize_t size, int resize)
37473748
}
37483749
else {
37493750
// Can raise MemoryError or OverflowError
3750-
if (_PyBytes_ResizeKeepOnError(&writer->obj, size)) {
3751+
if (_PyBytes_ResizeKeepOnError(&writer->obj, alloc)) {
37513752
assert(writer->obj != NULL);
37523753
return -1;
37533754
}
37543755
assert(_PyBytes_IsMutable(writer->obj));
37553756
}
37563757
assert(writer->obj != NULL);
37573758
}
3758-
else if (writer->use_bytearray) {
3759-
writer->obj = PyByteArray_FromStringAndSize(NULL, size);
3760-
if (writer->obj == NULL) {
3761-
return -1;
3762-
}
3763-
if (resize) {
3764-
assert((size_t)size > sizeof(writer->small_buffer));
3765-
memcpy(PyByteArray_AS_STRING(writer->obj),
3766-
writer->small_buffer,
3767-
sizeof(writer->small_buffer));
3768-
}
3769-
}
37703759
else {
3771-
writer->obj = PyBytes_FromStringAndSize(NULL, size);
3772-
if (writer->obj == NULL) {
3773-
return -1;
3760+
char *data;
3761+
if (writer->use_bytearray) {
3762+
writer->obj = PyByteArray_FromStringAndSize(NULL, alloc);
3763+
if (writer->obj == NULL) {
3764+
return -1;
3765+
}
3766+
data = PyByteArray_AS_STRING(writer->obj);
3767+
}
3768+
else {
3769+
writer->obj = PyBytes_FromStringAndSize(NULL, alloc);
3770+
if (writer->obj == NULL) {
3771+
return -1;
3772+
}
3773+
assert(_PyBytes_IsMutable(writer->obj));
3774+
data = PyBytes_AS_STRING(writer->obj);
37743775
}
3776+
37753777
if (resize) {
3776-
assert((size_t)size > sizeof(writer->small_buffer));
3777-
memcpy(PyBytes_AS_STRING(writer->obj),
3778-
writer->small_buffer,
3779-
sizeof(writer->small_buffer));
3778+
// Copy data from the small buffer
3779+
Py_ssize_t old_size = writer->size;
3780+
assert((size_t)old_size <= sizeof(writer->small_buffer));
3781+
assert(old_size <= alloc);
3782+
memcpy(data, writer->small_buffer, old_size);
37803783
}
3781-
assert(_PyBytes_IsMutable(writer->obj));
37823784
}
37833785

37843786
#ifdef Py_DEBUG
37853787
Py_ssize_t allocated = byteswriter_allocated(writer);
3786-
if (resize && allocated > old_allocated) {
3787-
memset(byteswriter_data(writer) + old_allocated, PyBytesWrite_NEW_BYTE,
3788-
allocated - old_allocated);
3788+
if (resize) {
3789+
Py_ssize_t old_size = writer->size;
3790+
assert(allocated > old_size);
3791+
memset(byteswriter_data(writer) + old_size, PyBytesWrite_NEW_BYTE,
3792+
allocated - old_size);
37893793
}
37903794
#endif
37913795

0 commit comments

Comments
 (0)