]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-152228: Fix an assertion failure in `str.replace` under a limited memory case...
authorsobolevn <mail@sobolevn.me>
Mon, 29 Jun 2026 16:22:22 +0000 (19:22 +0300)
committerGitHub <noreply@github.com>
Mon, 29 Jun 2026 16:22:22 +0000 (16:22 +0000)
Lib/test/test_str.py
Misc/NEWS.d/next/Core_and_Builtins/2026-06-25-21-34-15.gh-issue-152228.a6K14K.rst [new file with mode: 0644]
Objects/unicodeobject.c

index 4f57499af70f4d1d6978cf7477173ae115d473a4..979bfe36fff680d6fbdb6568852fe7f74b857463 100644 (file)
@@ -607,6 +607,21 @@ class StrTest(string_tests.StringLikeTest,
         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 = "&amp;"
+        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 (file)
index 0000000..8af7ae0
--- /dev/null
@@ -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.
index 3c689761de9b199d0b4256089d422bcf7b1a56d7..785620a186c9cd7f6711c592af40d2d670c914e5 100644 (file)
@@ -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)