Skip to content

Commit 7ff8a51

Browse files
[libc] Fix stale char_ptr for find_first_character_wide read (llvm#166594)
On exit from the loop, char_ptr had not been updated to match block_ptr, resulting in erroneous results. Moving all updates out of the loop fixes that. Adjust derefences to always be inside bounds checks.
1 parent 277bd09 commit 7ff8a51

File tree

2 files changed

+14
-9
lines changed

2 files changed

+14
-9
lines changed

libc/src/string/string_utils.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,27 +127,27 @@ find_first_character_wide_read(const unsigned char *src, unsigned char ch,
127127
size_t cur = 0;
128128

129129
// Step 1: read 1 byte at a time to align to block size
130-
for (; reinterpret_cast<uintptr_t>(char_ptr) % sizeof(Word) != 0 && cur < n;
131-
++char_ptr, ++cur) {
130+
for (; cur < n && reinterpret_cast<uintptr_t>(char_ptr) % sizeof(Word) != 0;
131+
++cur, ++char_ptr) {
132132
if (*char_ptr == ch)
133133
return const_cast<unsigned char *>(char_ptr);
134134
}
135135

136136
const Word ch_mask = repeat_byte<Word>(ch);
137137

138138
// Step 2: read blocks
139-
for (const Word *block_ptr = reinterpret_cast<const Word *>(char_ptr);
140-
!has_zeroes<Word>((*block_ptr) ^ ch_mask) && cur < n;
141-
++block_ptr, cur += sizeof(Word)) {
142-
char_ptr = reinterpret_cast<const unsigned char *>(block_ptr);
143-
}
139+
const Word *block_ptr = reinterpret_cast<const Word *>(char_ptr);
140+
for (; cur < n && !has_zeroes<Word>((*block_ptr) ^ ch_mask);
141+
cur += sizeof(Word), ++block_ptr)
142+
;
143+
char_ptr = reinterpret_cast<const unsigned char *>(block_ptr);
144144

145145
// Step 3: find the match in the block
146-
for (; *char_ptr != ch && cur < n; ++char_ptr, ++cur) {
146+
for (; cur < n && *char_ptr != ch; ++cur, ++char_ptr) {
147147
;
148148
}
149149

150-
if (*char_ptr != ch || cur >= n)
150+
if (cur >= n || *char_ptr != ch)
151151
return static_cast<void *>(nullptr);
152152

153153
return const_cast<unsigned char *>(char_ptr);

libc/test/src/string/memchr_test.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ const char *call_memchr(const void *src, int c, size_t size) {
2121
return reinterpret_cast<const char *>(LIBC_NAMESPACE::memchr(src, c, size));
2222
}
2323

24+
TEST(LlvmLibcMemChrTest, WideReadMultiIteration) {
25+
const char *src = "abcdefghijklmnopqrst$\n";
26+
ASSERT_STREQ(call_memchr(src, '$', 22), "$\n");
27+
}
28+
2429
TEST(LlvmLibcMemChrTest, FindsCharacterAfterNullTerminator) {
2530
// memchr should continue searching after a null terminator.
2631
const size_t size = 5;

0 commit comments

Comments
 (0)