Skip to content

Commit 348e22c

Browse files
[3.14] gh-127971: fix off-by-one read beyond the end of a string during search (GH-132574) (#136628)
gh-127971: fix off-by-one read beyond the end of a string during search (GH-132574) (cherry picked from commit 85ec3b3) Co-authored-by: Duane Griffin <duaneg@dghda.com>
1 parent ed1e0cd commit 348e22c

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
@@ -595,7 +595,7 @@ STRINGLIB(default_find)(const STRINGLIB_CHAR* s, Py_ssize_t n,
595595
continue;
596596
}
597597
/* miss: check if next character is part of pattern */
598-
if (!STRINGLIB_BLOOM(mask, ss[i+1])) {
598+
if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599599
i = i + m;
600600
}
601601
else {
@@ -604,7 +604,7 @@ STRINGLIB(default_find)(const STRINGLIB_CHAR* s, Py_ssize_t n,
604604
}
605605
else {
606606
/* skip: check if next character is part of pattern */
607-
if (!STRINGLIB_BLOOM(mask, ss[i+1])) {
607+
if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608608
i = i + m;
609609
}
610610
}
@@ -668,7 +668,7 @@ STRINGLIB(adaptive_find)(const STRINGLIB_CHAR* s, Py_ssize_t n,
668668
}
669669
}
670670
/* miss: check if next character is part of pattern */
671-
if (!STRINGLIB_BLOOM(mask, ss[i+1])) {
671+
if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
672672
i = i + m;
673673
}
674674
else {
@@ -677,7 +677,7 @@ STRINGLIB(adaptive_find)(const STRINGLIB_CHAR* s, Py_ssize_t n,
677677
}
678678
else {
679679
/* skip: check if next character is part of pattern */
680-
if (!STRINGLIB_BLOOM(mask, ss[i+1])) {
680+
if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
681681
i = i + m;
682682
}
683683
}

0 commit comments

Comments
 (0)