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 <kheniurval777@gmail.com>
(cherry picked from commit b475cc25b6)
pull/16202/head
Urval Kheni 1 week ago committed by Victor Julien
parent a2aa325f7f
commit 8b0775f557

@ -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

Loading…
Cancel
Save