https://github.com/python/cpython/commit/7ffef8d07bba6c1c8551cafc3f0cb58c9102f909
commit: 7ffef8d07bba6c1c8551cafc3f0cb58c9102f909
branch: 3.13
author: Donghee Na <donghee...@python.org>
committer: corona10 <donghee.n...@gmail.com>
date: 2025-04-29T14:26:44+09:00
summary:

[3.13] gh-132070: Use _PyObject_IsUniquelyReferenced in unicodeobject 
(gh-133039) (gh-133126)

* gh-132070: Use _PyObject_IsUniquelyReferenced in unicodeobject (gh-133039)

---------
(cherry picked from commit 75cbb8d89e7e92ccaba5c615c72459f241dca8b1)

Co-authored-by: Donghee Na <donghee...@python.org>
Co-authored-by: Kumar Aditya <kumaradi...@python.org>
Co-authored-by: Serhiy Storchaka <storch...@gmail.com>

* Add _PyObject_IsUniquelyReferenced

---------

Co-authored-by: Kumar Aditya <kumaradi...@python.org>
Co-authored-by: Serhiy Storchaka <storch...@gmail.com>

files:
M Include/internal/pycore_object.h
M Objects/unicodeobject.c

diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index 07b5a95ae1a037..bed8b9b171ba02 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -165,6 +165,23 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t 
n)
 extern void _Py_SetImmortal(PyObject *op);
 extern void _Py_SetImmortalUntracked(PyObject *op);
 
+// Checks if an object has a single, unique reference. If the caller holds a
+// unique reference, it may be able to safely modify the object in-place.
+static inline int
+_PyObject_IsUniquelyReferenced(PyObject *ob)
+{
+#if !defined(Py_GIL_DISABLED)
+    return Py_REFCNT(ob) == 1;
+#else
+    // NOTE: the entire ob_ref_shared field must be zero, including flags, to
+    // ensure that other threads cannot concurrently create new references to
+    // this object.
+    return (_Py_IsOwnedByCurrentThread(ob) &&
+            _Py_atomic_load_uint32_relaxed(&ob->ob_ref_local) == 1 &&
+            _Py_atomic_load_ssize_relaxed(&ob->ob_ref_shared) == 0);
+#endif
+}
+
 // Makes an immortal object mortal again with the specified refcnt. Should only
 // be used during runtime finalization.
 static inline void _Py_SetMortal(PyObject *op, Py_ssize_t refcnt)
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index a00125345b2dd5..27e66b2a7ca18c 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -1121,6 +1121,21 @@ unicode_fill_invalid(PyObject *unicode, Py_ssize_t 
old_length)
 }
 #endif
 
+static PyObject*
+resize_copy(PyObject *unicode, Py_ssize_t length)
+{
+    Py_ssize_t copy_length;
+    PyObject *copy;
+
+    copy = PyUnicode_New(length, PyUnicode_MAX_CHAR_VALUE(unicode));
+    if (copy == NULL)
+        return NULL;
+
+    copy_length = Py_MIN(length, PyUnicode_GET_LENGTH(unicode));
+    _PyUnicode_FastCopyCharacters(copy, 0, unicode, 0, copy_length);
+    return copy;
+}
+
 static PyObject*
 resize_compact(PyObject *unicode, Py_ssize_t length)
 {
@@ -1132,7 +1147,14 @@ resize_compact(PyObject *unicode, Py_ssize_t length)
     Py_ssize_t old_length = _PyUnicode_LENGTH(unicode);
 #endif
 
-    assert(unicode_modifiable(unicode));
+    if (!unicode_modifiable(unicode)) {
+        PyObject *copy = resize_copy(unicode, length);
+        if (copy == NULL) {
+            return NULL;
+        }
+        Py_DECREF(unicode);
+        return copy;
+    }
     assert(PyUnicode_IS_COMPACT(unicode));
 
     char_size = PyUnicode_KIND(unicode);
@@ -1232,21 +1254,6 @@ resize_inplace(PyObject *unicode, Py_ssize_t length)
     return 0;
 }
 
-static PyObject*
-resize_copy(PyObject *unicode, Py_ssize_t length)
-{
-    Py_ssize_t copy_length;
-    PyObject *copy;
-
-    copy = PyUnicode_New(length, PyUnicode_MAX_CHAR_VALUE(unicode));
-    if (copy == NULL)
-        return NULL;
-
-    copy_length = Py_MIN(length, PyUnicode_GET_LENGTH(unicode));
-    _PyUnicode_FastCopyCharacters(copy, 0, unicode, 0, copy_length);
-    return copy;
-}
-
 static const char*
 unicode_kind_name(PyObject *unicode)
 {
@@ -1836,7 +1843,7 @@ static int
 unicode_modifiable(PyObject *unicode)
 {
     assert(_PyUnicode_CHECK(unicode));
-    if (Py_REFCNT(unicode) != 1)
+    if (!_PyObject_IsUniquelyReferenced(unicode))
         return 0;
     if (PyUnicode_HASH(unicode) != -1)
         return 0;
@@ -14025,7 +14032,7 @@ _PyUnicode_FormatLong(PyObject *val, int alt, int prec, 
int type)
     assert(PyUnicode_IS_ASCII(result));
 
     /* To modify the string in-place, there can only be one reference. */
-    if (Py_REFCNT(result) != 1) {
+    if (!_PyObject_IsUniquelyReferenced(result)) {
         Py_DECREF(result);
         PyErr_BadInternalCall();
         return NULL;

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to