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

Skip to content

Commit a728f1c

Browse files
vstinnerStanFromIrelandcmaloney
authored
[3.13] gh-156995: Fix _PyBytes_Resize() in Free Threading (#156996) (#157373) (#157436)
[3.14] gh-156995: Fix _PyBytes_Resize() in Free Threading (#156996) (#157373) _PyBytes_Resize(&obj, 1) no longer returns a single byte singleton if the reference count is greater than 1. (cherry picked from commit fd569ea) Co-authored-by: Stan Ulbrych <[email protected]> Co-authored-by: Cody Maloney <[email protected]>
1 parent 8b2dd80 commit a728f1c

3 files changed

Lines changed: 43 additions & 26 deletions

File tree

Lib/test/test_capi/test_bytes.py

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
import unittest
23
from test.support import import_helper
34

@@ -231,26 +232,43 @@ def test_decodeescape(self):
231232

232233
def test_resize(self):
233234
"""Test _PyBytes_Resize()"""
234-
resize = _testcapi.bytes_resize
235+
_resize = _testcapi.bytes_resize
236+
empty_singleton = bytes()
237+
238+
def resize(obj, size, new):
239+
result = _resize(obj, size, new)
240+
if 1 <= len(result):
241+
if new or size != len(obj):
242+
# gh-156995: Make sure that the result is a fresh object.
243+
# Previously, _PyBytes_Resize(&obj, 1) returned a singleton
244+
# if the reference count is higher than 1.
245+
# Expect 2 references since sys.getrefcount() call adds
246+
# a reference.
247+
self.assertEqual(sys.getrefcount(result), 2)
248+
else:
249+
# check that the result is the empty bytes string singleton
250+
self.assertIs(result, empty_singleton)
251+
return result
235252

236253
for new in True, False:
237-
self.assertEqual(resize(b'abc', 0, new), b'')
238-
self.assertEqual(resize(b'abc', 1, new), b'a')
239-
self.assertEqual(resize(b'abc', 2, new), b'ab')
240-
self.assertEqual(resize(b'abc', 3, new), b'abc')
241-
b = resize(b'abc', 4, new)
242-
self.assertEqual(len(b), 4)
243-
self.assertEqual(b[:3], b'abc')
244-
245-
self.assertEqual(resize(b'a', 0, new), b'')
246-
self.assertEqual(resize(b'a', 1, new), b'a')
247-
b = resize(b'a', 2, new)
248-
self.assertEqual(len(b), 2)
249-
self.assertEqual(b[:1], b'a')
250-
251-
self.assertEqual(resize(b'', 0, new), b'')
252-
self.assertEqual(len(resize(b'', 1, new)), 1)
253-
self.assertEqual(len(resize(b'', 2, new)), 2)
254+
with self.subTest(new=new):
255+
self.assertEqual(resize(b'abc', 0, new), b'')
256+
self.assertEqual(resize(b'abc', 1, new), b'a')
257+
self.assertEqual(resize(b'abc', 2, new), b'ab')
258+
self.assertEqual(resize(b'abc', 3, new), b'abc')
259+
b = resize(b'abc', 4, new)
260+
self.assertEqual(len(b), 4)
261+
self.assertEqual(b[:3], b'abc')
262+
263+
self.assertEqual(resize(b'a', 0, new), b'')
264+
self.assertEqual(resize(b'a', 1, new), b'a')
265+
b = resize(b'a', 2, new)
266+
self.assertEqual(len(b), 2)
267+
self.assertEqual(b[:1], b'a')
268+
269+
self.assertEqual(resize(b'', 0, new), b'')
270+
self.assertEqual(len(resize(b'', 1, new)), 1)
271+
self.assertEqual(len(resize(b'', 2, new)), 2)
254272

255273
self.assertRaises(SystemError, resize, b'abc', -1, False)
256274
self.assertRaises(SystemError, resize, bytearray(b'abc'), 3, False)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
``_PyBytes_Resize(&obj, 1)`` no longer returns a single byte singleton if the
2+
reference count is greater than ``1``. Patch by Stan Ulbrych.

Objects/bytesobject.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3192,14 +3192,11 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize)
31923192
return 0;
31933193
}
31943194
if (Py_REFCNT(v) != 1) {
3195-
if (oldsize < newsize) {
3196-
*pv = _PyBytes_FromSize(newsize, 0);
3197-
if (*pv) {
3198-
memcpy(PyBytes_AS_STRING(*pv), PyBytes_AS_STRING(v), oldsize);
3199-
}
3200-
}
3201-
else {
3202-
*pv = PyBytes_FromStringAndSize(PyBytes_AS_STRING(v), newsize);
3195+
// Allocate and then copy so we don't get a one-character singleton!
3196+
*pv = _PyBytes_FromSize(newsize, 0);
3197+
if (*pv) {
3198+
memcpy(PyBytes_AS_STRING(*pv), PyBytes_AS_STRING(v),
3199+
Py_MIN(oldsize, newsize));
32033200
}
32043201
Py_DECREF(v);
32053202
return (*pv == NULL) ? -1 : 0;

0 commit comments

Comments
 (0)