Skip to content

Commit 7924903

Browse files
[3.14] gh-152228: Fix an assertion failure in str.replace under a limited memory case (GH-152229) (#152616)
gh-152228: Fix an assertion failure in `str.replace` under a limited memory case (GH-152229) (cherry picked from commit c5043dc) Co-authored-by: sobolevn <mail@sobolevn.me>
1 parent 7ad8bc2 commit 7924903

3 files changed

Lines changed: 26 additions & 9 deletions

File tree

Lib/test/test_str.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,21 @@ def test_replace_id(self):
600600
text = 'abc def'
601601
self.assertIs(text.replace(pattern, pattern), text)
602602

603+
@support.nomemtest
604+
def test_replace_oom(self):
605+
# https://github.com/python/cpython/issues/152228
606+
s1 = "轘" * 4
607+
s2 = "&"
608+
s3 = "&amp;"
609+
assertion = self.assertRaises(MemoryError)
610+
_testcapi.set_nomemory(0, 0)
611+
try:
612+
# No allocations made in the test itself:
613+
with assertion:
614+
s1.replace(s2, s3) # this line used to crash before
615+
finally:
616+
_testcapi.remove_mem_hooks()
617+
603618
def test_repeat_id_preserving(self):
604619
a = '123abc1@'
605620
b = '456zyx-+'
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix an assertion failure when python is built in a debug mode
2+
that happened in :meth:`str.replace` under a limited memory situation.

Objects/unicodeobject.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11046,9 +11046,9 @@ replace(PyObject *self, PyObject *str1,
1104611046
}
1104711047

1104811048
done:
11049-
assert(srelease == (sbuf != PyUnicode_DATA(self)));
11050-
assert(release1 == (buf1 != PyUnicode_DATA(str1)));
11051-
assert(release2 == (buf2 != PyUnicode_DATA(str2)));
11049+
assert(srelease == (sbuf != NULL && sbuf != PyUnicode_DATA(self)));
11050+
assert(release1 == (buf1 != NULL && buf1 != PyUnicode_DATA(str1)));
11051+
assert(release2 == (buf2 != NULL && buf2 != PyUnicode_DATA(str2)));
1105211052
if (srelease)
1105311053
PyMem_Free((void *)sbuf);
1105411054
if (release1)
@@ -11060,9 +11060,9 @@ replace(PyObject *self, PyObject *str1,
1106011060

1106111061
nothing:
1106211062
/* nothing to replace; return original string (when possible) */
11063-
assert(srelease == (sbuf != PyUnicode_DATA(self)));
11064-
assert(release1 == (buf1 != PyUnicode_DATA(str1)));
11065-
assert(release2 == (buf2 != PyUnicode_DATA(str2)));
11063+
assert(srelease == (sbuf != NULL && sbuf != PyUnicode_DATA(self)));
11064+
assert(release1 == (buf1 != NULL && buf1 != PyUnicode_DATA(str1)));
11065+
assert(release2 == (buf2 != NULL && buf2 != PyUnicode_DATA(str2)));
1106611066
if (srelease)
1106711067
PyMem_Free((void *)sbuf);
1106811068
if (release1)
@@ -11072,9 +11072,9 @@ replace(PyObject *self, PyObject *str1,
1107211072
return unicode_result_unchanged(self);
1107311073

1107411074
error:
11075-
assert(srelease == (sbuf != PyUnicode_DATA(self)));
11076-
assert(release1 == (buf1 != PyUnicode_DATA(str1)));
11077-
assert(release2 == (buf2 != PyUnicode_DATA(str2)));
11075+
assert(srelease == (sbuf != NULL && sbuf != PyUnicode_DATA(self)));
11076+
assert(release1 == (buf1 != NULL && buf1 != PyUnicode_DATA(str1)));
11077+
assert(release2 == (buf2 != NULL && buf2 != PyUnicode_DATA(str2)));
1107811078
if (srelease)
1107911079
PyMem_Free((void *)sbuf);
1108011080
if (release1)

0 commit comments

Comments
 (0)