https://github.com/python/cpython/commit/c5043dce1c6743682d93c71e937b95e7d27e0b35
commit: c5043dce1c6743682d93c71e937b95e7d27e0b35
branch: main
author: sobolevn <[email protected]>
committer: sobolevn <[email protected]>
date: 2026-06-29T16:22:22Z
summary:
gh-152228: Fix an assertion failure in `str.replace` under a limited memory
case (#152229)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst
M Lib/test/test_str.py
M Objects/unicodeobject.c
diff --git a/Lib/test/test_str.py b/Lib/test/test_str.py
index 4f57499af70f4d1..979bfe36fff680d 100644
--- a/Lib/test/test_str.py
+++ b/Lib/test/test_str.py
@@ -607,6 +607,21 @@ def test_replace_id(self):
text = 'abc def'
self.assertIs(text.replace(pattern, pattern), text)
+ @support.nomemtest
+ def test_replace_oom(self):
+ # https://github.com/python/cpython/issues/152228
+ s1 = "轘" * 4
+ s2 = "&"
+ s3 = "&"
+ assertion = self.assertRaises(MemoryError)
+ _testcapi.set_nomemory(0, 0)
+ try:
+ # No allocations made in the test itself:
+ with assertion:
+ s1.replace(s2, s3) # this line used to crash before
+ finally:
+ _testcapi.remove_mem_hooks()
+
def test_repeat_id_preserving(self):
a = '123abc1@'
b = '456zyx-+'
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst
new file mode 100644
index 000000000000000..8af7ae0d1739130
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst
@@ -0,0 +1,2 @@
+Fix an assertion failure when python is built in a debug mode
+that happened in :meth:`str.replace` under a limited memory situation.
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 3c689761de9b199..785620a186c9cd7 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -10753,9 +10753,9 @@ replace(PyObject *self, PyObject *str1,
}
done:
- assert(srelease == (sbuf != PyUnicode_DATA(self)));
- assert(release1 == (buf1 != PyUnicode_DATA(str1)));
- assert(release2 == (buf2 != PyUnicode_DATA(str2)));
+ assert(srelease == (sbuf != NULL && sbuf != PyUnicode_DATA(self)));
+ assert(release1 == (buf1 != NULL && buf1 != PyUnicode_DATA(str1)));
+ assert(release2 == (buf2 != NULL && buf2 != PyUnicode_DATA(str2)));
if (srelease)
PyMem_Free((void *)sbuf);
if (release1)
@@ -10767,9 +10767,9 @@ replace(PyObject *self, PyObject *str1,
nothing:
/* nothing to replace; return original string (when possible) */
- assert(srelease == (sbuf != PyUnicode_DATA(self)));
- assert(release1 == (buf1 != PyUnicode_DATA(str1)));
- assert(release2 == (buf2 != PyUnicode_DATA(str2)));
+ assert(srelease == (sbuf != NULL && sbuf != PyUnicode_DATA(self)));
+ assert(release1 == (buf1 != NULL && buf1 != PyUnicode_DATA(str1)));
+ assert(release2 == (buf2 != NULL && buf2 != PyUnicode_DATA(str2)));
if (srelease)
PyMem_Free((void *)sbuf);
if (release1)
@@ -10779,9 +10779,9 @@ replace(PyObject *self, PyObject *str1,
return unicode_result_unchanged(self);
error:
- assert(srelease == (sbuf != PyUnicode_DATA(self)));
- assert(release1 == (buf1 != PyUnicode_DATA(str1)));
- assert(release2 == (buf2 != PyUnicode_DATA(str2)));
+ assert(srelease == (sbuf != NULL && sbuf != PyUnicode_DATA(self)));
+ assert(release1 == (buf1 != NULL && buf1 != PyUnicode_DATA(str1)));
+ assert(release2 == (buf2 != NULL && buf2 != PyUnicode_DATA(str2)));
if (srelease)
PyMem_Free((void *)sbuf);
if (release1)
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]