aboutsummaryrefslogtreecommitdiff
path: root/lib/libc/tests/string
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/tests/string')
-rw-r--r--lib/libc/tests/string/Makefile17
-rw-r--r--lib/libc/tests/string/bcmp_test.c32
-rw-r--r--lib/libc/tests/string/ffs_test.c1
-rw-r--r--lib/libc/tests/string/fls_test.c1
-rw-r--r--lib/libc/tests/string/memccpy_test.c229
-rw-r--r--lib/libc/tests/string/memcmp_test.c88
-rw-r--r--lib/libc/tests/string/memrchr_test.c116
-rw-r--r--lib/libc/tests/string/memset_s_test.c1
-rw-r--r--lib/libc/tests/string/memset_test.c29
-rw-r--r--lib/libc/tests/string/stpncpy_test.c100
-rw-r--r--lib/libc/tests/string/strcmp_test.c132
-rw-r--r--lib/libc/tests/string/strcspn_test.c269
-rw-r--r--lib/libc/tests/string/strlcpy_test.c183
-rw-r--r--lib/libc/tests/string/strncmp_test.c165
-rw-r--r--lib/libc/tests/string/strnlen_test.c141
-rw-r--r--lib/libc/tests/string/strspn_test.c30
-rw-r--r--lib/libc/tests/string/strxfrm_test.c1
-rw-r--r--lib/libc/tests/string/timingsafe_bcmp_test.c32
-rw-r--r--lib/libc/tests/string/timingsafe_memcmp_test.c32
-rw-r--r--lib/libc/tests/string/wcscasecmp_test.c1
-rw-r--r--lib/libc/tests/string/wcscoll_test.c1
-rw-r--r--lib/libc/tests/string/wcsnlen_test.c1
22 files changed, 1552 insertions, 50 deletions
diff --git a/lib/libc/tests/string/Makefile b/lib/libc/tests/string/Makefile
index a7545b75e0e9..a019939c30af 100644
--- a/lib/libc/tests/string/Makefile
+++ b/lib/libc/tests/string/Makefile
@@ -1,19 +1,30 @@
-
# ensure libc functions are tested, not clang's builtins
CFLAGS+= -fno-builtin
+ATF_TESTS_C+= bcmp_test
ATF_TESTS_C+= ffs_test
ATF_TESTS_C+= ffsl_test
ATF_TESTS_C+= ffsll_test
ATF_TESTS_C+= fls_test
ATF_TESTS_C+= flsl_test
ATF_TESTS_C+= flsll_test
+ATF_TESTS_C+= memccpy_test
ATF_TESTS_C+= memcmp_test
+ATF_TESTS_C+= memrchr_test
+ATF_TESTS_C+= memset2_test
ATF_TESTS_C+= memset_s_test
+ATF_TESTS_C+= strncmp_test
ATF_TESTS_C+= stpncpy_test
+ATF_TESTS_C+= strnlen_test
+ATF_TESTS_C+= strcmp2_test
+ATF_TESTS_C+= strcspn_test
ATF_TESTS_C+= strerror2_test
+ATF_TESTS_C+= strlcpy_test
+ATF_TESTS_C+= strspn_test
ATF_TESTS_C+= strverscmp_test
ATF_TESTS_C+= strxfrm_test
+ATF_TESTS_C+= timingsafe_bcmp_test
+ATF_TESTS_C+= timingsafe_memcmp_test
ATF_TESTS_C+= wcscasecmp_test
ATF_TESTS_C+= wcscoll_test
ATF_TESTS_C+= wcsnlen_test
@@ -29,14 +40,14 @@ NETBSD_ATF_TESTS_C+= strchr_test
NETBSD_ATF_TESTS_C+= strchrnul_test
NETBSD_ATF_TESTS_C+= strcmp_test
NETBSD_ATF_TESTS_C+= strcpy_test
-NETBSD_ATF_TESTS_C+= strcspn_test
NETBSD_ATF_TESTS_C+= strerror_test
NETBSD_ATF_TESTS_C+= strlen_test
NETBSD_ATF_TESTS_C+= strpbrk_test
NETBSD_ATF_TESTS_C+= strrchr_test
-NETBSD_ATF_TESTS_C+= strspn_test
NETBSD_ATF_TESTS_C+= swab_test
+SRCS.memset2_test= memset_test.c
+SRCS.strcmp2_test= strcmp_test.c
SRCS.strerror2_test= strerror_test.c
.include "../Makefile.netbsd-tests"
diff --git a/lib/libc/tests/string/bcmp_test.c b/lib/libc/tests/string/bcmp_test.c
new file mode 100644
index 000000000000..fdf5e48b3eb4
--- /dev/null
+++ b/lib/libc/tests/string/bcmp_test.c
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2023 The FreeBSD Foundation
+ *
+ * This software was developed by Robert Clausecker <fuz@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE
+ */
+
+#define MEMCMP bcmp
+#define RES(x) ((x) != 0)
+
+#include "memcmp_test.c"
diff --git a/lib/libc/tests/string/ffs_test.c b/lib/libc/tests/string/ffs_test.c
index aea61254482e..4b59385d712e 100644
--- a/lib/libc/tests/string/ffs_test.c
+++ b/lib/libc/tests/string/ffs_test.c
@@ -25,7 +25,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE
*/
-#include <sys/cdefs.h>
#include <atf-c.h>
#include <limits.h>
diff --git a/lib/libc/tests/string/fls_test.c b/lib/libc/tests/string/fls_test.c
index 847977d260c9..55691b36617c 100644
--- a/lib/libc/tests/string/fls_test.c
+++ b/lib/libc/tests/string/fls_test.c
@@ -25,7 +25,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE
*/
-#include <sys/cdefs.h>
#include <atf-c.h>
#include <limits.h>
diff --git a/lib/libc/tests/string/memccpy_test.c b/lib/libc/tests/string/memccpy_test.c
new file mode 100644
index 000000000000..4784fee4ede5
--- /dev/null
+++ b/lib/libc/tests/string/memccpy_test.c
@@ -0,0 +1,229 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * Copyright (c) 2023, 2024 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Robert Clausecker
+ * <fuz@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+void *(*memccpy_fn)(void *restrict, const void *restrict, int, size_t);
+
+static char *
+makebuf(size_t len, int guard_at_end)
+{
+ char *buf;
+ size_t alloc_size, page_size;
+
+ page_size = getpagesize();
+ alloc_size = roundup2(len, page_size) + page_size;
+
+ buf = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
+ assert(buf);
+ if (guard_at_end) {
+ assert(mprotect(buf + alloc_size - page_size, page_size, PROT_NONE) == 0);
+ return (buf + alloc_size - page_size - len);
+ } else {
+ assert(mprotect(buf, page_size, PROT_NONE) == 0);
+ return (buf + page_size);
+ }
+}
+
+static void
+freebuf(char * buf, size_t len, int guard_at_end)
+{
+ size_t alloc_size, page_size;
+
+ page_size = getpagesize();
+ alloc_size = roundup2(len, page_size) + page_size;
+
+ if (guard_at_end)
+ munmap(buf + len + page_size - alloc_size, alloc_size);
+ else
+ munmap(buf - page_size, alloc_size);
+}
+
+static void
+test_memccpy(const char *s, size_t size)
+{
+ char *src, *dst, *expected;
+ size_t bufsize, x;
+ int i, j;
+
+ for (i = 0; i <= 1; i++) {
+ for (j = 0; j <= 1; j++) {
+ for (bufsize = 0; bufsize <= size + 32; bufsize++) {
+ dst = makebuf(bufsize, j);
+ if (bufsize < size) {
+ src = makebuf(bufsize, i);
+ memcpy(src, s, bufsize);
+ expected = NULL;
+ } else {
+ src = makebuf(size, i);
+ memcpy(src, s, size);
+ expected = dst + size;
+ }
+
+ memset(dst, 'X', bufsize);
+ assert(memccpy_fn(dst, src, s[size-1], bufsize) == expected);
+ assert(memcmp(src, dst, MIN(bufsize, size)) == 0);
+ for (x = size; x < bufsize; x++)
+ assert(dst[x] == 'X');
+
+ freebuf(dst, bufsize, j);
+ freebuf(src, bufsize < size ? bufsize : size, i);
+ }
+ }
+ }
+}
+
+static void
+test_sentinel(char *dest, char *src, size_t destlen, size_t srclen)
+{
+ size_t i, effective_len;
+ void *res, *wantres;
+ const char *fail = NULL;
+ char terminator;
+
+ for (i = 0; i < srclen; i++)
+ /* src will never include (){} */
+ src[i] = '0' + i;
+
+ /* source sentinels: not to be copied */
+ src[-1] = '(';
+ src[srclen] = ')';
+
+ memset(dest, '\xee', destlen);
+
+ /* destination sentinels: not to be touched */
+ dest[-1] = '{';
+ dest[destlen] = '}';
+
+ effective_len = srclen < destlen ? srclen : destlen;
+ wantres = srclen <= destlen ? dest + srclen : NULL;
+ terminator = src[srclen-1];
+ res = memccpy_fn(dest, src, terminator, destlen);
+
+ if (dest[-1] != '{')
+ fail = "start sentinel overwritten";
+ else if (dest[destlen] != '}')
+ fail = "end sentinel overwritten";
+ else if (res != wantres)
+ fail = "incorrect return value";
+ else if (destlen > 0 && memcmp(src, dest, effective_len) != 0)
+ fail = "string not copied correctly";
+ else for (i = srclen; i < destlen; i++)
+ if (dest[i] != '\xee') {
+ fail = "buffer mutilated behind string";
+ break;
+ }
+
+ if (fail)
+ atf_tc_fail_nonfatal("%s\n"
+ "memccpy(%p \"%s\", %p \"%s\", %u '%c', %zu) = %p (want %p)\n",
+ fail, dest, dest, src, src, terminator, terminator, destlen, res, wantres);
+}
+
+ATF_TC_WITHOUT_HEAD(null);
+ATF_TC_BODY(null, tc)
+{
+ ATF_CHECK_EQ(memccpy_fn(NULL, "foo", 42, 0), NULL);
+}
+
+ATF_TC(zero_extension);
+ATF_TC_HEAD(zero_extension, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Ensure the upper bits of the terminator are ignored");
+}
+ATF_TC_BODY(zero_extension, tc)
+{
+ int mask = -1 & ~UCHAR_MAX;
+ char buf[16];
+
+ memset(buf, 0xcc, sizeof(buf));
+ ATF_CHECK_EQ(memccpy(buf, "foobar", 'r', sizeof(buf)), buf + sizeof("foobar") - 1);
+ ATF_CHECK_EQ(memcmp(buf, "foobar", sizeof("foobar") - 1), 0);
+
+ memset(buf, 0xcc, sizeof(buf));
+ ATF_CHECK_EQ(memccpy(buf, "foobar", mask | 'r', sizeof(buf)), buf + sizeof("foobar") - 1);
+ ATF_CHECK_EQ(memcmp(buf, "foobar", sizeof("foobar") - 1), 0);
+}
+
+ATF_TC_WITHOUT_HEAD(bounds);
+ATF_TC_BODY(bounds, tc)
+{
+ size_t i;
+ char buf[64];
+
+ for (i = 0; i < sizeof(buf) - 1; i++) {
+ buf[i] = ' ' + i;
+ buf[i+1] = '\0';
+ test_memccpy(buf, i + 1);
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(alignments);
+ATF_TC_BODY(alignments, tc)
+{
+ size_t srcalign, destalign, srclen, destlen;
+ char src[15+2+64]; /* 15 offsets + 64 max length + sentinels */
+ char dest[15+2+64]; /* 15 offsets + 64 max length + sentinels */
+
+ for (srcalign = 0; srcalign < 16; srcalign++)
+ for (destalign = 0; destalign < 16; destalign++)
+ for (srclen = 1; srclen < 64; srclen++)
+ for (destlen = 0; destlen < 64; destlen++)
+ test_sentinel(dest+destalign+1,
+ src+srcalign+1, destlen, srclen);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ void *dl_handle;
+
+ dl_handle = dlopen(NULL, RTLD_LAZY);
+ memccpy_fn = dlsym(dl_handle, "test_memccpy");
+ if (memccpy_fn == NULL)
+ memccpy_fn = memccpy;
+
+ ATF_TP_ADD_TC(tp, null);
+ ATF_TP_ADD_TC(tp, zero_extension);
+ ATF_TP_ADD_TC(tp, bounds);
+ ATF_TP_ADD_TC(tp, alignments);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/string/memcmp_test.c b/lib/libc/tests/string/memcmp_test.c
index ab782c92f255..5286a0b994f3 100644
--- a/lib/libc/tests/string/memcmp_test.c
+++ b/lib/libc/tests/string/memcmp_test.c
@@ -1,7 +1,11 @@
/*-
* Copyright (c) 2016 Jilles Tjoelker <jilles@FreeBSD.org>
+ * Copyright (c) 2023 The FreeBSD Foundation
* All rights reserved.
*
+ * Portions of this software were developed by Robert Clausecker
+ * <fuz@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -24,20 +28,48 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
+#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
+#ifndef MEMCMP
+#define MEMCMP memcmp
+#endif
+
+/*
+ * On FreeBSD we demand that memcmp returns the difference between the
+ * characters at the first site of mismatch. However, ISO/IEC 9899:1990
+ * only specifies that a number greater than, equal to, or less than
+ * zero shall be returned. If a unit test for this less strict
+ * behaviour is desired, define RES(x) to be (((x) > 0) - ((x) < 0)).
+ */
+#ifndef RES
+#define RES(x) (x)
+#endif
+
+static int (*memcmp_fn)(const void *, const void *, size_t);
+
+static void
+check_memcmp(const char *a, const char *b, size_t len, int expected)
+{
+ int got;
+
+ got = memcmp_fn(a, b, len);
+ ATF_CHECK_EQ_MSG(RES(expected), RES(got),
+ "%s(%p, %p, %zu) gave %d, but wanted %d",
+ __XSTRING(MEMCMP), a, b, len, got, expected);
+}
+
ATF_TC_WITHOUT_HEAD(zero);
ATF_TC_BODY(zero, tc)
{
- assert(memcmp("a", "b", 0) == 0);
- assert(memcmp("", "", 0) == 0);
+ check_memcmp("a", "b", 0, 0);
+ check_memcmp("", "", 0, 0);
}
ATF_TC_WITHOUT_HEAD(eq);
@@ -49,9 +81,9 @@ ATF_TC_BODY(eq, tc)
for (i = 0; i < 256; i++)
data1[i] = data2[i] = i ^ 0x55;
for (i = 1; i < 256; i++)
- assert(memcmp(data1, data2, i) == 0);
+ check_memcmp(data1, data2, i, 0);
for (i = 1; i < 256; i++)
- assert(memcmp(data1 + i, data2 + i, 256 - i) == 0);
+ check_memcmp(data1 + i, data2 + i, 256 - i, 0);
}
ATF_TC_WITHOUT_HEAD(neq);
@@ -65,9 +97,9 @@ ATF_TC_BODY(neq, tc)
data2[i] = i ^ 0x55;
}
for (i = 1; i < 256; i++)
- assert(memcmp(data1, data2, i) != 0);
+ check_memcmp(data1, data2, i, -0x55);
for (i = 1; i < 256; i++)
- assert(memcmp(data1 + i, data2 + i, 256 - i) != 0);
+ check_memcmp(data1 + i, data2 + i, 256 - i, i - (i ^ 0x55));
}
ATF_TC_WITHOUT_HEAD(diff);
@@ -81,37 +113,43 @@ ATF_TC_BODY(diff, tc)
data1[128] = 255;
data2[128] = 0;
for (i = 1; i < 66; i++) {
- assert(memcmp(data1 + 128, data2 + 128, i) == 255);
- assert(memcmp(data2 + 128, data1 + 128, i) == -255);
- assert(memcmp(data1 + 129 - i, data2 + 129 - i, i) == 255);
- assert(memcmp(data2 + 129 - i, data1 + 129 - i, i) == -255);
- assert(memcmp(data1 + 129 - i, data2 + 129 - i, i * 2) == 255);
- assert(memcmp(data2 + 129 - i, data1 + 129 - i, i * 2) == -255);
+ check_memcmp(data1 + 128, data2 + 128, i, 255);
+ check_memcmp(data2 + 128, data1 + 128, i, -255);
+ check_memcmp(data1 + 129 - i, data2 + 129 - i, i, 255);
+ check_memcmp(data2 + 129 - i, data1 + 129 - i, i, -255);
+ check_memcmp(data1 + 129 - i, data2 + 129 - i, i * 2, 255);
+ check_memcmp(data2 + 129 - i, data1 + 129 - i, i * 2, -255);
}
data1[128] = 'c';
data2[128] = 'e';
for (i = 1; i < 66; i++) {
- assert(memcmp(data1 + 128, data2 + 128, i) == -2);
- assert(memcmp(data2 + 128, data1 + 128, i) == 2);
- assert(memcmp(data1 + 129 - i, data2 + 129 - i, i) == -2);
- assert(memcmp(data2 + 129 - i, data1 + 129 - i, i) == 2);
- assert(memcmp(data1 + 129 - i, data2 + 129 - i, i * 2) == -2);
- assert(memcmp(data2 + 129 - i, data1 + 129 - i, i * 2) == 2);
+ check_memcmp(data1 + 128, data2 + 128, i, -2);
+ check_memcmp(data2 + 128, data1 + 128, i, 2);
+ check_memcmp(data1 + 129 - i, data2 + 129 - i, i, -2);
+ check_memcmp(data2 + 129 - i, data1 + 129 - i, i, 2);
+ check_memcmp(data1 + 129 - i, data2 + 129 - i, i * 2, -2);
+ check_memcmp(data2 + 129 - i, data1 + 129 - i, i * 2, 2);
}
memset(data1 + 129, 'A', sizeof(data1) - 129);
memset(data2 + 129, 'Z', sizeof(data2) - 129);
for (i = 1; i < 66; i++) {
- assert(memcmp(data1 + 128, data2 + 128, i) == -2);
- assert(memcmp(data2 + 128, data1 + 128, i) == 2);
- assert(memcmp(data1 + 129 - i, data2 + 129 - i, i) == -2);
- assert(memcmp(data2 + 129 - i, data1 + 129 - i, i) == 2);
- assert(memcmp(data1 + 129 - i, data2 + 129 - i, i * 2) == -2);
- assert(memcmp(data2 + 129 - i, data1 + 129 - i, i * 2) == 2);
+ check_memcmp(data1 + 128, data2 + 128, i, -2);
+ check_memcmp(data2 + 128, data1 + 128, i, 2);
+ check_memcmp(data1 + 129 - i, data2 + 129 - i, i, -2);
+ check_memcmp(data2 + 129 - i, data1 + 129 - i, i, 2);
+ check_memcmp(data1 + 129 - i, data2 + 129 - i, i * 2, -2);
+ check_memcmp(data2 + 129 - i, data1 + 129 - i, i * 2, 2);
}
}
ATF_TP_ADD_TCS(tp)
{
+ void *dl_handle;
+
+ dl_handle = dlopen(NULL, RTLD_LAZY);
+ memcmp_fn = dlsym(dl_handle, "test_" __XSTRING(MEMCMP));
+ if (memcmp_fn == NULL)
+ memcmp_fn = MEMCMP;
ATF_TP_ADD_TC(tp, zero);
ATF_TP_ADD_TC(tp, eq);
diff --git a/lib/libc/tests/string/memrchr_test.c b/lib/libc/tests/string/memrchr_test.c
new file mode 100644
index 000000000000..12f696c9dc1e
--- /dev/null
+++ b/lib/libc/tests/string/memrchr_test.c
@@ -0,0 +1,116 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Robert Clausecker
+ */
+
+#include <sys/cdefs.h>
+
+#include <dlfcn.h>
+#include <limits.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+static void *(*memrchr_fn)(const void *, int, size_t);
+
+ATF_TC_WITHOUT_HEAD(null);
+ATF_TC_BODY(null, tc)
+{
+ ATF_CHECK_EQ(memrchr_fn(NULL, 42, 0), NULL);
+}
+
+ATF_TC_WITHOUT_HEAD(not_found);
+ATF_TC_BODY(not_found, tc)
+{
+ size_t i, j;
+ char buf[1+15+64+1]; /* offset [0..15] + 64 buffer bytes + sentinels */
+
+ buf[0] = 'X';
+ memset(buf + 1, '-', sizeof(buf) - 1);
+
+ for (i = 0; i < 16; i++)
+ for (j = 0; j < 64; j++) {
+ buf[i + j + 1] = 'X';
+ ATF_CHECK_EQ(memrchr_fn(buf + i + 1, 'X', j), NULL);
+ buf[i + j + 1] = '-';
+ }
+}
+
+static void
+do_found_test(char buf[], size_t len, size_t first, size_t second)
+{
+ /* invariant: first <= second */
+
+ buf[first] = 'X';
+ buf[second] = 'X';
+ ATF_CHECK_EQ(memrchr_fn(buf, 'X', len), buf + second);
+ buf[first] = '-';
+ buf[second] = '-';
+}
+
+ATF_TC_WITHOUT_HEAD(found);
+ATF_TC_BODY(found, tc)
+{
+ size_t i, j, k, l;
+ char buf[1+15+64+1];
+
+ buf[0] = 'X';
+ memset(buf + 1, '-', sizeof(buf) - 1);
+
+ for (i = 0; i < 16; i++)
+ for (j = 0; j < 64; j++)
+ for (k = 0; k < j; k++)
+ for (l = 0; l <= k; l++) {
+ buf[i + j + 1] = 'X';
+ do_found_test(buf + i + 1, j, l, k);
+ buf[i + j + 1] = '-';
+ }
+}
+
+/* check that the right character is found */
+static void
+do_values_test(unsigned char buf[], size_t len, size_t i, int c)
+{
+ /* sentinels */
+ buf[-1] = c;
+ buf[len] = c;
+ memset(buf, c + 1, len);
+
+ if (i < len) {
+ buf[i] = c;
+ ATF_CHECK_EQ(memrchr_fn(buf, c, len), buf + i);
+ } else
+ ATF_CHECK_EQ(memrchr_fn(buf, c, len), NULL);
+}
+
+ATF_TC_WITHOUT_HEAD(values);
+ATF_TC_BODY(values, tc)
+{
+ size_t i, j, k;
+ int c;
+ unsigned char buf[1+15+64+1];
+
+ for (i = 0; i < 16; i++)
+ for (j = 0; j < 64; j++)
+ for (k = 0; k <= j; k++)
+ for (c = 0; c <= UCHAR_MAX; c++)
+ do_values_test(buf + i + 1, j, k, c);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ void *dl_handle;
+
+ dl_handle = dlopen(NULL, RTLD_LAZY);
+ memrchr_fn = dlsym(dl_handle, "test_memrchr");
+ if (memrchr_fn == NULL)
+ memrchr_fn = memrchr;
+
+ ATF_TP_ADD_TC(tp, null);
+ ATF_TP_ADD_TC(tp, not_found);
+ ATF_TP_ADD_TC(tp, found);
+ ATF_TP_ADD_TC(tp, values);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/string/memset_s_test.c b/lib/libc/tests/string/memset_s_test.c
index 90a6958cb369..c822a2ee4554 100644
--- a/lib/libc/tests/string/memset_s_test.c
+++ b/lib/libc/tests/string/memset_s_test.c
@@ -23,7 +23,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
diff --git a/lib/libc/tests/string/memset_test.c b/lib/libc/tests/string/memset_test.c
new file mode 100644
index 000000000000..b898ad5af251
--- /dev/null
+++ b/lib/libc/tests/string/memset_test.c
@@ -0,0 +1,29 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Strahinja Stanisic <strajabot@FreeBSD.org>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(int_char_conv);
+ATF_TC_BODY(int_char_conv, tc)
+{
+ char b[64];
+ int c = 0xDEADBEEF;
+ memset(&b, c, 64);
+ for(int i = 0; i < 64; i++) {
+ assert(b[i] == (char)c);
+ }
+
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, int_char_conv);
+ return (atf_no_error());
+}
+
diff --git a/lib/libc/tests/string/stpncpy_test.c b/lib/libc/tests/string/stpncpy_test.c
index 6602bda0c2a9..8574b2d591be 100644
--- a/lib/libc/tests/string/stpncpy_test.c
+++ b/lib/libc/tests/string/stpncpy_test.c
@@ -1,7 +1,11 @@
/*-
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * Copyright (c) 2023 The FreeBSD Foundation
* All rights reserved.
*
+ * Portions of this software were developed by Robert Clausecker
+ * <fuz@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -24,16 +28,18 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <assert.h>
+#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
+static char *(*stpncpy_fn)(char *restrict, const char *restrict, size_t);
+
static char *
makebuf(size_t len, int guard_at_end)
{
@@ -70,7 +76,7 @@ test_stpncpy(const char *s)
dst = makebuf(bufsize, j);
memset(dst, 'X', bufsize);
len = (bufsize < size) ? bufsize : size - 1;
- assert(stpncpy(dst, src, bufsize) == dst+len);
+ assert(stpncpy_fn(dst, src, bufsize) == dst+len);
assert(memcmp(src, dst, len) == 0);
for (x = len; x < bufsize; x++)
assert(dst[x] == '\0');
@@ -79,33 +85,97 @@ test_stpncpy(const char *s)
}
}
-ATF_TC_WITHOUT_HEAD(nul);
-ATF_TC_BODY(nul, tc)
+static void
+test_sentinel(char *dest, char *src, size_t destlen, size_t srclen)
{
+ size_t i;
+ const char *res, *wantres;
+ const char *fail = NULL;
+
+ for (i = 0; i < srclen; i++)
+ /* src will never include (){} */
+ src[i] = '0' + i;
+ src[srclen] = '\0';
+
+ /* source sentinels: not to be copied */
+ src[-1] = '(';
+ src[srclen+1] = ')';
+
+ memset(dest, 0xee, destlen);
+
+ /* destination sentinels: not to be touched */
+ dest[-1] = '{';
+ dest[destlen] = '}';
+
+ wantres = dest + (srclen > destlen ? destlen : srclen);
+ res = stpncpy_fn(dest, src, destlen);
+
+ if (dest[-1] != '{')
+ fail = "start sentinel overwritten";
+ else if (dest[destlen] != '}')
+ fail = "end sentinel overwritten";
+ else if (strncmp(src, dest, destlen) != 0)
+ fail = "string not copied correctly";
+ else if (res != wantres)
+ fail = "incorrect return value";
+ else for (i = srclen; i < destlen; i++)
+ if (dest[i] != '\0') {
+ fail = "incomplete NUL padding";
+ break;
+ }
- test_stpncpy("");
+ if (fail)
+ atf_tc_fail_nonfatal("%s\n"
+ "stpncpy(%p \"%s\", %p \"%s\", %zu) = %p (want %p)\n",
+ fail, dest, dest, src, src, destlen, res, wantres);
}
-ATF_TC_WITHOUT_HEAD(foo);
-ATF_TC_BODY(foo, tc)
+ATF_TC_WITHOUT_HEAD(null);
+ATF_TC_BODY(null, tc)
{
-
- test_stpncpy("foo");
+ ATF_CHECK_EQ(stpncpy_fn(NULL, NULL, 0), NULL);
}
-ATF_TC_WITHOUT_HEAD(glorp);
-ATF_TC_BODY(glorp, tc)
+ATF_TC_WITHOUT_HEAD(bounds);
+ATF_TC_BODY(bounds, tc)
{
+ size_t i;
+ char buf[64+1];
- test_stpncpy("glorp");
+ for (i = 0; i < sizeof(buf) - 1; i++) {
+ buf[i] = ' ' + i;
+ buf[i+1] = '\0';
+ test_stpncpy(buf);
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(alignments);
+ATF_TC_BODY(alignments, tc)
+{
+ size_t srcalign, destalign, srclen, destlen;
+ char src[15+3+64]; /* 15 offsets + 64 max length + NUL + sentinels */
+ char dest[15+2+64]; /* 15 offsets + 64 max length + sentinels */
+
+ for (srcalign = 0; srcalign < 16; srcalign++)
+ for (destalign = 0; destalign < 16; destalign++)
+ for (srclen = 0; srclen < 64; srclen++)
+ for (destlen = 0; destlen < 64; destlen++)
+ test_sentinel(dest+destalign+1,
+ src+srcalign+1, destlen, srclen);
}
ATF_TP_ADD_TCS(tp)
{
+ void *dl_handle;
+
+ dl_handle = dlopen(NULL, RTLD_LAZY);
+ stpncpy_fn = dlsym(dl_handle, "test_stpncpy");
+ if (stpncpy_fn == NULL)
+ stpncpy_fn = stpncpy;
- ATF_TP_ADD_TC(tp, nul);
- ATF_TP_ADD_TC(tp, foo);
- ATF_TP_ADD_TC(tp, glorp);
+ ATF_TP_ADD_TC(tp, null);
+ ATF_TP_ADD_TC(tp, bounds);
+ ATF_TP_ADD_TC(tp, alignments);
return (atf_no_error());
}
diff --git a/lib/libc/tests/string/strcmp_test.c b/lib/libc/tests/string/strcmp_test.c
new file mode 100644
index 000000000000..75ebcbcadda2
--- /dev/null
+++ b/lib/libc/tests/string/strcmp_test.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 2023 The FreeBSD Foundation
+ *
+ * This software was developed by Robert Clausecker <fuz@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE
+ */
+
+#include <sys/cdefs.h>
+
+#include <atf-c.h>
+#include <dlfcn.h>
+#include <string.h>
+
+int (*volatile strcmp_fn)(const char *, const char *);
+
+ATF_TC(strcmp_alignments);
+ATF_TC_HEAD(strcmp_alignments, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test strcmp(3) with various alignments");
+}
+
+static void
+alignment_testcase(char *a, char *b, int want)
+{
+ int res;
+
+ res = strcmp_fn(a, b);
+ ATF_CHECK_MSG(want == (res > 0) - (res < 0),
+ "strcmp(%p \"%s\", %p \"%s\") = %d != %d",
+ (void *)a, a, (void *)b, b, res, want);
+}
+
+static void
+check_strcmp_alignments(char a[], char b[],
+ size_t a_off, size_t b_off, size_t len, size_t pos)
+{
+ char *a_str, *b_str, a_orig, b_orig;
+
+ a[a_off] = '\0';
+ b[b_off] = '\0';
+
+ a_str = a + a_off + 1;
+ b_str = b + b_off + 1;
+
+ a_str[len] = '\0';
+ b_str[len] = '\0';
+ a_str[len+1] = 'A';
+ b_str[len+1] = 'B';
+
+ a_orig = a_str[pos];
+ b_orig = b_str[pos];
+
+ alignment_testcase(a_str, b_str, 0);
+
+ if (pos < len) {
+ a_str[pos] = '\0';
+ alignment_testcase(a_str, b_str, -1);
+ a_str[pos] = a_orig;
+ b_str[pos] = '\0';
+ alignment_testcase(a_str, b_str, 1);
+ b_str[pos] = b_orig;
+ }
+
+ a_str[pos] = 'X';
+ alignment_testcase(a_str, b_str, 1);
+ a_str[pos] = a_orig;
+ b_str[pos] = 'X';
+ alignment_testcase(a_str, b_str, -1);
+ b_str[pos] = b_orig;
+
+ a[a_off] = '-';
+ b[b_off] = '-';
+ a_str[len] = '-';
+ b_str[len] = '-';
+ a_str[len+1] = '-';
+ b_str[len+1] = '-';
+}
+
+ATF_TC_BODY(strcmp_alignments, tc)
+{
+ size_t a_off, b_off, len, pos;
+ /* 16B alignment offset + 64B buffer + sentinel before/after + NUL */
+ char a[64+16+3], b[64+16+3];
+
+ memset(a, '-', sizeof(a));
+ memset(b, '-', sizeof(b));
+ a[sizeof(a) - 1] = '\0';
+ b[sizeof(b) - 1] = '\0';
+
+ /* check alignment offsets relevant for SSE routines */
+ for (a_off = 0; a_off < 16; a_off++)
+ for (b_off = 0; b_off < 16; b_off++)
+ /* ensure main loop (@ 32B) is completed at least once */
+ for (len = 1; len <= 64; len++)
+ for (pos = 0; pos <= len; pos++)
+ check_strcmp_alignments(a, b, a_off, b_off, len, pos);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ void *dl_handle;
+
+ dl_handle = dlopen(NULL, RTLD_LAZY);
+ strcmp_fn = dlsym(dl_handle, "test_strcmp");
+ if (strcmp_fn == NULL)
+ strcmp_fn = strcmp;
+
+ ATF_TP_ADD_TC(tp, strcmp_alignments);
+
+ return atf_no_error();
+}
diff --git a/lib/libc/tests/string/strcspn_test.c b/lib/libc/tests/string/strcspn_test.c
new file mode 100644
index 000000000000..293fc2bc8d4e
--- /dev/null
+++ b/lib/libc/tests/string/strcspn_test.c
@@ -0,0 +1,269 @@
+/*-
+ * Copyright (c) 2023 The FreeBSD Foundation
+ *
+ * This software was developed by Robert Clausecker <fuz@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE
+ */
+
+
+#include <atf-c.h>
+#include <assert.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+enum {
+ MAXALIGN = 16, /* test all offsets from this alignment */
+ MAXBUF = 64, /* test up to this buffer length */
+};
+
+enum { NOMATCH, MATCH };
+
+#ifdef STRSPN
+#define STRXSPN strspn
+#else
+#define STRXSPN strcspn
+#endif
+
+static void
+testcase(char *buf, size_t buflen, char *set, size_t setlen, int want_match)
+{
+ size_t i, outcome, expected;
+
+ assert(setlen < UCHAR_MAX - 2);
+
+ for (i = 0; i < buflen; i++)
+#ifdef STRSPN
+ buf[i] = UCHAR_MAX - i % (setlen > 0 ? setlen : 1);
+#else /* strcspn */
+ buf[i] = 1 + i % (UCHAR_MAX - setlen - 1);
+#endif
+
+ buf[i] = '\0';
+
+ for (i = 0; i < setlen; i++)
+ set[i] = UCHAR_MAX - i;
+
+ set[i] = '\0';
+
+#ifdef STRSPN
+ if (setlen == 0)
+ expected = 0;
+ else if (want_match == MATCH && buflen > 0) {
+ buf[buflen - 1] = 1;
+ expected = buflen - 1;
+ } else
+ expected = buflen;
+#else /* strcspn */
+ if (want_match == MATCH && buflen > 0 && setlen > 0) {
+ buf[buflen - 1] = UCHAR_MAX;
+ expected = buflen - 1;
+ } else
+ expected = buflen;
+#endif
+
+ outcome = STRXSPN(buf, set);
+ ATF_CHECK_EQ_MSG(expected, outcome, "%s(%p[%zu], %p[%zu]) = %zu != %zu",
+ __XSTRING(STRXSPN), buf, buflen, set, setlen, outcome, expected);
+}
+
+/* test set with all alignments and lengths of buf */
+static void
+test_buf_alignments(char *set, size_t setlen, int want_match)
+{
+ char buf[MAXALIGN + MAXBUF + 1];
+ size_t i, j;
+
+ for (i = 0; i < MAXALIGN; i++)
+ for (j = 0; j <= MAXBUF; j++)
+ testcase(buf + i, j, set, setlen, want_match);
+}
+
+/* test buf with all alignments and lengths of set */
+static void
+test_set_alignments(char *buf, size_t buflen, int want_match)
+{
+ char set[MAXALIGN + MAXBUF + 1];
+ size_t i, j;
+
+ for (i = 0; i < MAXALIGN; i++)
+ for (j = 0; j <= MAXBUF; j++)
+ testcase(buf, buflen, set + i, j, want_match);
+}
+
+ATF_TC_WITHOUT_HEAD(buf_alignments);
+ATF_TC_BODY(buf_alignments, tc)
+{
+ char set[41];
+
+ test_buf_alignments(set, 0, MATCH);
+ test_buf_alignments(set, 1, MATCH);
+ test_buf_alignments(set, 5, MATCH);
+ test_buf_alignments(set, 20, MATCH);
+ test_buf_alignments(set, 40, MATCH);
+
+ test_buf_alignments(set, 0, NOMATCH);
+ test_buf_alignments(set, 1, NOMATCH);
+ test_buf_alignments(set, 5, NOMATCH);
+ test_buf_alignments(set, 20, NOMATCH);
+ test_buf_alignments(set, 40, NOMATCH);
+}
+
+ATF_TC_WITHOUT_HEAD(set_alignments);
+ATF_TC_BODY(set_alignments, tc)
+{
+ char buf[31];
+
+ test_set_alignments(buf, 0, MATCH);
+ test_set_alignments(buf, 10, MATCH);
+ test_set_alignments(buf, 20, MATCH);
+ test_set_alignments(buf, 30, MATCH);
+
+ test_set_alignments(buf, 0, NOMATCH);
+ test_set_alignments(buf, 10, NOMATCH);
+ test_set_alignments(buf, 20, NOMATCH);
+ test_set_alignments(buf, 30, NOMATCH);
+}
+
+#ifndef STRSPN
+/* test all positions in which set could match buf */
+static void
+test_match_positions(char *buf, char *set, size_t buflen, size_t setlen)
+{
+ size_t i, j, outcome;
+
+ memset(buf, '-', buflen);
+
+ for (i = 0; i < setlen; i++)
+ set[i] = 'A' + i;
+
+ buf[buflen] = '\0';
+ set[setlen] = '\0';
+
+ /*
+ * Check for (mis)match at buffer position i
+ * against set position j.
+ */
+ for (i = 0; i < buflen; i++) {
+ for (j = 0; j < setlen; j++) {
+ buf[i] = set[j];
+
+ outcome = strcspn(buf, set);
+ ATF_CHECK_EQ_MSG(i, outcome,
+ "strcspn(\"%s\", \"%s\") = %zu != %zu",
+ buf, set, outcome, i);
+ }
+
+ buf[i] = '-';
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(match_positions);
+ATF_TC_BODY(match_positions, tc)
+{
+ char buf[129], set[65];
+
+ test_match_positions(buf, set, 128, 64);
+ test_match_positions(buf, set, 64, 64);
+ test_match_positions(buf, set, 32, 64);
+ test_match_positions(buf, set, 16, 64);
+ test_match_positions(buf, set, 8, 64);
+ test_match_positions(buf, set, 128, 32);
+ test_match_positions(buf, set, 64, 32);
+ test_match_positions(buf, set, 32, 32);
+ test_match_positions(buf, set, 16, 32);
+ test_match_positions(buf, set, 8, 32);
+ test_match_positions(buf, set, 128, 16);
+ test_match_positions(buf, set, 64, 16);
+ test_match_positions(buf, set, 32, 16);
+ test_match_positions(buf, set, 16, 16);
+ test_match_positions(buf, set, 8, 16);
+ test_match_positions(buf, set, 128, 8);
+ test_match_positions(buf, set, 64, 8);
+ test_match_positions(buf, set, 32, 8);
+ test_match_positions(buf, set, 16, 8);
+ test_match_positions(buf, set, 8, 8);
+}
+
+/* if there are two matches, check that the earlier match is taken */
+static void
+test_match_order(char *buf, char *set, size_t buflen, size_t setlen)
+{
+ size_t i, j, k, l, outcome;
+
+ memset(buf, '-', buflen);
+
+ for (i = 0; i < setlen; i++)
+ set[i] = 'A' + i;
+
+ buf[buflen] = '\0';
+ set[setlen] = '\0';
+
+ for (i = 0; i < setlen; i++)
+ for (j = 0; j < setlen; j++)
+ for (k = 0; k + 1 < buflen; k++)
+ for (l = k + 1; l < buflen; l++) {
+ buf[k] = set[i];
+ buf[l] = set[j];
+ outcome = strcspn(buf, set);
+ ATF_CHECK_EQ_MSG(k, outcome,
+ "strcspn(\"%s\", \"%s\") = %zu != %zu",
+ buf, set, outcome, k);
+ buf[k] = '-';
+ buf[l] = '-';
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(match_order);
+ATF_TC_BODY(match_order, tc)
+{
+ char buf[33], set[65];
+
+ test_match_order(buf, set, 32, 64);
+ test_match_order(buf, set, 16, 64);
+ test_match_order(buf, set, 8, 64);
+ test_match_order(buf, set, 32, 32);
+ test_match_order(buf, set, 16, 32);
+ test_match_order(buf, set, 8, 32);
+ test_match_order(buf, set, 32, 16);
+ test_match_order(buf, set, 16, 16);
+ test_match_order(buf, set, 8, 16);
+ test_match_order(buf, set, 32, 8);
+ test_match_order(buf, set, 16, 8);
+ test_match_order(buf, set, 8, 8);
+}
+#endif /* !defined(STRSPN) */
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, buf_alignments);
+ ATF_TP_ADD_TC(tp, set_alignments);
+#ifndef STRSPN
+ ATF_TP_ADD_TC(tp, match_positions);
+ ATF_TP_ADD_TC(tp, match_order);
+#endif
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/string/strlcpy_test.c b/lib/libc/tests/string/strlcpy_test.c
new file mode 100644
index 000000000000..646bef42683e
--- /dev/null
+++ b/lib/libc/tests/string/strlcpy_test.c
@@ -0,0 +1,183 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * Copyright (c) 2023 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Robert Clausecker
+ * <fuz@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+size_t (*strlcpy_fn)(char *restrict, const char *restrict, size_t);
+
+static char *
+makebuf(size_t len, int guard_at_end)
+{
+ char *buf;
+ size_t alloc_size, page_size;
+
+ page_size = getpagesize();
+ alloc_size = roundup2(len, page_size) + page_size;
+
+ buf = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
+ assert(buf);
+ if (guard_at_end) {
+ assert(munmap(buf + alloc_size - page_size, page_size) == 0);
+ return (buf + alloc_size - page_size - len);
+ } else {
+ assert(munmap(buf, page_size) == 0);
+ return (buf + page_size);
+ }
+}
+
+static void
+test_strlcpy(const char *s)
+{
+ char *src, *dst;
+ size_t size, bufsize, x;
+ int i, j;
+
+ size = strlen(s) + 1;
+ for (i = 0; i <= 1; i++) {
+ for (j = 0; j <= 1; j++) {
+ for (bufsize = 0; bufsize <= size + 10; bufsize++) {
+ src = makebuf(size, i);
+ memcpy(src, s, size);
+ dst = makebuf(bufsize, j);
+ memset(dst, 'X', bufsize);
+ assert(strlcpy_fn(dst, src, bufsize) == size-1);
+ assert(bufsize == 0 || strncmp(src, dst, bufsize - 1) == 0);
+ for (x = size; x < bufsize; x++)
+ assert(dst[x] == 'X');
+ }
+ }
+ }
+}
+
+static void
+test_sentinel(char *dest, char *src, size_t destlen, size_t srclen)
+{
+ size_t i;
+ size_t res, wantres;
+ const char *fail = NULL;
+
+ for (i = 0; i < srclen; i++)
+ /* src will never include (){} */
+ src[i] = '0' + i;
+ src[srclen] = '\0';
+
+ /* source sentinels: not to be copied */
+ src[-1] = '(';
+ src[srclen+1] = ')';
+
+ memset(dest, '\xee', destlen);
+
+ /* destination sentinels: not to be touched */
+ dest[-1] = '{';
+ dest[destlen] = '}';
+
+ wantres = srclen;
+ res = strlcpy_fn(dest, src, destlen);
+
+ if (dest[-1] != '{')
+ fail = "start sentinel overwritten";
+ else if (dest[destlen] != '}')
+ fail = "end sentinel overwritten";
+ else if (res != wantres)
+ fail = "incorrect return value";
+ else if (destlen > 0 && strncmp(src, dest, destlen - 1) != 0)
+ fail = "string not copied correctly";
+ else if (destlen > 0 && srclen >= destlen - 1 && dest[destlen-1] != '\0')
+ fail = "string not NUL terminated";
+ else for (i = srclen + 1; i < destlen; i++)
+ if (dest[i] != '\xee') {
+ fail = "buffer mutilated behind string";
+ break;
+ }
+
+ if (fail)
+ atf_tc_fail_nonfatal("%s\n"
+ "strlcpy(%p \"%s\", %p \"%s\", %zu) = %zu (want %zu)\n",
+ fail, dest, dest, src, src, destlen, res, wantres);
+}
+
+ATF_TC_WITHOUT_HEAD(null);
+ATF_TC_BODY(null, tc)
+{
+ ATF_CHECK_EQ(strlcpy_fn(NULL, "foo", 0), 3);
+}
+
+ATF_TC_WITHOUT_HEAD(bounds);
+ATF_TC_BODY(bounds, tc)
+{
+ size_t i;
+ char buf[64+1];
+
+ for (i = 0; i < sizeof(buf) - 1; i++) {
+ buf[i] = ' ' + i;
+ buf[i+1] = '\0';
+ test_strlcpy(buf);
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(alignments);
+ATF_TC_BODY(alignments, tc)
+{
+ size_t srcalign, destalign, srclen, destlen;
+ char src[15+3+64]; /* 15 offsets + 64 max length + NUL + sentinels */
+ char dest[15+2+64]; /* 15 offsets + 64 max length + sentinels */
+
+ for (srcalign = 0; srcalign < 16; srcalign++)
+ for (destalign = 0; destalign < 16; destalign++)
+ for (srclen = 0; srclen < 64; srclen++)
+ for (destlen = 0; destlen < 64; destlen++)
+ test_sentinel(dest+destalign+1,
+ src+srcalign+1, destlen, srclen);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ void *dl_handle;
+
+ dl_handle = dlopen(NULL, RTLD_LAZY);
+ strlcpy_fn = dlsym(dl_handle, "test_strlcpy");
+ if (strlcpy_fn == NULL)
+ strlcpy_fn = strlcpy;
+
+ ATF_TP_ADD_TC(tp, null);
+ ATF_TP_ADD_TC(tp, bounds);
+ ATF_TP_ADD_TC(tp, alignments);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/string/strncmp_test.c b/lib/libc/tests/string/strncmp_test.c
new file mode 100644
index 000000000000..989c58bcfedf
--- /dev/null
+++ b/lib/libc/tests/string/strncmp_test.c
@@ -0,0 +1,165 @@
+/*-
+ * Copyright (c) 2023 The FreeBSD Foundation
+ *
+ * This software was developed by Robert Clausecker <fuz@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE
+ */
+
+#include <sys/cdefs.h>
+
+#include <atf-c.h>
+#include <dlfcn.h>
+#include <string.h>
+
+int (*volatile strncmp_fn)(const char *, const char *, size_t);
+
+static void
+alignment_testcase(char *a, char *b, int want, size_t len)
+{
+ int res;
+
+ res = strncmp_fn(a, b, len);
+ ATF_CHECK_MSG(want == (res > 0) - (res < 0),
+ "strcmp(%p \"%s\", %p \"%s\", %zu) = %d != %d",
+ (void *)a, a, (void *)b, b, len, res, want);
+}
+
+static void
+check_strncmp_alignments(char a[], char b[],
+ size_t a_off, size_t b_off, size_t len, size_t pos)
+{
+ char *a_str, *b_str, a_orig, b_orig;
+
+ a[a_off] = '\0';
+ b[b_off] = '\0';
+
+ a_str = a + a_off + 1;
+ b_str = b + b_off + 1;
+
+ a_str[len] = '\0';
+ b_str[len] = '\0';
+ a_str[len+1] = 'A';
+ b_str[len+1] = 'B';
+
+ a_orig = a_str[pos];
+ b_orig = b_str[pos];
+
+ alignment_testcase(a_str, b_str, 0, len + 16);
+ alignment_testcase(a_str, b_str, 0, len + 1);
+ alignment_testcase(a_str, b_str, 0, len);
+
+ if (pos < len) {
+ a_str[pos] = '\0';
+ alignment_testcase(a_str, b_str, -1, len + 16);
+ alignment_testcase(a_str, b_str, -1, len + 1);
+ alignment_testcase(a_str, b_str, -1, len);
+ alignment_testcase(a_str, b_str, -1, pos + 1);
+ alignment_testcase(a_str, b_str, 0, pos);
+ a_str[pos] = a_orig;
+
+ b_str[pos] = '\0';
+ alignment_testcase(a_str, b_str, 1, len + 16);
+ alignment_testcase(a_str, b_str, 1, len + 1);
+ alignment_testcase(a_str, b_str, 1, len);
+ alignment_testcase(a_str, b_str, 1, pos + 1);
+ alignment_testcase(a_str, b_str, 0, pos);
+ b_str[pos] = b_orig;
+ }
+
+ a_str[pos] = 'X';
+ alignment_testcase(a_str, b_str, 1, len + 16);
+ alignment_testcase(a_str, b_str, 0, pos);
+ alignment_testcase(a_str, b_str, 1, pos + 1);
+ if (pos < len) {
+ alignment_testcase(a_str, b_str, 1, len);
+ alignment_testcase(a_str, b_str, 1, len + 1);
+ }
+ a_str[pos] = a_orig;
+
+ b_str[pos] = 'X';
+ alignment_testcase(a_str, b_str, -1, len + 16);
+ alignment_testcase(a_str, b_str, 0, pos);
+ alignment_testcase(a_str, b_str, -1, pos + 1);
+ if (pos < len) {
+ alignment_testcase(a_str, b_str, -1, len);
+ alignment_testcase(a_str, b_str, -1, len + 1);
+ }
+ b_str[pos] = b_orig;
+
+ a[a_off] = '-';
+ b[b_off] = '-';
+ a_str[len] = '-';
+ b_str[len] = '-';
+ a_str[len+1] = '-';
+ b_str[len+1] = '-';
+}
+
+ATF_TC(strncmp_alignments);
+ATF_TC_HEAD(strncmp_alignments, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test strncmp(3) with various alignments");
+}
+
+ATF_TC_BODY(strncmp_alignments, tc)
+{
+ size_t a_off, b_off, len, pos;
+ char a[64+16+16+3], b[64+16+16+3];
+
+ memset(a, '-', sizeof(a));
+ memset(b, '-', sizeof(b));
+ a[sizeof(a) - 1] = '\0';
+ b[sizeof(b) - 1] = '\0';
+
+ for (a_off = 0; a_off < 16; a_off++)
+ for (b_off = 0; b_off < 16; b_off++)
+ for (len = 1; len <= 64; len++)
+ for (pos = 0; pos <= len; pos++)
+ check_strncmp_alignments(a, b, a_off, b_off, len, pos);
+}
+
+ATF_TC(strncmp_null);
+ATF_TC_HEAD(strncmp_null, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test strncmp(3) with null pointers");
+}
+
+ATF_TC_BODY(strncmp_null, tc)
+{
+ alignment_testcase(NULL, NULL, 0, 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ void *dl_handle;
+
+ dl_handle = dlopen(NULL, RTLD_LAZY);
+ strncmp_fn = dlsym(dl_handle, "test_strncmp");
+ if (strncmp_fn == NULL)
+ strncmp_fn = strncmp;
+
+ ATF_TP_ADD_TC(tp, strncmp_alignments);
+ ATF_TP_ADD_TC(tp, strncmp_null);
+
+ return atf_no_error();
+}
diff --git a/lib/libc/tests/string/strnlen_test.c b/lib/libc/tests/string/strnlen_test.c
new file mode 100644
index 000000000000..31c2384bb30f
--- /dev/null
+++ b/lib/libc/tests/string/strnlen_test.c
@@ -0,0 +1,141 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Strahinja Stanisic <strajabot@FreeBSD.org>
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdalign.h>
+#include <stdint.h>
+
+#include <atf-c.h>
+
+ATF_TC(strnlen_alignments);
+ATF_TC_HEAD(strnlen_alignments, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test strnlen(3) with different alignments");
+}
+
+ATF_TC_BODY(strnlen_alignments, tc)
+{
+ size_t (*strnlen_fn)(const char*, size_t) = strnlen;
+ char alignas(16) buffer[1 + 16 + 64 + 1 + 1];
+
+ memset(buffer, '/', sizeof(buffer));
+
+ for (int align = 1; align < 1 + 16; align++) {
+ char *s = buffer + align;
+
+ for (size_t maxlen = 0; maxlen <= 64; maxlen++) {
+ for (size_t len = 0; len <= maxlen; len++) {
+ /* returns length */
+
+ /* without sentinels */
+ s[len] = '\0';
+ size_t val = strnlen_fn(s, maxlen);
+ if (val != len) {
+ fprintf(stderr, "align = %d, maxlen = %zu, len = %zu",
+ align, maxlen, len);
+ atf_tc_fail("returned incorrect len");
+ }
+
+ /* with sentinels */
+ s[-1] = '\0';
+ s[maxlen + 1] = '\0';
+ val = strnlen_fn(s, maxlen);
+ if (val != len) {
+ fprintf(stderr, "align = %d, maxlen = %zu, len = %zu",
+ align, maxlen, len);
+ atf_tc_fail("returned incorrect len (sentinels)");
+ }
+
+ /* cleanup */
+ s[-1] = '/';
+ s[len] = '/';
+ s[maxlen + 1] = '/';
+
+ }
+
+ /* returns maxlen */
+
+ /* without sentinels */
+ size_t val = strnlen_fn(s, maxlen);
+ if (val != maxlen) {
+ fprintf(stderr, "align = %d, maxlen = %zu",
+ align, maxlen);
+ atf_tc_fail("should return maxlen");
+ }
+
+ /* with sentinels */
+ s[-1] = '\0';
+ s[maxlen + 1] = '\0';
+ val = strnlen_fn(s, maxlen);
+ if (val != maxlen) {
+ fprintf(stderr, "align = %d, maxlen = %zu",
+ align, maxlen);
+ atf_tc_fail("should return maxlen (sentinels)");
+ }
+
+ /* cleanup */
+ s[-1] = '/';
+ s[maxlen + 1] = '/';
+ }
+ }
+}
+
+ATF_TC(strnlen_size_max);
+ATF_TC_HEAD(strnlen_size_max, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test strnlen(3) with maxlen=SIZE_MAX");
+}
+
+ATF_TC_BODY(strnlen_size_max, tc)
+{
+ size_t (*strnlen_fn)(const char*, size_t) = strnlen;
+ char alignas(16) buffer[1 + 16 + 64 + 1 + 1];
+
+ memset(buffer, '/', sizeof(buffer));
+
+ for (int align = 1; align < 1 + 16; align++) {
+ char* s = buffer + align;
+
+ for (size_t len = 0; len <= 64; len++) {
+ /* returns length */
+
+ /* without sentinels */
+ s[len] = '\0';
+ size_t val = strnlen_fn(s, SIZE_MAX);
+ if (val != len) {
+ fprintf(stderr, "align = %d, maxlen = %zu, len = %zu",
+ align, SIZE_MAX, len);
+ atf_tc_fail("returned incorrect len (SIZE_MAX)");
+ }
+
+ /* with sentinels */
+ s[-1] = '\0';
+ val = strnlen_fn(s, SIZE_MAX);
+ if (val != len) {
+ fprintf(stderr, "align = %d, maxlen = %zu, len = %zu",
+ align, SIZE_MAX, len);
+ atf_tc_fail("returned incorrect len (sentinels) (SIZE_MAX)");
+ }
+
+ /* cleanup */
+ s[-1] = '/';
+ s[len] = '/';
+ }
+ }
+}
+
+
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, strnlen_alignments);
+ ATF_TP_ADD_TC(tp, strnlen_size_max);
+
+ return atf_no_error();
+}
diff --git a/lib/libc/tests/string/strspn_test.c b/lib/libc/tests/string/strspn_test.c
new file mode 100644
index 000000000000..73a08ddefa1b
--- /dev/null
+++ b/lib/libc/tests/string/strspn_test.c
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 2023 The FreeBSD Foundation
+ *
+ * This software was developed by Robert Clausecker <fuz@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE
+ */
+
+#define STRSPN
+#include "strcspn_test.c"
diff --git a/lib/libc/tests/string/strxfrm_test.c b/lib/libc/tests/string/strxfrm_test.c
index 3c2ab58cb72b..becc620ba79c 100644
--- a/lib/libc/tests/string/strxfrm_test.c
+++ b/lib/libc/tests/string/strxfrm_test.c
@@ -24,7 +24,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <string.h>
#include <locale.h>
#include <stdio.h>
diff --git a/lib/libc/tests/string/timingsafe_bcmp_test.c b/lib/libc/tests/string/timingsafe_bcmp_test.c
new file mode 100644
index 000000000000..96bf789633f2
--- /dev/null
+++ b/lib/libc/tests/string/timingsafe_bcmp_test.c
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2023 The FreeBSD Foundation
+ *
+ * This software was developed by Robert Clausecker <fuz@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE
+ */
+
+#define MEMCMP timingsafe_bcmp
+#define RES(x) ((x) != 0)
+
+#include "memcmp_test.c"
diff --git a/lib/libc/tests/string/timingsafe_memcmp_test.c b/lib/libc/tests/string/timingsafe_memcmp_test.c
new file mode 100644
index 000000000000..5f97e41fcf8a
--- /dev/null
+++ b/lib/libc/tests/string/timingsafe_memcmp_test.c
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2023 The FreeBSD Foundation
+ *
+ * This software was developed by Robert Clausecker <fuz@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE
+ */
+
+#define MEMCMP timingsafe_memcmp
+#define RES(x) (((x) > 0) - ((x) < 0))
+
+#include "memcmp_test.c"
diff --git a/lib/libc/tests/string/wcscasecmp_test.c b/lib/libc/tests/string/wcscasecmp_test.c
index 5927345e7f4a..9a47c0d91b31 100644
--- a/lib/libc/tests/string/wcscasecmp_test.c
+++ b/lib/libc/tests/string/wcscasecmp_test.c
@@ -24,7 +24,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <locale.h>
#include <stdio.h>
diff --git a/lib/libc/tests/string/wcscoll_test.c b/lib/libc/tests/string/wcscoll_test.c
index d64e03f0605a..2ce85bbb986b 100644
--- a/lib/libc/tests/string/wcscoll_test.c
+++ b/lib/libc/tests/string/wcscoll_test.c
@@ -26,7 +26,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
#include <locale.h>
#include <stdlib.h>
diff --git a/lib/libc/tests/string/wcsnlen_test.c b/lib/libc/tests/string/wcsnlen_test.c
index 56a2ef1e3623..ba2e1c8d7c57 100644
--- a/lib/libc/tests/string/wcsnlen_test.c
+++ b/lib/libc/tests/string/wcsnlen_test.c
@@ -24,7 +24,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <assert.h>