This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git

commit 0b3049b6ca86d8f9a7bc5dcb75d6cfad13770d0a
Author: anjiahao <[email protected]>
AuthorDate: Wed Jul 1 16:02:13 2026 +0800

    testing/libc/arch_libc: Add strchrnul test and sweep size boundaries.
    
    Add test_strchrnul() and speed_strchrnul(), selected by the new
    CONFIG_TESTING_ARCH_LIBC_STRCHRNUL option, covering the hit, miss and
    NUL cases.
    
    Sweep alignment 0..7 and the boundary sizes {0, 1, 7, 8, 9, 15, 16, 17,
    31, 32, 33, 63, 64, 65, 127, 128, 129, 255, 256, 257} in the scan
    function tests (memcmp, memchr, strlen, strcmp, strchr, strncmp,
    strnlen, strrchr) and in memmove.  Those sizes sit on the 8 and 16 byte
    chunk edges and on the sub-word tails, so vectorized (NEON/MVE) and
    word-at-a-time implementations are stressed exactly at their alignment
    and size boundaries instead of only at "nice" lengths.  memmove is
    additionally exercised across four overlap layouts: forward, backward,
    contained and adjacent.
    
    Impact: test only, selected by CONFIG_TESTING_ARCH_LIBC (default n).
    
    Testing: built and ran qemu-armv7a:nsh (Cortex-A7, generic C
    implementation) and sim:nsh on Linux x86_64 (Ubuntu 24.04, gcc 13.3.0)
    with CONFIG_TESTING_ARCH_LIBC=y.  All 16 enabled functions report
    PASSED and "arch_libc_test Passed".  These tests pass against the
    generic C routines, which establishes the correctness baseline before
    architecture optimized assembly is introduced.
    
    Signed-off-by: anjiahao <[email protected]>
---
 testing/libc/arch_libc/Kconfig               |   4 +
 testing/libc/arch_libc/arch_libc_test_main.c | 685 ++++++++++++++++++++-------
 2 files changed, 507 insertions(+), 182 deletions(-)

diff --git a/testing/libc/arch_libc/Kconfig b/testing/libc/arch_libc/Kconfig
index b0aba69a5..97885ea40 100644
--- a/testing/libc/arch_libc/Kconfig
+++ b/testing/libc/arch_libc/Kconfig
@@ -72,6 +72,10 @@ config TESTING_ARCH_LIBC_STRRCHR
        bool "test strrchr"
        default y
 
+config TESTING_ARCH_LIBC_STRCHRNUL
+       bool "test strchrnul"
+       default y
+
 config TESTING_ARCH_LIBC_PROGNAME
        string "Program name"
        default "arch_libctest"
diff --git a/testing/libc/arch_libc/arch_libc_test_main.c 
b/testing/libc/arch_libc/arch_libc_test_main.c
index 67f8e6cb3..b840ab815 100644
--- a/testing/libc/arch_libc/arch_libc_test_main.c
+++ b/testing/libc/arch_libc/arch_libc_test_main.c
@@ -34,12 +34,13 @@
 #include <errno.h>
 #include <nuttx/debug.h>
 #include <assert.h>
+#include <sys/param.h>
 
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
 
-#define TEST_BUF_SIZE  256
+#define TEST_BUF_SIZE  512
 #define TEST_REPEAT    100
 #define MAX_ALIGN      16
 
@@ -51,6 +52,18 @@ static char g_buf1[TEST_BUF_SIZE + MAX_ALIGN];
 static char g_buf2[TEST_BUF_SIZE + MAX_ALIGN];
 static volatile uintptr_t g_sink;
 
+/* Boundary sizes that exercise 8-byte and 16-byte chunk edges and sub-word
+ * tails, so that vectorized (NEON/MVE) and word-at-a-time paths are stressed
+ * at their alignment and size boundaries.  Unused if every test that sweeps
+ * these sizes is disabled.
+ */
+
+static const int unused_data g_boundary_sizes[] =
+{
+  0, 1, 7, 8, 9, 15, 16, 17, 31, 32, 33,
+  63, 64, 65, 127, 128, 129, 255, 256, 257
+};
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -121,36 +134,77 @@ static void speed_memcpy(void)
 #ifdef CONFIG_TESTING_ARCH_LIBC_MEMMOVE
 static int test_memmove(void)
 {
+  int align;
+  int si;
   int size;
   int fail = 0;
 
   printf("Testing memmove...\n");
 
-  /* Test overlapping forward */
+  /* Sweep alignment 0..7 and boundary sizes, across four overlap layouts:
+   *  forward  : dst = src + 8        (dst > src, backward copy internally)
+   *  backward : dst = src - 8        (dst < src, forward copy internally)
+   *  contained: dst = src + size/2   (full overlap region)
+   *  adjacent : dst = src + size     (no overlap, tail-to-tail)
+   */
 
-  for (size = 1; size <= 64; size++)
+  for (align = 0; align < 8; align++)
     {
-      fill_pattern(g_buf1, size + 16);
-      memcpy(g_buf2, g_buf1, size + 16);
-      memmove(g_buf1 + 8, g_buf1, size);
-      if (memcmp(g_buf1 + 8, g_buf2, size) != 0)
+      for (si = 0; si < nitems(g_boundary_sizes); si++)
         {
-          printf("  FAIL forward: size=%d\n", size);
-          fail++;
-        }
-    }
+          size = g_boundary_sizes[si];
+          if (size < 1)
+            {
+              continue;
+            }
 
-  /* Test overlapping backward */
+          /* Forward overlap: dst = src + 8 */
 
-  for (size = 1; size <= 64; size++)
-    {
-      fill_pattern(g_buf1 + 8, size);
-      memcpy(g_buf2, g_buf1 + 8, size);
-      memmove(g_buf1, g_buf1 + 8, size);
-      if (memcmp(g_buf1, g_buf2, size) != 0)
-        {
-          printf("  FAIL backward: size=%d\n", size);
-          fail++;
+          fill_pattern(g_buf1 + align + 8, size);
+          memcpy(g_buf2 + align + 8, g_buf1 + align + 8, size);
+          memmove(g_buf1 + align + 16, g_buf1 + align + 8, size);
+          if (memcmp(g_buf1 + align + 16, g_buf2 + align + 8, size) != 0)
+            {
+              printf("  FAIL forward: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* Backward overlap: dst = src - 8 */
+
+          fill_pattern(g_buf1 + align + 16, size);
+          memcpy(g_buf2 + align + 16, g_buf1 + align + 16, size);
+          memmove(g_buf1 + align + 8, g_buf1 + align + 16, size);
+          if (memcmp(g_buf1 + align + 8, g_buf2 + align + 16, size) != 0)
+            {
+              printf("  FAIL backward: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* Contained overlap: dst = src + size/2 */
+
+          fill_pattern(g_buf1 + align + 32, size);
+          memcpy(g_buf2 + align + 32, g_buf1 + align + 32, size);
+          memmove(g_buf1 + align + 32 + size / 2,
+                  g_buf1 + align + 32, size);
+          if (memcmp(g_buf1 + align + 32 + size / 2,
+                     g_buf2 + align + 32, size) != 0)
+            {
+              printf("  FAIL contained: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* Adjacent (no overlap): dst = src + size */
+
+          fill_pattern(g_buf1 + align + 64, size);
+          memcpy(g_buf2 + align + 64, g_buf1 + align + 64, size);
+          memmove(g_buf1 + align + 64 + size,
+                  g_buf1 + align + 64, size);
+          if (memcmp(g_buf1 + align + 64 + size,
+                     g_buf2 + align + 64, size) != 0)
+            {
+              printf("  FAIL adjacent: align=%d size=%d\n", align, size);
+              fail++;
+            }
         }
     }
 
@@ -238,32 +292,59 @@ static void speed_memset(void)
 #ifdef CONFIG_TESTING_ARCH_LIBC_MEMCMP
 static int test_memcmp(void)
 {
+  int align;
+  int si;
   int size;
   int fail = 0;
 
   printf("Testing memcmp...\n");
-  for (size = 1; size <= 128; size++)
+  for (align = 0; align < 8; align++)
     {
-      fill_pattern(g_buf1, size);
-      fill_pattern(g_buf2, size);
-      if (memcmp(g_buf1, g_buf2, size) != 0)
+      for (si = 0; si < nitems(g_boundary_sizes); si++)
         {
-          printf("  FAIL equal: size=%d\n", size);
-          fail++;
-        }
+          size = g_boundary_sizes[si];
+          if (size < 1)
+            {
+              continue;
+            }
 
-      g_buf2[size - 1] = '~';
-      if (memcmp(g_buf1, g_buf2, size) >= 0)
-        {
-          printf("  FAIL less: size=%d\n", size);
-          fail++;
-        }
+          fill_pattern(g_buf1 + align, size);
+          fill_pattern(g_buf2 + align, size);
 
-      g_buf2[size - 1] = 0;
-      if (memcmp(g_buf1, g_buf2, size) <= 0)
-        {
-          printf("  FAIL greater: size=%d\n", size);
-          fail++;
+          /* Equal */
+
+          if (memcmp(g_buf1 + align, g_buf2 + align, size) != 0)
+            {
+              printf("  FAIL equal: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* Last byte less */
+
+          g_buf2[align + size - 1] = '~';
+          if (memcmp(g_buf1 + align, g_buf2 + align, size) >= 0)
+            {
+              printf("  FAIL less: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* Last byte greater */
+
+          g_buf2[align + size - 1] = 0;
+          if (memcmp(g_buf1 + align, g_buf2 + align, size) <= 0)
+            {
+              printf("  FAIL greater: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* First byte differs */
+
+          g_buf2[align] = g_buf1[align] + 1;
+          if (memcmp(g_buf1 + align, g_buf2 + align, size) >= 0)
+            {
+              printf("  FAIL first: align=%d size=%d\n", align, size);
+              fail++;
+            }
         }
     }
 
@@ -298,31 +379,68 @@ static void speed_memcmp(void)
 #ifdef CONFIG_TESTING_ARCH_LIBC_MEMCHR
 static int test_memchr(void)
 {
+  int align;
+  int si;
   int size;
   int fail = 0;
   FAR void *p;
 
   printf("Testing memchr...\n");
-  for (size = 1; size <= 128; size++)
+  for (align = 0; align < 8; align++)
     {
-      fill_pattern(g_buf1, size);
+      for (si = 0; si < nitems(g_boundary_sizes); si++)
+        {
+          size = g_boundary_sizes[si];
+          if (size < 1)
+            {
+              continue;
+            }
 
-      /* Find last char */
+          fill_pattern(g_buf1 + align, size);
 
-      p = memchr(g_buf1, g_buf1[size - 1], size);
-      if (p == NULL)
-        {
-          printf("  FAIL found: size=%d\n", size);
-          fail++;
-        }
+          /* Find first char (pattern starts with 'A' at align) */
 
-      /* Not found */
+          p = memchr(g_buf1 + align, g_buf1[align], size);
+          if (p != g_buf1 + align)
+            {
+              printf("  FAIL first: align=%d size=%d\n", align, size);
+              fail++;
+            }
 
-      p = memchr(g_buf1, 0xff, size);
-      if (p != NULL)
-        {
-          printf("  FAIL notfound: size=%d\n", size);
-          fail++;
+          /* Find a unique marker placed at the last position */
+
+          fill_pattern(g_buf1 + align, size);
+          g_buf1[align + size - 1] = 0x7e;
+          p = memchr(g_buf1 + align, 0x7e, size);
+          if (p != g_buf1 + align + size - 1)
+            {
+              printf("  FAIL last: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* Find a unique marker placed in the middle */
+
+          if (size > 2)
+            {
+              fill_pattern(g_buf1 + align, size);
+              g_buf1[align + size / 2] = 0x7e;
+              p = memchr(g_buf1 + align, 0x7e, size);
+              if (p != g_buf1 + align + size / 2)
+                {
+                  printf("  FAIL mid: align=%d size=%d\n", align, size);
+                  fail++;
+                }
+            }
+
+          /* Not found (full scan) */
+
+          fill_pattern(g_buf1 + align, size);
+          p = memchr(g_buf1 + align, 0xff, size);
+          if (p != NULL)
+            {
+              printf("  FAIL notfound: align=%d size=%d\n", align, size);
+              fail++;
+            }
         }
     }
 
@@ -356,18 +474,25 @@ static void speed_memchr(void)
 #ifdef CONFIG_TESTING_ARCH_LIBC_STRLEN
 static int test_strlen(void)
 {
+  int align;
+  int si;
   int size;
   int fail = 0;
 
   printf("Testing strlen...\n");
-  for (size = 0; size <= 128; size++)
+  for (align = 0; align < 8; align++)
     {
-      fill_pattern(g_buf1, size);
-      g_buf1[size] = '\0';
-      if ((int)strlen(g_buf1) != size)
+      for (si = 0; si < nitems(g_boundary_sizes); si++)
         {
-          printf("  FAIL: size=%d got=%d\n", size, (int)strlen(g_buf1));
-          fail++;
+          size = g_boundary_sizes[si];
+          fill_pattern(g_buf1 + align, size);
+          g_buf1[align + size] = '\0';
+          if ((int)strlen(g_buf1 + align) != size)
+            {
+              printf("  FAIL: align=%d size=%d got=%d\n", align, size,
+                     (int)strlen(g_buf1 + align));
+              fail++;
+            }
         }
     }
 
@@ -402,28 +527,54 @@ static void speed_strlen(void)
 #ifdef CONFIG_TESTING_ARCH_LIBC_STRCMP
 static int test_strcmp(void)
 {
+  int align;
+  int si;
   int size;
   int fail = 0;
 
   printf("Testing strcmp...\n");
-  for (size = 1; size <= 128; size++)
+  for (align = 0; align < 8; align++)
     {
-      fill_pattern(g_buf1, size);
-      g_buf1[size] = '\0';
-      fill_pattern(g_buf2, size);
-      g_buf2[size] = '\0';
-      if (strcmp(g_buf1, g_buf2) != 0)
+      for (si = 0; si < nitems(g_boundary_sizes); si++)
         {
-          printf("  FAIL equal: size=%d\n", size);
-          fail++;
-        }
+          size = g_boundary_sizes[si];
+          if (size < 1)
+            {
+              continue;
+            }
 
-      g_buf2[size - 1] = '~';
-      g_buf2[size] = '\0';
-      if (strcmp(g_buf1, g_buf2) >= 0)
-        {
-          printf("  FAIL less: size=%d\n", size);
-          fail++;
+          fill_pattern(g_buf1 + align, size);
+          g_buf1[align + size] = '\0';
+          fill_pattern(g_buf2 + align, size);
+          g_buf2[align + size] = '\0';
+
+          /* Equal */
+
+          if (strcmp(g_buf1 + align, g_buf2 + align) != 0)
+            {
+              printf("  FAIL equal: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* Last byte less */
+
+          g_buf2[align + size - 1] = '~';
+          if (strcmp(g_buf1 + align, g_buf2 + align) >= 0)
+            {
+              printf("  FAIL less: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* First byte differs */
+
+          fill_pattern(g_buf2 + align, size);
+          g_buf2[align + size] = '\0';
+          g_buf2[align] = g_buf1[align] + 1;
+          if (strcmp(g_buf1 + align, g_buf2 + align) >= 0)
+            {
+              printf("  FAIL first: align=%d size=%d\n", align, size);
+              fail++;
+            }
         }
     }
 
@@ -512,41 +663,66 @@ static void speed_strcpy(void)
 #ifdef CONFIG_TESTING_ARCH_LIBC_STRCHR
 static int test_strchr(void)
 {
+  int align;
+  int si;
   int size;
   int fail = 0;
   FAR char *p;
 
   printf("Testing strchr...\n");
-  for (size = 1; size <= 128; size++)
+  for (align = 0; align < 8; align++)
     {
-      fill_pattern(g_buf1, size);
-      g_buf1[size] = '\0';
+      for (si = 0; si < nitems(g_boundary_sizes); si++)
+        {
+          size = g_boundary_sizes[si];
+          if (size < 1)
+            {
+              continue;
+            }
 
-      /* Find first char */
+          fill_pattern(g_buf1 + align, size);
+          g_buf1[align + size] = '\0';
 
-      p = strchr(g_buf1, g_buf1[0]);
-      if (p != g_buf1)
-        {
-          printf("  FAIL first: size=%d\n", size);
-          fail++;
-        }
+          /* Find first char (pattern starts with 'A' at align) */
 
-      /* Find NUL */
+          p = strchr(g_buf1 + align, g_buf1[align]);
+          if (p != g_buf1 + align)
+            {
+              printf("  FAIL first: align=%d size=%d\n", align, size);
+              fail++;
+            }
 
-      p = strchr(g_buf1, '\0');
-      if (p != g_buf1 + size)
-        {
-          printf("  FAIL nul: size=%d\n", size);
-          fail++;
-        }
+          /* Find a unique marker placed at the last position */
 
-      /* Not found */
+          fill_pattern(g_buf1 + align, size);
+          g_buf1[align + size] = '\0';
+          g_buf1[align + size - 1] = 0x7e;
+          p = strchr(g_buf1 + align, 0x7e);
+          if (p != g_buf1 + align + size - 1)
+            {
+              printf("  FAIL last: align=%d size=%d\n", align, size);
+              fail++;
+            }
 
-      p = strchr(g_buf1, 0x01);
-      if (p != NULL)
-        {
-          printf("  FAIL notfound: size=%d\n", size);
-          fail++;
+          /* Find NUL terminator */
+
+          fill_pattern(g_buf1 + align, size);
+          g_buf1[align + size] = '\0';
+          p = strchr(g_buf1 + align, '\0');
+          if (p != g_buf1 + align + size)
+            {
+              printf("  FAIL nul: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* Not found (full scan) */
+
+          p = strchr(g_buf1 + align, 0x01);
+          if (p != NULL)
+            {
+              printf("  FAIL notfound: align=%d size=%d\n", align, size);
+              fail++;
+            }
         }
     }
 
@@ -581,51 +757,72 @@ static void speed_strchr(void)
 #ifdef CONFIG_TESTING_ARCH_LIBC_STRNCMP
 static int test_strncmp(void)
 {
+  int align;
+  int si;
   int size;
   int fail = 0;
 
   printf("Testing strncmp...\n");
-  for (size = 1; size <= 128; size++)
+  for (align = 0; align < 8; align++)
     {
-      fill_pattern(g_buf1, size);
-      g_buf1[size] = '\0';
-      fill_pattern(g_buf2, size);
-      g_buf2[size] = '\0';
+      for (si = 0; si < nitems(g_boundary_sizes); si++)
+        {
+          size = g_boundary_sizes[si];
+          if (size < 1)
+            {
+              continue;
+            }
 
-      /* Equal within n */
+          fill_pattern(g_buf1 + align, size);
+          g_buf1[align + size] = '\0';
+          fill_pattern(g_buf2 + align, size);
+          g_buf2[align + size] = '\0';
 
-      if (strncmp(g_buf1, g_buf2, size) != 0)
-        {
-          printf("  FAIL equal: size=%d\n", size);
-          fail++;
-        }
+          /* Equal within n */
 
-      /* Differ at last position */
+          if (strncmp(g_buf1 + align, g_buf2 + align, size) != 0)
+            {
+              printf("  FAIL equal: align=%d size=%d\n", align, size);
+              fail++;
+            }
 
-      g_buf2[size - 1] = '~';
-      if (strncmp(g_buf1, g_buf2, size) >= 0)
-        {
-          printf("  FAIL less: size=%d\n", size);
-          fail++;
-        }
+          /* Differ at last position */
 
-      /* Equal when n is smaller */
+          g_buf2[align + size - 1] = '~';
+          if (strncmp(g_buf1 + align, g_buf2 + align, size) >= 0)
+            {
+              printf("  FAIL less: align=%d size=%d\n", align, size);
+              fail++;
+            }
 
-      fill_pattern(g_buf2, size);
-      g_buf2[size] = '\0';
-      g_buf2[size - 1] = '~';
-      if (size > 1 && strncmp(g_buf1, g_buf2, size - 1) != 0)
-        {
-          printf("  FAIL partial: size=%d\n", size);
-          fail++;
-        }
+          /* Equal when n is smaller than the difference */
+
+          fill_pattern(g_buf2 + align, size);
+          g_buf2[align + size] = '\0';
+          g_buf2[align + size - 1] = '~';
+          if (size > 1 &&
+              strncmp(g_buf1 + align, g_buf2 + align, size - 1) != 0)
+            {
+              printf("  FAIL partial: align=%d size=%d\n", align, size);
+              fail++;
+            }
 
-      /* Zero count */
+          /* n boundary: 0 and 1 (reset buf2 to match buf1 first) */
 
-      if (strncmp(g_buf1, g_buf2, 0) != 0)
-        {
-          printf("  FAIL zero: size=%d\n", size);
-          fail++;
+          fill_pattern(g_buf2 + align, size);
+          g_buf2[align + size] = '\0';
+
+          if (strncmp(g_buf1 + align, g_buf2 + align, 0) != 0)
+            {
+              printf("  FAIL zero: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          if (strncmp(g_buf1 + align, g_buf2 + align, 1) != 0)
+            {
+              printf("  FAIL one: align=%d size=%d\n", align, size);
+              fail++;
+            }
         }
     }
 
@@ -662,37 +859,52 @@ static void speed_strncmp(void)
 #ifdef CONFIG_TESTING_ARCH_LIBC_STRNLEN
 static int test_strnlen(void)
 {
+  int align;
+  int si;
   int size;
   int fail = 0;
 
   printf("Testing strnlen...\n");
-  for (size = 0; size <= 128; size++)
+  for (align = 0; align < 8; align++)
     {
-      fill_pattern(g_buf1, size);
-      g_buf1[size] = '\0';
+      for (si = 0; si < nitems(g_boundary_sizes); si++)
+        {
+          size = g_boundary_sizes[si];
+          fill_pattern(g_buf1 + align, size);
+          g_buf1[align + size] = '\0';
 
-      /* maxlen >= actual length */
+          /* maxlen >= actual length */
 
-      if ((int)strnlen(g_buf1, size + 10) != size)
-        {
-          printf("  FAIL full: size=%d\n", size);
-          fail++;
-        }
+          if ((int)strnlen(g_buf1 + align, size + 10) != size)
+            {
+              printf("  FAIL full: align=%d size=%d\n", align, size);
+              fail++;
+            }
 
-      /* maxlen < actual length */
+          /* maxlen == actual length */
 
-      if (size > 0 && (int)strnlen(g_buf1, size - 1) != size - 1)
-        {
-          printf("  FAIL trunc: size=%d\n", size);
-          fail++;
-        }
+          if ((int)strnlen(g_buf1 + align, size) != size)
+            {
+              printf("  FAIL exact: align=%d size=%d\n", align, size);
+              fail++;
+            }
 
-      /* maxlen == 0 */
+          /* maxlen < actual length */
 
-      if (strnlen(g_buf1, 0) != 0)
-        {
-          printf("  FAIL zero: size=%d\n", size);
-          fail++;
+          if (size > 0 &&
+              (int)strnlen(g_buf1 + align, size - 1) != size - 1)
+            {
+              printf("  FAIL trunc: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* maxlen == 0 */
+
+          if (strnlen(g_buf1 + align, 0) != 0)
+            {
+              printf("  FAIL zero: align=%d size=%d\n", align, size);
+              fail++;
+            }
         }
     }
 
@@ -955,53 +1167,65 @@ static void speed_strcat(void)
 #ifdef CONFIG_TESTING_ARCH_LIBC_STRRCHR
 static int test_strrchr(void)
 {
+  int align;
+  int si;
   int size;
   int fail = 0;
   FAR char *p;
 
   printf("Testing strrchr...\n");
-  for (size = 1; size <= 128; size++)
+  for (align = 0; align < 8; align++)
     {
-      fill_pattern(g_buf1, size);
-      g_buf1[size] = '\0';
+      for (si = 0; si < nitems(g_boundary_sizes); si++)
+        {
+          size = g_boundary_sizes[si];
+          if (size < 1)
+            {
+              continue;
+            }
 
-      /* Find last occurrence of first char (repeats every 26) */
+          fill_pattern(g_buf1 + align, size);
+          g_buf1[align + size] = '\0';
 
-      p = strrchr(g_buf1, 'A');
-      if (p == NULL)
-        {
-          printf("  FAIL found: size=%d\n", size);
-          fail++;
-        }
-      else
-        {
-          /* 'A' appears at 0, 26, 52, ... — last one <= size-1 */
+          /* Find last occurrence of first char (repeats every 26) */
 
-          int expected = ((size - 1) / 26) * 26;
-          if (p != g_buf1 + expected)
+          p = strrchr(g_buf1 + align, 'A');
+          if (p == NULL)
             {
-              printf("  FAIL pos: size=%d expected=%d got=%d\n",
-                     size, expected, (int)(p - g_buf1));
+              printf("  FAIL found: align=%d size=%d\n", align, size);
               fail++;
             }
-        }
+          else
+            {
+              /* 'A' appears at 0, 26, 52, ... — last one <= size-1 */
 
-      /* Find NUL */
+              int expected = ((size - 1) / 26) * 26;
+              if (p != g_buf1 + align + expected)
+                {
+                  printf("  FAIL pos: align=%d size=%d expected=%d"
+                         " got=%d\n", align, size, expected,
+                         (int)(p - (g_buf1 + align)));
+                  fail++;
+                }
+            }
 
-      p = strrchr(g_buf1, '\0');
-      if (p != g_buf1 + size)
-        {
-          printf("  FAIL nul: size=%d\n", size);
-          fail++;
-        }
+          /* Find NUL */
+
+          p = strrchr(g_buf1 + align, '\0');
+          if (p != g_buf1 + align + size)
+            {
+              printf("  FAIL nul: align=%d size=%d\n", align, size);
+              fail++;
+            }
 
-      /* Not found */
+          /* Not found (full scan) */
 
-      p = strrchr(g_buf1, 0x01);
-      if (p != NULL)
-        {
-          printf("  FAIL notfound: size=%d\n", size);
-          fail++;
+          p = strrchr(g_buf1 + align, 0x01);
+          if (p != NULL)
+            {
+              printf("  FAIL notfound: align=%d size=%d\n", align, size);
+              fail++;
+            }
         }
     }
 
@@ -1029,6 +1253,100 @@ static void speed_strrchr(void)
 }
 #endif
 
+/****************************************************************************
+ * Name: test_strchrnul
+ ****************************************************************************/
+
+#ifdef CONFIG_TESTING_ARCH_LIBC_STRCHRNUL
+static int test_strchrnul(void)
+{
+  int align;
+  int si;
+  int size;
+  int fail = 0;
+  FAR char *p;
+
+  printf("Testing strchrnul...\n");
+  for (align = 0; align < 8; align++)
+    {
+      for (si = 0; si < nitems(g_boundary_sizes); si++)
+        {
+          size = g_boundary_sizes[si];
+          if (size < 1)
+            {
+              continue;
+            }
+
+          fill_pattern(g_buf1 + align, size);
+          g_buf1[align + size] = '\0';
+
+          /* Find first char (pattern starts with 'A' at align) */
+
+          p = strchrnul(g_buf1 + align, g_buf1[align]);
+          if (p != g_buf1 + align)
+            {
+              printf("  FAIL first: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* Find a unique marker placed at the last position */
+
+          fill_pattern(g_buf1 + align, size);
+          g_buf1[align + size] = '\0';
+          g_buf1[align + size - 1] = 0x7e;
+          p = strchrnul(g_buf1 + align, 0x7e);
+          if (p != g_buf1 + align + size - 1)
+            {
+              printf("  FAIL last: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* Find NUL terminator (always succeeds) */
+
+          fill_pattern(g_buf1 + align, size);
+          g_buf1[align + size] = '\0';
+          p = strchrnul(g_buf1 + align, '\0');
+          if (p != g_buf1 + align + size)
+            {
+              printf("  FAIL nul: align=%d size=%d\n", align, size);
+              fail++;
+            }
+
+          /* Not found: must return pointer to the NUL terminator */
+
+          p = strchrnul(g_buf1 + align, 0x01);
+          if (p != g_buf1 + align + size)
+            {
+              printf("  FAIL notfound: align=%d size=%d\n", align, size);
+              fail++;
+            }
+        }
+    }
+
+  printf("strchrnul: %s\n", fail ? "FAILED" : "PASSED");
+  return fail;
+}
+
+static void speed_strchrnul(void)
+{
+  clock_t start;
+  clock_t end;
+  int i;
+
+  fill_pattern(g_buf1, 128);
+  g_buf1[128] = '\0';
+  start = perf_gettime();
+  for (i = 0; i < TEST_REPEAT; i++)
+    {
+      g_sink = (uintptr_t)strchrnul(g_buf1, g_buf1[127]);
+    }
+
+  end = perf_gettime();
+  printf("strchrnul(128) avg cycles: %ju\n",
+         (uintmax_t)(end - start) / TEST_REPEAT);
+}
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -1101,8 +1419,11 @@ int main(int argc, FAR char *argv[])
   fail += test_strrchr();
   speed_strrchr();
 #endif
+#ifdef CONFIG_TESTING_ARCH_LIBC_STRCHRNUL
+  fail += test_strchrnul();
+  speed_strchrnul();
+#endif
 
   printf("arch_libc_test %s\n", fail ? "Failed" : "Passed");
   return fail ? EXIT_FAILURE : EXIT_SUCCESS;
 }
-

Reply via email to