[libc-commits] [libc] [libc] Hide the object from the clang_vector string loads (PR #236612)
Mike Lothian via libc-commits
libc-commits at lists.llvm.org
Thu Oct 29 12:10:21 PDT 2026
https://github.com/FireBurn updated https://github.com/llvm/llvm-project/pull/236612
>From cdbaeaea9c3aca6bc8220bc49c1f94f74532e6a6 Mon Sep 17 00:00:00 2001
From: Mike Lothian <mike at fireburn.co.uk>
Date: Thu, 29 Oct 2026 00:34:06 +0000
Subject: [PATCH] [libc] Read known objects bytewise in the clang_vector string
loads
string_length and find_first_character load the whole aligned vector
around the string, which reads outside the object on purpose. When a
call is inlined with a known array, as under LTO in the unit tests, the
compiler sees the bytes outside the array as undefined and returns
whatever it likes: strlen gave 30, 48 or 38 for a six character string
built with -O3 -flto=thin. Use a bytewise loop when
__builtin_object_size knows the object, which costs nothing for the
common case of an unknown pointer
Assisted-by: Claude
---
.../memory_utils/generic/inline_strlen.h | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/libc/src/string/memory_utils/generic/inline_strlen.h b/libc/src/string/memory_utils/generic/inline_strlen.h
index 833ff9fbcbf80a..2c6fc6cd7bfebf 100644
--- a/libc/src/string/memory_utils/generic/inline_strlen.h
+++ b/libc/src/string/memory_utils/generic/inline_strlen.h
@@ -28,6 +28,17 @@ LIBC_INLINE constexpr cpp::simd_mask<byte_ty> shift_mask(cpp::simd_mask<char> m,
LIBC_NO_SANITIZE_OOB_ACCESS LIBC_INLINE size_t string_length(const char *src) {
constexpr cpp::simd<char> null_byte = cpp::splat('\0');
+ // The vector loads below read outside the string on purpose. That is only
+ // sound when the compiler cannot see the object, since it treats a read
+ // outside a known object as undefined. Once a call is inlined on a known
+ // array, as under LTO, the size is known, so read it bytewise.
+ if (__builtin_object_size(src, 0) != static_cast<size_t>(-1)) {
+ size_t length = 0;
+ while (src[length])
+ ++length;
+ return length;
+ }
+
size_t alignment = alignof(cpp::simd<char>);
const cpp::simd<char> *aligned = reinterpret_cast<const cpp::simd<char> *>(
__builtin_align_down(src, alignment));
@@ -61,6 +72,14 @@ find_first_character(const unsigned char *s, unsigned char c, size_t n) {
using Mask = cpp::simd_mask<char>;
Vector c_byte = c;
+ // See string_length.
+ if (__builtin_object_size(s, 0) != static_cast<size_t>(-1)) {
+ for (size_t i = 0; i < n; ++i)
+ if (s[i] == c)
+ return const_cast<unsigned char *>(s) + i;
+ return nullptr;
+ }
+
size_t alignment = alignof(Vector);
const Vector *aligned =
reinterpret_cast<const Vector *>(__builtin_align_down(s, alignment));
More information about the libc-commits
mailing list