git: 6fa9e7d87375 - main - lib/libc/tests/string/stpncpy_test.c: extend for upcoming SSE implementation

From: Robert Clausecker <fuz_at_FreeBSD.org>
Date: Mon, 25 Dec 2023 14:25:46 UTC
The branch main has been updated by fuz:

URL: https://cgit.FreeBSD.org/src/commit/?id=6fa9e7d8737548ef93c573387ce62402c368d486

commit 6fa9e7d8737548ef93c573387ce62402c368d486
Author:     Robert Clausecker <fuz@FreeBSD.org>
AuthorDate: 2023-11-05 04:02:00 +0000
Commit:     Robert Clausecker <fuz@FreeBSD.org>
CommitDate: 2023-12-25 13:55:37 +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
---
 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());
 }