Skip to content

Commit 2383c60

Browse files
authored
[3.13] gh-127971: fix off-by-one read beyond the end of a string during search (#132574) (#136648)
(cherry picked from commit 85ec3b3)
1 parent 823bf76 commit 2383c60

File tree

3 files changed

+14
-4
lines changed

3 files changed

+14
-4
lines changed

Lib/test/string_tests.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,15 @@ def test_replace(self):
767767
self.checkraises(TypeError, 'hello', 'replace', 42, 'h')
768768
self.checkraises(TypeError, 'hello', 'replace', 'h', 42)
769769

770+
def test_replacement_on_buffer_boundary(self):
771+
# gh-127971: Check we don't read past the end of the buffer when a
772+
# potential match misses on the last character.
773+
any_3_nonblank_codepoints = '!!!'
774+
seven_codepoints = any_3_nonblank_codepoints + ' ' + any_3_nonblank_codepoints
775+
a = (' ' * 243) + seven_codepoints + (' ' * 7)
776+
b = ' ' * 6 + chr(256)
777+
a.replace(seven_codepoints, b)
778+
770779
def test_replace_uses_two_way_maxcount(self):
771780
# Test that maxcount works in _two_way_count in fastsearch.h
772781
A, B = "A"*1000, "B"*1000
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix off-by-one read beyond the end of a string in string search.

Objects/stringlib/fastsearch.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ STRINGLIB(default_find)(const STRINGLIB_CHAR* s, Py_ssize_t n,
588588
continue;
589589
}
590590
/* miss: check if next character is part of pattern */
591-
if (!STRINGLIB_BLOOM(mask, ss[i+1])) {
591+
if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
592592
i = i + m;
593593
}
594594
else {
@@ -597,7 +597,7 @@ STRINGLIB(default_find)(const STRINGLIB_CHAR* s, Py_ssize_t n,
597597
}
598598
else {
599599
/* skip: check if next character is part of pattern */
600-
if (!STRINGLIB_BLOOM(mask, ss[i+1])) {
600+
if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
601601
i = i + m;
602602
}
603603
}
@@ -661,7 +661,7 @@ STRINGLIB(adaptive_find)(const STRINGLIB_CHAR* s, Py_ssize_t n,
661661
}
662662
}
663663
/* miss: check if next character is part of pattern */
664-
if (!STRINGLIB_BLOOM(mask, ss[i+1])) {
664+
if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
665665
i = i + m;
666666
}
667667
else {
@@ -670,7 +670,7 @@ STRINGLIB(adaptive_find)(const STRINGLIB_CHAR* s, Py_ssize_t n,
670670
}
671671
else {
672672
/* skip: check if next character is part of pattern */
673-
if (!STRINGLIB_BLOOM(mask, ss[i+1])) {
673+
if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
674674
i = i + m;
675675
}
676676
}

0 commit comments

Comments
 (0)