From b92057584f09d442f27b9177b12fe6fdf36ddbaf Mon Sep 17 00:00:00 2001
From: Frank Mehnert <frank.mehnert@kernkonzept.com>
Date: Tue, 7 Jan 2025 13:09:50 +0100
Subject: fix possible overflow in pointer arithmetics strnlen()

It is undefined behavior to compare two pointers belonging to different
objects. This includes the case where the addition overflows. Clang-20
seems to follow this rule more eagerly and optimizes away the old test.

Fix the test by performing the addition on uintptr_t values rather than
on on char pointers.

See also https://github.com/llvm/llvm-project/issues/121909.

Signed-off-by: Marcus Haehnel <marcus.haehnel@kernkonzept.com>
---
 libc/string/generic/strnlen.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

(limited to 'libc/string/generic/strnlen.c')

diff --git a/libc/string/generic/strnlen.c b/libc/string/generic/strnlen.c
index 4d4cde84f..82d4122ec 100644
--- a/libc/string/generic/strnlen.c
+++ b/libc/string/generic/strnlen.c
@@ -29,15 +29,17 @@
    '\0' terminator is found in that many characters, return MAXLEN.  */
 size_t strnlen (const char *str, size_t maxlen)
 {
-  const char *char_ptr, *end_ptr = str + maxlen;
+  const char *char_ptr, *end_ptr;
   const unsigned long int *longword_ptr;
   unsigned long int longword, himagic, lomagic;
 
   if (maxlen == 0)
     return 0;
 
-  if (__builtin_expect (end_ptr < str, 0))
+  if (__builtin_expect ((uintptr_t)str + maxlen < (uintptr_t)str, 0))
     end_ptr = (const char *) ~0UL;
+  else
+    end_ptr = str + maxlen;
 
   /* Handle the first few characters by reading one character at a time.
      Do this until CHAR_PTR is aligned on a longword boundary.  */
-- 
cgit v1.2.3