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>
pull/16185/head
Urval Kheni 2 months ago committed by Victor Julien
parent c608165c04
commit b475cc25b6

@ -26,37 +26,46 @@
#include "util-unittest.h" #include "util-unittest.h"
#include "util-memrchr.h" #include "util-memrchr.h"
#ifndef HAVE_MEMRCHR #if !defined(HAVE_MEMRCHR) || defined(UNITTESTS)
void *memrchr (const void *s, int c, size_t n) 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) { while (p > (const unsigned char *)s) {
if (*end == (char)c) p--;
return (void *)end; if (*p == uc)
end--; return (void *)p;
} }
return NULL; return NULL;
} }
#endif
#ifndef HAVE_MEMRCHR
void *memrchr(const void *s, int c, size_t n)
{
return SCMemrchrFallback(s, c, n);
}
#endif /* HAVE_MEMRCHR */ #endif /* HAVE_MEMRCHR */
#ifdef UNITTESTS #ifdef UNITTESTS
static int MemrchrTest01 (void) static int MemrchrTest01 (void)
{ {
const char *haystack = "abcabc"; char buf[] = { 'x', 'y', 'z' };
char needle = 'b'; char one_byte[] = { 'q' };
char dup[] = { 'a', 'b', 'a' };
char *ptr = memrchr(haystack, needle, strlen(haystack)); unsigned char high_byte[] = { 0x80, 'x', 0x80 };
if (ptr == NULL)
return 0;
if (strlen(ptr) != 2)
return 0;
if (strcmp(ptr, "bc") != 0) FAIL_IF(SCMemrchrFallback(buf, 'x', sizeof(buf)) != &buf[0]);
return 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 #endif

Loading…
Cancel
Save