summaryrefslogtreecommitdiff
path: root/libc/string/generic/strnlen.c
diff options
context:
space:
mode:
authorFrank Mehnert <frank.mehnert@kernkonzept.com>2025-01-07 13:09:50 +0100
committerWaldemar Brodkorb <wbx@openadk.org>2025-01-07 13:28:17 +0100
commitb92057584f09d442f27b9177b12fe6fdf36ddbaf (patch)
tree10f251b3ce388177ba027e5121f42003ab98aad5 /libc/string/generic/strnlen.c
parent1de51fb74b68a94207384021a878c1a3035d2aff (diff)
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>
Diffstat (limited to 'libc/string/generic/strnlen.c')
-rw-r--r--libc/string/generic/strnlen.c6
1 files changed, 4 insertions, 2 deletions
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. */