summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2024-03-25 15:32:11 (GMT)
committerGitHub <noreply@github.com>2024-03-25 15:32:11 (GMT)
commit0c1a42cf9c8cd0d4534d5c1d58f118ce7c5c446e (patch)
tree929ca228612a2f48b5e7afa86101fcecb04ad29d /Objects
parent01e7405da400e8997f8964d06cc414045e144681 (diff)
downloadcpython-0c1a42cf9c8cd0d4534d5c1d58f118ce7c5c446e.zip
cpython-0c1a42cf9c8cd0d4534d5c1d58f118ce7c5c446e.tar.gz
cpython-0c1a42cf9c8cd0d4534d5c1d58f118ce7c5c446e.tar.bz2
gh-87193: Support bytes objects with refcount > 1 in _PyBytes_Resize() (GH-117160)
Create a new bytes object and destroy the old one if it has refcount > 1.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/bytesobject.c41
-rw-r--r--Objects/fileobject.c8
2 files changed, 24 insertions, 25 deletions
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index 26227dd..256e01f 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -3025,11 +3025,9 @@ PyBytes_ConcatAndDel(PyObject **pv, PyObject *w)
/* The following function breaks the notion that bytes are immutable:
- it changes the size of a bytes object. We get away with this only if there
- is only one module referencing the object. You can also think of it
+ it changes the size of a bytes object. You can think of it
as creating a new bytes object and destroying the old one, only
- more efficiently. In any case, don't use this if the bytes object may
- already be known to some other part of the code...
+ more efficiently.
Note that if there's not enough memory to resize the bytes object, the
original bytes object at *pv is deallocated, *pv is set to NULL, an "out of
memory" exception is set, and -1 is returned. Else (on success) 0 is
@@ -3045,28 +3043,40 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize)
PyBytesObject *sv;
v = *pv;
if (!PyBytes_Check(v) || newsize < 0) {
- goto error;
+ *pv = 0;
+ Py_DECREF(v);
+ PyErr_BadInternalCall();
+ return -1;
}
- if (Py_SIZE(v) == newsize) {
+ Py_ssize_t oldsize = PyBytes_GET_SIZE(v);
+ if (oldsize == newsize) {
/* return early if newsize equals to v->ob_size */
return 0;
}
- if (Py_SIZE(v) == 0) {
- if (newsize == 0) {
- return 0;
- }
+ if (oldsize == 0) {
*pv = _PyBytes_FromSize(newsize, 0);
Py_DECREF(v);
return (*pv == NULL) ? -1 : 0;
}
- if (Py_REFCNT(v) != 1) {
- goto error;
- }
if (newsize == 0) {
*pv = bytes_get_empty();
Py_DECREF(v);
return 0;
}
+ if (Py_REFCNT(v) != 1) {
+ if (oldsize < newsize) {
+ *pv = _PyBytes_FromSize(newsize, 0);
+ if (*pv) {
+ memcpy(PyBytes_AS_STRING(*pv), PyBytes_AS_STRING(v), oldsize);
+ }
+ }
+ else {
+ *pv = PyBytes_FromStringAndSize(PyBytes_AS_STRING(v), newsize);
+ }
+ Py_DECREF(v);
+ return (*pv == NULL) ? -1 : 0;
+ }
+
#ifdef Py_TRACE_REFS
_Py_ForgetReference(v);
#endif
@@ -3089,11 +3099,6 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
sv->ob_shash = -1; /* invalidate cached hash value */
_Py_COMP_DIAG_POP
return 0;
-error:
- *pv = 0;
- Py_DECREF(v);
- PyErr_BadInternalCall();
- return -1;
}
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index e30ab95..bae49d3 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -80,13 +80,7 @@ PyFile_GetLine(PyObject *f, int n)
"EOF when reading a line");
}
else if (s[len-1] == '\n') {
- if (Py_REFCNT(result) == 1)
- _PyBytes_Resize(&result, len-1);
- else {
- PyObject *v;
- v = PyBytes_FromStringAndSize(s, len-1);
- Py_SETREF(result, v);
- }
+ (void) _PyBytes_Resize(&result, len-1);
}
}
if (n < 0 && result != NULL && PyUnicode_Check(result)) {