git: 438a1ff803a5 - stable/14 - lib/libc/tests/string/stpncpy_test.c: extend for upcoming SSE implementation

From: Robert Clausecker <fuz_at_FreeBSD.org>
Date: Wed, 24 Jan 2024 19:44:40 UTC
The branch stable/14 has been updated by fuz:

URL: https://cgit.FreeBSD.org/src/commit/?id=438a1ff803a5d033b80b16880b2718f1402d904f

commit 438a1ff803a5d033b80b16880b2718f1402d904f
Author:     Robert Clausecker <fuz@FreeBSD.org>
AuthorDate: 2023-11-05 04:02:00 +0000
Commit:     Robert Clausecker <fuz@FreeBSD.org>
CommitDate: 2024-01-24 19:39:27 +0000

    lib/libc/tests/string/stpncpy_test.c: extend for upcoming SSE implementation
    
    This adds additional unit tests validating the function for
    All possible alignment offsets of source and destination.
    
    Also extend the test to allow testing of an external stpncpy
    implementation, which greatly simplifies the development of
    custom implementations.
    
    Sponsored by:   The FreeBSD Foundation
    Tested by:      developers@, exp-run
    Approved by:    mjg
    MFC after:      1 month
    MFC to:         stable/14
    PR:             275785
    Differential Revision:  https://reviews.freebsd.org/D42519
    
    (cherry picked from commit 6fa9e7d8737548ef93c573387ce62402c368d486)
---
 lib/libc/tests/string/stpncpy_test.c | 99 +++++++++++++++++++++++++++++++-----
 1 file changed, 85 insertions(+), 14 deletions(-)

diff --git a/lib/libc/tests/string/stpncpy_test.c b/lib/libc/tests/string/stpncpy_test.c
index 8154237eb8c2..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:
@@ -27,12 +31,15 @@
 #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)
 {
@@ -69,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');
@@ -78,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());
 }