mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-10 23:15:18 +00:00
testing/libc/arch_libc: Cover unaligned src/dst copy paths.
test_strcpy(), test_strncpy() and test_stpcpy() applied the same offset to the source and to the destination, so both pointers always shared the same word congruence. Architecture optimized copy routines take a different code path when the two offsets differ: a byte prologue to align the destination, then either a byte fallback or a shift-merge loop that recombines two source words per store. None of that was reached by the test. Vary the source and destination offsets independently over 0..7 in those three tests, so both the equal congruence (aligned word copy) and the unequal congruence (shift-merge) paths are covered, and report both offsets on failure so a regression points at the offending combination. Also drop the ARCH_TOOLCHAIN_GNU dependency from TESTING_ARCH_LIBC. The test only uses standard C string functions and perf_gettime(), with no GNU specific construct, so it builds with non GNU toolchains such as TASKING as well. Impact: test only, selected by CONFIG_TESTING_ARCH_LIBC (default n). Dropping the ARCH_TOOLCHAIN_GNU dependency only widens the set of toolchains that may select the test, no existing configuration changes. Testing: built and ran sim:nsh on Linux x86_64 (Ubuntu 24.04, gcc 13.3.0) with CONFIG_TESTING_ARCH_LIBC=y. strcpy, strncpy and stpcpy report PASSED for all 64 offset combinations, and "arch_libc_test Passed". Assisted-by: Claude:claude-opus-5 Signed-off-by: zhangyuan29 <zhangyuan29@xiaomi.com>
This commit is contained in:
parent
7043f96fef
commit
413d2ddbc3
2 changed files with 57 additions and 30 deletions
|
|
@ -6,7 +6,6 @@
|
|||
config TESTING_ARCH_LIBC
|
||||
tristate "arch-specific libc function test"
|
||||
default n
|
||||
depends on ARCH_TOOLCHAIN_GNU
|
||||
---help---
|
||||
Enable the arch libc test
|
||||
|
||||
|
|
|
|||
|
|
@ -618,22 +618,32 @@ static void speed_strcmp(void)
|
|||
#ifdef CONFIG_TESTING_ARCH_LIBC_STRCPY
|
||||
static int test_strcpy(void)
|
||||
{
|
||||
int align;
|
||||
int size;
|
||||
int fail = 0;
|
||||
int ai;
|
||||
|
||||
printf("Testing strcpy...\n");
|
||||
for (align = 0; align < 8; align++)
|
||||
|
||||
/* ai encodes da*8+sa: sa==da keeps src/dst in the same 4-byte congruence
|
||||
* (aligned word-copy path), sa!=da forces different congruence and
|
||||
* exercises the shift-merge path; any nonzero da also hits the dst byte
|
||||
* prologue.
|
||||
*/
|
||||
|
||||
for (ai = 0; ai < 64; ai++)
|
||||
{
|
||||
int da = ai / 8;
|
||||
int sa = ai % 8;
|
||||
|
||||
for (size = 1; size <= 64; size++)
|
||||
{
|
||||
fill_pattern(g_buf1 + align, size);
|
||||
g_buf1[align + size] = '\0';
|
||||
fill_pattern(g_buf1 + sa, size);
|
||||
g_buf1[sa + size] = '\0';
|
||||
memset(g_buf2, 0, sizeof(g_buf2));
|
||||
strcpy(g_buf2 + align, g_buf1 + align);
|
||||
if (strcmp(g_buf2 + align, g_buf1 + align) != 0)
|
||||
strcpy(g_buf2 + da, g_buf1 + sa);
|
||||
if (strcmp(g_buf2 + da, g_buf1 + sa) != 0)
|
||||
{
|
||||
printf(" FAIL: align=%d size=%d\n", align, size);
|
||||
printf(" FAIL: sa=%d da=%d size=%d\n", sa, da, size);
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
|
@ -946,26 +956,34 @@ static void speed_strnlen(void)
|
|||
#ifdef CONFIG_TESTING_ARCH_LIBC_STRNCPY
|
||||
static int test_strncpy(void)
|
||||
{
|
||||
int align;
|
||||
int size;
|
||||
int i;
|
||||
int fail = 0;
|
||||
int ai;
|
||||
|
||||
printf("Testing strncpy...\n");
|
||||
for (align = 0; align < 8; align++)
|
||||
|
||||
/* ai encodes da*8+sa so src/dst offsets vary independently: sa!=da forces
|
||||
* different congruence and exercises the shift-merge path.
|
||||
*/
|
||||
|
||||
for (ai = 0; ai < 64; ai++)
|
||||
{
|
||||
int da = ai / 8;
|
||||
int sa = ai % 8;
|
||||
|
||||
for (size = 1; size <= 64; size++)
|
||||
{
|
||||
fill_pattern(g_buf1 + align, size);
|
||||
g_buf1[align + size] = '\0';
|
||||
fill_pattern(g_buf1 + sa, size);
|
||||
g_buf1[sa + size] = '\0';
|
||||
|
||||
/* n > strlen: should copy and zero-fill */
|
||||
|
||||
memset(g_buf2, 0xaa, sizeof(g_buf2));
|
||||
strncpy(g_buf2 + align, g_buf1 + align, size + 4);
|
||||
if (strcmp(g_buf2 + align, g_buf1 + align) != 0)
|
||||
strncpy(g_buf2 + da, g_buf1 + sa, size + 4);
|
||||
if (strcmp(g_buf2 + da, g_buf1 + sa) != 0)
|
||||
{
|
||||
printf(" FAIL copy: align=%d size=%d\n", align, size);
|
||||
printf(" FAIL copy: sa=%d da=%d size=%d\n", sa, da, size);
|
||||
fail++;
|
||||
}
|
||||
|
||||
|
|
@ -973,9 +991,10 @@ static int test_strncpy(void)
|
|||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (g_buf2[align + size + i] != '\0')
|
||||
if (g_buf2[da + size + i] != '\0')
|
||||
{
|
||||
printf(" FAIL zfill: align=%d size=%d\n", align, size);
|
||||
printf(" FAIL zfill: sa=%d da=%d size=%d\n",
|
||||
sa, da, size);
|
||||
fail++;
|
||||
break;
|
||||
}
|
||||
|
|
@ -986,10 +1005,11 @@ static int test_strncpy(void)
|
|||
if (size > 1)
|
||||
{
|
||||
memset(g_buf2, 0xaa, sizeof(g_buf2));
|
||||
strncpy(g_buf2 + align, g_buf1 + align, size - 1);
|
||||
if (memcmp(g_buf2 + align, g_buf1 + align, size - 1) != 0)
|
||||
strncpy(g_buf2 + da, g_buf1 + sa, size - 1);
|
||||
if (memcmp(g_buf2 + da, g_buf1 + sa, size - 1) != 0)
|
||||
{
|
||||
printf(" FAIL trunc: align=%d size=%d\n", align, size);
|
||||
printf(" FAIL trunc: sa=%d da=%d size=%d\n",
|
||||
sa, da, size);
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
|
@ -1027,40 +1047,48 @@ static void speed_strncpy(void)
|
|||
#ifdef CONFIG_TESTING_ARCH_LIBC_STPCPY
|
||||
static int test_stpcpy(void)
|
||||
{
|
||||
int align;
|
||||
int size;
|
||||
int fail = 0;
|
||||
int ai;
|
||||
FAR char *p;
|
||||
|
||||
printf("Testing stpcpy...\n");
|
||||
for (align = 0; align < 8; align++)
|
||||
|
||||
/* ai encodes da*8+sa so src/dst offsets vary independently: sa!=da forces
|
||||
* different congruence and exercises the shift-merge path.
|
||||
*/
|
||||
|
||||
for (ai = 0; ai < 64; ai++)
|
||||
{
|
||||
int da = ai / 8;
|
||||
int sa = ai % 8;
|
||||
|
||||
for (size = 1; size <= 64; size++)
|
||||
{
|
||||
fill_pattern(g_buf1 + align, size);
|
||||
g_buf1[align + size] = '\0';
|
||||
fill_pattern(g_buf1 + sa, size);
|
||||
g_buf1[sa + size] = '\0';
|
||||
memset(g_buf2, 0, sizeof(g_buf2));
|
||||
p = stpcpy(g_buf2 + align, g_buf1 + align);
|
||||
p = stpcpy(g_buf2 + da, g_buf1 + sa);
|
||||
|
||||
/* Check content */
|
||||
|
||||
if (strcmp(g_buf2 + align, g_buf1 + align) != 0)
|
||||
if (strcmp(g_buf2 + da, g_buf1 + sa) != 0)
|
||||
{
|
||||
printf(" FAIL copy: align=%d size=%d\n", align, size);
|
||||
printf(" FAIL copy: sa=%d da=%d size=%d\n", sa, da, size);
|
||||
fail++;
|
||||
}
|
||||
|
||||
/* Check return value points to NUL */
|
||||
|
||||
if (p != g_buf2 + align + size)
|
||||
if (p != g_buf2 + da + size)
|
||||
{
|
||||
printf(" FAIL retval: align=%d size=%d\n", align, size);
|
||||
printf(" FAIL retval: sa=%d da=%d size=%d\n", sa, da, size);
|
||||
fail++;
|
||||
}
|
||||
|
||||
if (*p != '\0')
|
||||
{
|
||||
printf(" FAIL nul: align=%d size=%d\n", align, size);
|
||||
printf(" FAIL nul: sa=%d da=%d size=%d\n", sa, da, size);
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue