From b475cc25b6c1761d56608de82e69174fe8c2af65 Mon Sep 17 00:00:00 2001 From: Urval Kheni Date: Fri, 4 Sep 2026 19:00:49 +0530 Subject: [PATCH] util: fix fallback memrchr() implementation The fallback memrchr() implementation initialized the search pointer to the one-past-end position and dereferenced it before decrementing, which is undefined behavior in C. Update the implementation to decrement the pointer before dereferencing while preserving memrchr() semantics. Compare bytes using unsigned char semantics to ensure values with the high bit set are handled correctly. Refactor the fallback into a local SCMemrchrFallback() helper so it can be exercised by unit tests on platforms that provide a native memrchr() implementation. Expand the unit test to cover first, middle, last, duplicate, single-byte, zero-length, absent-element, and high-byte values. Ticket: 9010 Signed-off-by: Urval Kheni --- src/util-memrchr.c | 47 +++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/util-memrchr.c b/src/util-memrchr.c index e531f845c7..c490481b57 100644 --- a/src/util-memrchr.c +++ b/src/util-memrchr.c @@ -26,37 +26,46 @@ #include "util-unittest.h" #include "util-memrchr.h" -#ifndef HAVE_MEMRCHR -void *memrchr (const void *s, int c, size_t n) +#if !defined(HAVE_MEMRCHR) || defined(UNITTESTS) +static void *SCMemrchrFallback(const void *s, int c, size_t n) { - const char *end = s + n; + const unsigned char *p = (const unsigned char *)s + n; + const unsigned char uc = (unsigned char)c; - while (end > (const char *)s) { - if (*end == (char)c) - return (void *)end; - end--; + while (p > (const unsigned char *)s) { + p--; + if (*p == uc) + return (void *)p; } return NULL; } +#endif + +#ifndef HAVE_MEMRCHR +void *memrchr(const void *s, int c, size_t n) +{ + return SCMemrchrFallback(s, c, n); +} #endif /* HAVE_MEMRCHR */ #ifdef UNITTESTS static int MemrchrTest01 (void) { - const char *haystack = "abcabc"; - char needle = 'b'; - - char *ptr = memrchr(haystack, needle, strlen(haystack)); - if (ptr == NULL) - return 0; - - if (strlen(ptr) != 2) - return 0; + char buf[] = { 'x', 'y', 'z' }; + char one_byte[] = { 'q' }; + char dup[] = { 'a', 'b', 'a' }; + unsigned char high_byte[] = { 0x80, 'x', 0x80 }; - if (strcmp(ptr, "bc") != 0) - return 0; + FAIL_IF(SCMemrchrFallback(buf, 'x', sizeof(buf)) != &buf[0]); + FAIL_IF(SCMemrchrFallback(buf, 'z', sizeof(buf)) != &buf[2]); + FAIL_IF(SCMemrchrFallback(buf, 'y', sizeof(buf)) != &buf[1]); + FAIL_IF(SCMemrchrFallback(buf, 'a', sizeof(buf)) != NULL); + FAIL_IF(SCMemrchrFallback(one_byte, 'q', sizeof(one_byte)) != &one_byte[0]); + FAIL_IF(SCMemrchrFallback(one_byte, 'q', 0) != NULL); + FAIL_IF(SCMemrchrFallback(dup, 'a', sizeof(dup)) != &dup[2]); + FAIL_IF(SCMemrchrFallback(high_byte, 0x80, sizeof(high_byte)) != &high_byte[2]); - return 1; + PASS; } #endif