[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