[libc-commits] [libc] [libc] Don't read memory in vector find_first_character if n is 0 (PR #235289)
via libc-commits
libc-commits at lists.llvm.org
Sat Oct 24 05:39:52 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: Fabian Meumertzheim (fmeum)
<details>
<summary>Changes</summary>
The vectorized `find_first_character` implementations (`clang_vector` and the x86_64 `arch_vector`) loaded the aligned block containing the start pointer before checking the length. With a length of zero, the pointer doesn't have to be dereferenceable, so `memchr(p, c, 0)` and `strnlen(p, 0)` crashed if `p` was the start of an inaccessible page.
The new test covers all implementations, since no configuration selects the vectorized ones by default. On aarch64 Linux, it segfaults without the fix and passes with it. The x86_64 changes were only compiled, not run.
Assisted-by: Claude Code (Claude Opus 5.5)
---
Full diff: https://github.com/llvm/llvm-project/pull/235289.diff
3 Files Affected:
- (modified) libc/src/string/memory_utils/generic/inline_strlen.h (+4)
- (modified) libc/src/string/memory_utils/x86_64/inline_strlen.h (+4)
- (modified) libc/test/src/strings/wide_read_memory_test.cpp (+21)
``````````diff
diff --git a/libc/src/string/memory_utils/generic/inline_strlen.h b/libc/src/string/memory_utils/generic/inline_strlen.h
index 833ff9fbcbf80a..2758f97c58cc55 100644
--- a/libc/src/string/memory_utils/generic/inline_strlen.h
+++ b/libc/src/string/memory_utils/generic/inline_strlen.h
@@ -57,6 +57,10 @@ LIBC_INLINE static void *calculate_find_first_character_return(
LIBC_NO_SANITIZE_OOB_ACCESS LIBC_INLINE static void *
find_first_character(const unsigned char *s, unsigned char c, size_t n) {
+ // s doesn't have to be dereferenceable if there is nothing to search.
+ if (n == 0)
+ return nullptr;
+
using Vector = cpp::simd<char>;
using Mask = cpp::simd_mask<char>;
Vector c_byte = c;
diff --git a/libc/src/string/memory_utils/x86_64/inline_strlen.h b/libc/src/string/memory_utils/x86_64/inline_strlen.h
index 0343e22f3e58e3..a3d3eade0d4522 100644
--- a/libc/src/string/memory_utils/x86_64/inline_strlen.h
+++ b/libc/src/string/memory_utils/x86_64/inline_strlen.h
@@ -59,6 +59,10 @@ template <typename Vector, typename Mask,
Mask (*CompareAndMask)(const Vector *, char)>
LIBC_NO_SANITIZE_OOB_ACCESS LIBC_INLINE static void *
find_first_character_vector(const unsigned char *s, unsigned char c, size_t n) {
+ // s doesn't have to be dereferenceable if there is nothing to search.
+ if (n == 0)
+ return nullptr;
+
uintptr_t misalign_bytes = reinterpret_cast<uintptr_t>(s) % sizeof(Vector);
const Vector *block_ptr =
diff --git a/libc/test/src/strings/wide_read_memory_test.cpp b/libc/test/src/strings/wide_read_memory_test.cpp
index 7b173d479dc9db..c146901fb3732f 100644
--- a/libc/test/src/strings/wide_read_memory_test.cpp
+++ b/libc/test/src/strings/wide_read_memory_test.cpp
@@ -40,6 +40,7 @@ using TwoKilobyteBuffer = cpp::array<char, 2048>;
static constexpr unsigned long kLargestTestVectorSize = 512;
class LlvmLibcWideAccessMemoryTest : public testing::Test {
+protected:
char *page0_;
char *page1_;
char *page2_;
@@ -99,6 +100,26 @@ TEST_F(LlvmLibcWideAccessMemoryTest, StringLength) {
});
}
+TEST_F(LlvmLibcWideAccessMemoryTest, FindFirstCharZeroLength) {
+ // All implementations, since the configured one is usually not vectorized.
+ static constexpr void *(*kImpls[])(const unsigned char *, unsigned char,
+ size_t) = {
+ internal::element::find_first_character,
+ internal::word::find_first_character,
+#if LIBC_HAS_VECTOR_TYPE
+ clang_vector::find_first_character,
+#endif
+#ifdef LIBC_TARGET_ARCH_IS_X86
+ internal::arch_vector::find_first_character,
+#endif
+ };
+ // A zero-length search must not read the start of an inaccessible page.
+ for (auto find_first_character : kImpls)
+ ASSERT_EQ(reinterpret_cast<const void *>(find_first_character(
+ reinterpret_cast<const unsigned char *>(page2_), 'a', 0)),
+ nullptr);
+}
+
TEST_F(LlvmLibcWideAccessMemoryTest, FindFirstChar) {
// 1.5 k long vector of a's.
TwoKilobyteBuffer buf;
``````````
</details>
https://github.com/llvm/llvm-project/pull/235289
More information about the libc-commits
mailing list