Module Name: src
Committed By: pgoyette
Date: Sat Dec 25 21:10:25 UTC 2010
Modified Files:
src/distrib/sets/lists/tests: mi
src/etc/mtree: NetBSD.dist.tests
src/tests/lib/libc: Makefile
src/tests/lib/libc/string: Makefile
Added Files:
src/tests/lib/libc/string: t_string.c
Log Message:
Migrate J.T.Conklin's public-domain str* tests from regress to atf.
While here, do some clean-up and knf.
To generate a diff of this commit:
cvs rdiff -u -r1.189 -r1.190 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r1.6 -r1.7 src/etc/mtree/NetBSD.dist.tests
cvs rdiff -u -r1.8 -r1.9 src/tests/lib/libc/Makefile
cvs rdiff -u -r1.2 -r1.3 src/tests/lib/libc/string/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/lib/libc/string/t_string.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/distrib/sets/lists/tests/mi
diff -u src/distrib/sets/lists/tests/mi:1.189 src/distrib/sets/lists/tests/mi:1.190
--- src/distrib/sets/lists/tests/mi:1.189 Sat Dec 25 01:04:27 2010
+++ src/distrib/sets/lists/tests/mi Sat Dec 25 21:10:24 2010
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.189 2010/12/25 01:04:27 pgoyette Exp $
+# $NetBSD: mi,v 1.190 2010/12/25 21:10:24 pgoyette Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@@ -334,8 +334,9 @@
./usr/libdata/debug/usr/tests/lib/libc/stdlib/t_environment_pth.debug tests-lib-debug debug,atf
./usr/libdata/debug/usr/tests/lib/libc/stdlib/t_mi_vector_hash.debug tests-lib-debug debug,atf
./usr/libdata/debug/usr/tests/lib/libc/stdlib/t_strtox.debug tests-lib-debug debug,atf
-./usr/libdata/debug/usr/tests/lib/libc/string tests-obsolete obsolete
-./usr/libdata/debug/usr/tests/lib/libc/string/t_popcount.debug tests-obsolete obsolete
+./usr/libdata/debug/usr/tests/lib/libc/string tests-lib-debug
+#./usr/libdata/debug/usr/tests/lib/libc/string/t_popcount.debug tests-lib-debug debug,atf
+./usr/libdata/debug/usr/tests/lib/libc/string/t_string.debug tests-lib-debug debug,atf
./usr/libdata/debug/usr/tests/lib/libdes tests-lib-debug
./usr/libdata/debug/usr/tests/lib/libdes/t_des.debug tests-lib-debug debug,atf,crypto
./usr/libdata/debug/usr/tests/lib/semaphore tests-lib-debug
@@ -1558,9 +1559,10 @@
./usr/tests/lib/libc/stdio/t_fmemopen tests-lib-tests atf
./usr/tests/lib/libc/stdio/t_format tests-lib-tests atf
./usr/tests/lib/libc/stdio/t_popen tests-lib-tests atf
-./usr/tests/lib/libc/string tests-obsolete obsolete
-./usr/tests/lib/libc/string/Atffile tests-obsolete obsolete
-./usr/tests/lib/libc/string/t_popcount tests-obsolete obsolete
+./usr/tests/lib/libc/string tests-lib-tests
+./usr/tests/lib/libc/string/Atffile tests-lib-tests atf
+#./usr/tests/lib/libc/string/t_popcount tests-lib-tests atf
+./usr/tests/lib/libc/string/t_string tests-lib-tests atf
./usr/tests/lib/libdes tests-lib-tests
./usr/tests/lib/libdes/Atffile tests-lib-tests atf,crypto
./usr/tests/lib/libdes/t_des tests-lib-tests atf,crypto
Index: src/etc/mtree/NetBSD.dist.tests
diff -u src/etc/mtree/NetBSD.dist.tests:1.6 src/etc/mtree/NetBSD.dist.tests:1.7
--- src/etc/mtree/NetBSD.dist.tests:1.6 Mon Dec 20 23:47:23 2010
+++ src/etc/mtree/NetBSD.dist.tests Sat Dec 25 21:10:25 2010
@@ -1,4 +1,4 @@
-# $NetBSD: NetBSD.dist.tests,v 1.6 2010/12/20 23:47:23 pgoyette Exp $
+# $NetBSD: NetBSD.dist.tests,v 1.7 2010/12/25 21:10:25 pgoyette Exp $
./usr/libdata/debug/usr/tests
./usr/libdata/debug/usr/tests/atf
@@ -49,6 +49,7 @@
./usr/libdata/debug/usr/tests/lib/libc/hash
./usr/libdata/debug/usr/tests/lib/libc/stdio
./usr/libdata/debug/usr/tests/lib/libc/stdlib
+./usr/libdata/debug/usr/tests/lib/libc/string
./usr/libdata/debug/usr/tests/lib/libdes
./usr/libdata/debug/usr/tests/lib/libevent
./usr/libdata/debug/usr/tests/lib/semaphore
@@ -141,6 +142,7 @@
./usr/tests/lib/libc/hash
./usr/tests/lib/libc/stdio
./usr/tests/lib/libc/stdlib
+./usr/tests/lib/libc/string
./usr/tests/lib/libdes
./usr/tests/lib/semaphore
./usr/tests/lib/semaphore/pthread
Index: src/tests/lib/libc/Makefile
diff -u src/tests/lib/libc/Makefile:1.8 src/tests/lib/libc/Makefile:1.9
--- src/tests/lib/libc/Makefile:1.8 Wed Nov 3 20:20:12 2010
+++ src/tests/lib/libc/Makefile Sat Dec 25 21:10:25 2010
@@ -1,11 +1,8 @@
-# $NetBSD: Makefile,v 1.8 2010/11/03 20:20:12 christos Exp $
+# $NetBSD: Makefile,v 1.9 2010/12/25 21:10:25 pgoyette Exp $
.include <bsd.own.mk>
-TESTS_SUBDIRS+= gen hash stdlib stdio
-
-# Disabled for now, only test in there is very expensive
-#SUBDIR+= string
+TESTS_SUBDIRS+= gen hash stdlib stdio string
TESTSDIR= ${TESTSBASE}/lib/libc
Index: src/tests/lib/libc/string/Makefile
diff -u src/tests/lib/libc/string/Makefile:1.2 src/tests/lib/libc/string/Makefile:1.3
--- src/tests/lib/libc/string/Makefile:1.2 Fri Feb 26 09:35:08 2010
+++ src/tests/lib/libc/string/Makefile Sat Dec 25 21:10:24 2010
@@ -1,10 +1,12 @@
-# $NetBSD: Makefile,v 1.2 2010/02/26 09:35:08 martin Exp $
+# $NetBSD: Makefile,v 1.3 2010/12/25 21:10:24 pgoyette Exp $
.include <bsd.own.mk>
TESTSDIR= ${TESTSBASE}/lib/libc/string
-# EXPENSIVE, REALY, REALY EXPENSIVE test!
-TESTS_C+= t_popcount
+TESTS_C+= t_string
+
+# EXPENSIVE, REALY, REALY EXPENSIVE test! Disable for now.
+#TESTS_C+= t_popcount
.include <bsd.test.mk>
Added files:
Index: src/tests/lib/libc/string/t_string.c
diff -u /dev/null src/tests/lib/libc/string/t_string.c:1.1
--- /dev/null Sat Dec 25 21:10:25 2010
+++ src/tests/lib/libc/string/t_string.c Sat Dec 25 21:10:24 2010
@@ -0,0 +1,1111 @@
+/* $NetBSD: t_string.c,v 1.1 2010/12/25 21:10:24 pgoyette Exp $ */
+
+/*
+ * Written by J.T. Conklin <[email protected]>
+ * Public domain.
+ */
+
+/*
+ * str*() regression suite
+ *
+ * Trivial str*() implementations can be audited by hand. Optimized
+ * versions that unroll loops, use naturally-aligned memory acesses,
+ * and "magic" arithmetic sequences to detect zero-bytes, written in
+ * assembler are much harder to validate. This program attempts to
+ * catch the corner cases.
+ *
+ * BUGS:
+ * Misssing checks for strncpy, strncat, strncmp, etc.
+ *
+ * TODO:
+ * Use mmap/mprotect to ensure the functions don't access memory
+ * across page boundaries.
+ *
+ * Consider generating tables programmatically. It would reduce
+ * the size, but it's also one more thing to go wrong.
+ *
+ * Share tables between strlen, strcpy, and strcat?
+ * Share tables between strchr and strrchr?
+ */
+
+#include <atf-c.h>
+
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+/* for strchr */
+char * (*volatile strchr_fn)(const char *, int);
+
+ATF_TC(check_memchr);
+
+ATF_TC_HEAD(check_memchr, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Test memchr results");
+}
+
+ATF_TC_BODY(check_memchr, tc)
+{
+ /* try to trick the compiler */
+ void * (*f)(const void *, int, size_t) = memchr;
+
+ unsigned int a, t;
+ void *off, *off2;
+ char buf[32];
+
+ struct tab {
+ const char *val;
+ size_t len;
+ char match;
+ ssize_t off;
+ };
+
+ const struct tab tab[] = {
+ { "", 0, 0, 0 },
+
+ { "/", 0, 0, 0 },
+ { "/", 1, 1, 0 },
+ { "/a", 2, 1, 0 },
+ { "/ab", 3, 1, 0 },
+ { "/abc", 4, 1, 0 },
+ { "/abcd", 5, 1, 0 },
+ { "/abcde", 6, 1, 0 },
+ { "/abcdef", 7, 1, 0 },
+ { "/abcdefg", 8, 1, 0 },
+
+ { "a/", 1, 0, 0 },
+ { "a/", 2, 1, 1 },
+ { "a/b", 3, 1, 1 },
+ { "a/bc", 4, 1, 1 },
+ { "a/bcd", 5, 1, 1 },
+ { "a/bcde", 6, 1, 1 },
+ { "a/bcdef", 7, 1, 1 },
+ { "a/bcdefg", 8, 1, 1 },
+
+ { "ab/", 2, 0, 0 },
+ { "ab/", 3, 1, 2 },
+ { "ab/c", 4, 1, 2 },
+ { "ab/cd", 5, 1, 2 },
+ { "ab/cde", 6, 1, 2 },
+ { "ab/cdef", 7, 1, 2 },
+ { "ab/cdefg", 8, 1, 2 },
+
+ { "abc/", 3, 0, 0 },
+ { "abc/", 4, 1, 3 },
+ { "abc/d", 5, 1, 3 },
+ { "abc/de", 6, 1, 3 },
+ { "abc/def", 7, 1, 3 },
+ { "abc/defg", 8, 1, 3 },
+
+ { "abcd/", 4, 0, 0 },
+ { "abcd/", 5, 1, 4 },
+ { "abcd/e", 6, 1, 4 },
+ { "abcd/ef", 7, 1, 4 },
+ { "abcd/efg", 8, 1, 4 },
+
+ { "abcde/", 5, 0, 0 },
+ { "abcde/", 6, 1, 5 },
+ { "abcde/f", 7, 1, 5 },
+ { "abcde/fg", 8, 1, 5 },
+
+ { "abcdef/", 6, 0, 0 },
+ { "abcdef/", 7, 1, 6 },
+ { "abcdef/g", 8, 1, 6 },
+
+ { "abcdefg/", 7, 0, 0 },
+ { "abcdefg/", 8, 1, 7 },
+
+ { "\xff\xff\xff\xff" "efg/", 8, 1, 7 },
+ { "a" "\xff\xff\xff\xff" "fg/", 8, 1, 7 },
+ { "ab" "\xff\xff\xff\xff" "g/", 8, 1, 7 },
+ { "abc" "\xff\xff\xff\xff" "/", 8, 1, 7 },
+ };
+
+ for (a = 1; a < 1 + sizeof(long); ++a) {
+ for (t = 0; t < (sizeof(tab) / sizeof(tab[0])); ++t) {
+ buf[a-1] = '/';
+ strcpy(&buf[a], tab[t].val);
+
+ off = f(&buf[a], '/', tab[t].len);
+ if (tab[t].match == 0) {
+ if (off != 0) {
+ fprintf(stderr, "a = %d, t = %d\n",
+ a, t);
+ atf_tc_fail("should not have found "
+ " char past len");
+ }
+ } else if (tab[t].match == 1) {
+ if (tab[t].off != ((char*)off - &buf[a])) {
+ fprintf(stderr, "a = %d, t = %d\n",
+ a, t);
+ atf_tc_fail("char not found at "
+ "correct offset");
+ }
+ } else {
+ fprintf(stderr, "a = %d, t = %d\n", a, t);
+ atf_tc_fail("Corrupt test case data");
+ }
+
+ /* check zero extension of char arg */
+ off2 = f(&buf[a], 0xffffff00 | '/', tab[t].len);
+ if (off2 != off)
+ atf_tc_fail("zero extension of char arg "
+ "failed");
+ }
+ }
+}
+
+ATF_TC(check_strcat);
+
+ATF_TC_HEAD(check_strcat, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Test strcat results");
+}
+
+ATF_TC_BODY(check_strcat, tc)
+{
+ /* try to trick the compiler */
+ char * (*f)(char *, const char *s) = strcat;
+
+ unsigned int a0, a1, t0, t1;
+ char buf0[64];
+ char buf1[64];
+ char *ret;
+
+ struct tab {
+ const char* val;
+ size_t len;
+ };
+
+ const struct tab tab[] = {
+ /*
+ * patterns that check for all combinations of leading and
+ * trailing unaligned characters (on a 64 bit processor)
+ */
+
+ { "", 0 },
+ { "a", 1 },
+ { "ab", 2 },
+ { "abc", 3 },
+ { "abcd", 4 },
+ { "abcde", 5 },
+ { "abcdef", 6 },
+ { "abcdefg", 7 },
+ { "abcdefgh", 8 },
+ { "abcdefghi", 9 },
+ { "abcdefghij", 10 },
+ { "abcdefghijk", 11 },
+ { "abcdefghijkl", 12 },
+ { "abcdefghijklm", 13 },
+ { "abcdefghijklmn", 14 },
+ { "abcdefghijklmno", 15 },
+ { "abcdefghijklmnop", 16 },
+ { "abcdefghijklmnopq", 17 },
+ { "abcdefghijklmnopqr", 18 },
+ { "abcdefghijklmnopqrs", 19 },
+ { "abcdefghijklmnopqrst", 20 },
+ { "abcdefghijklmnopqrstu", 21 },
+ { "abcdefghijklmnopqrstuv", 22 },
+ { "abcdefghijklmnopqrstuvw", 23 },
+
+ /*
+ * patterns that check for the cases where the expression:
+ *
+ * ((word - 0x7f7f..7f) & 0x8080..80)
+ *
+ * returns non-zero even though there are no zero bytes in
+ * the word.
+ */
+
+ { "" "\xff\xff\xff\xff\xff\xff\xff\xff" "abcdefgh", 16 },
+ { "a" "\xff\xff\xff\xff\xff\xff\xff\xff" "bcdefgh", 16 },
+ { "ab" "\xff\xff\xff\xff\xff\xff\xff\xff" "cdefgh", 16 },
+ { "abc" "\xff\xff\xff\xff\xff\xff\xff\xff" "defgh", 16 },
+ { "abcd" "\xff\xff\xff\xff\xff\xff\xff\xff" "efgh", 16 },
+ { "abcde" "\xff\xff\xff\xff\xff\xff\xff\xff" "fgh", 16 },
+ { "abcdef" "\xff\xff\xff\xff\xff\xff\xff\xff" "gh", 16 },
+ { "abcdefg" "\xff\xff\xff\xff\xff\xff\xff\xff" "h", 16 },
+ { "abcdefgh" "\xff\xff\xff\xff\xff\xff\xff\xff" "", 16 },
+ };
+
+ for (a0 = 0; a0 < sizeof(long); ++a0) {
+ for (a1 = 0; a1 < sizeof(long); ++a1) {
+ for (t0 = 0; t0 < __arraycount(tab); ++t0) {
+ for (t1 = 0; t1 < __arraycount(tab); ++t1) {
+
+ memcpy(&buf0[a0], tab[t0].val,
+ tab[t0].len + 1);
+ memcpy(&buf1[a1], tab[t1].val,
+ tab[t1].len + 1);
+
+ ret = f(&buf0[a0], &buf1[a1]);
+
+ /*
+ * verify strcat returns address
+ * of first parameter
+ */
+ if (&buf0[a0] != ret) {
+ fprintf(stderr, "a0 %d, a1 %d, "
+ "t0 %d, t1 %d\n",
+ a0, a1, t0, t1);
+ atf_tc_fail("strcat did not "
+ "return its first arg");
+ }
+
+ /* verify string copied correctly */
+ if (memcmp(&buf0[a0] + tab[t0].len,
+ &buf1[a1],
+ tab[t1].len + 1) != 0) {
+ fprintf(stderr, "a0 %d, a1 %d, "
+ "t0 %d, t1 %d\n",
+ a0, a1, t0, t1);
+ atf_tc_fail("string not copied "
+ "correctly");
+ }
+ }
+ }
+ }
+ }
+}
+
+static char *
+slow_strchr(char *buf, int ch)
+{
+ unsigned char c = 1;
+
+ ch &= 0xff;
+
+ for (; c != 0; buf++) {
+ c = *buf;
+ if (c == ch)
+ return buf;
+ }
+ return 0;
+}
+
+static void
+verify_strchr(char *buf, int ch, unsigned int t, unsigned int a)
+{
+ const char *off, *ok_off;
+
+ off = strchr_fn(buf, ch);
+ ok_off = slow_strchr(buf, ch);
+ if (off == ok_off)
+ return;
+
+ fprintf(stderr, "test_strchr(\"%s\", %#x) gave %zd not %zd (test %d, "
+ "alignment %d)\n",
+ buf, ch, off ? off - buf : -1, ok_off ? ok_off - buf : -1, t, a);
+
+ atf_tc_fail("Check stderr for details");
+}
+
+ATF_TC(check_strchr);
+
+ATF_TC_HEAD(check_strchr, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Test strchr results");
+}
+
+ATF_TC_BODY(check_strchr, tc)
+{
+ unsigned int t, a;
+ char *off;
+ char buf[32];
+
+ const char *tab[] = {
+ "",
+ "a",
+ "aa",
+ "abc",
+ "abcd",
+ "abcde",
+ "abcdef",
+ "abcdefg",
+ "abcdefgh",
+
+ "/",
+ "//",
+ "/a",
+ "/a/",
+ "/ab",
+ "/ab/",
+ "/abc",
+ "/abc/",
+ "/abcd",
+ "/abcd/",
+ "/abcde",
+ "/abcde/",
+ "/abcdef",
+ "/abcdef/",
+ "/abcdefg",
+ "/abcdefg/",
+ "/abcdefgh",
+ "/abcdefgh/",
+
+ "a/",
+ "a//",
+ "a/a",
+ "a/a/",
+ "a/ab",
+ "a/ab/",
+ "a/abc",
+ "a/abc/",
+ "a/abcd",
+ "a/abcd/",
+ "a/abcde",
+ "a/abcde/",
+ "a/abcdef",
+ "a/abcdef/",
+ "a/abcdefg",
+ "a/abcdefg/",
+ "a/abcdefgh",
+ "a/abcdefgh/",
+
+ "ab/",
+ "ab//",
+ "ab/a",
+ "ab/a/",
+ "ab/ab",
+ "ab/ab/",
+ "ab/abc",
+ "ab/abc/",
+ "ab/abcd",
+ "ab/abcd/",
+ "ab/abcde",
+ "ab/abcde/",
+ "ab/abcdef",
+ "ab/abcdef/",
+ "ab/abcdefg",
+ "ab/abcdefg/",
+ "ab/abcdefgh",
+ "ab/abcdefgh/",
+
+ "abc/",
+ "abc//",
+ "abc/a",
+ "abc/a/",
+ "abc/ab",
+ "abc/ab/",
+ "abc/abc",
+ "abc/abc/",
+ "abc/abcd",
+ "abc/abcd/",
+ "abc/abcde",
+ "abc/abcde/",
+ "abc/abcdef",
+ "abc/abcdef/",
+ "abc/abcdefg",
+ "abc/abcdefg/",
+ "abc/abcdefgh",
+ "abc/abcdefgh/",
+
+ "abcd/",
+ "abcd//",
+ "abcd/a",
+ "abcd/a/",
+ "abcd/ab",
+ "abcd/ab/",
+ "abcd/abc",
+ "abcd/abc/",
+ "abcd/abcd",
+ "abcd/abcd/",
+ "abcd/abcde",
+ "abcd/abcde/",
+ "abcd/abcdef",
+ "abcd/abcdef/",
+ "abcd/abcdefg",
+ "abcd/abcdefg/",
+ "abcd/abcdefgh",
+ "abcd/abcdefgh/",
+
+ "abcde/",
+ "abcde//",
+ "abcde/a",
+ "abcde/a/",
+ "abcde/ab",
+ "abcde/ab/",
+ "abcde/abc",
+ "abcde/abc/",
+ "abcde/abcd",
+ "abcde/abcd/",
+ "abcde/abcde",
+ "abcde/abcde/",
+ "abcde/abcdef",
+ "abcde/abcdef/",
+ "abcde/abcdefg",
+ "abcde/abcdefg/",
+ "abcde/abcdefgh",
+ "abcde/abcdefgh/",
+
+ "abcdef/",
+ "abcdef//",
+ "abcdef/a",
+ "abcdef/a/",
+ "abcdef/ab",
+ "abcdef/ab/",
+ "abcdef/abc",
+ "abcdef/abc/",
+ "abcdef/abcd",
+ "abcdef/abcd/",
+ "abcdef/abcde",
+ "abcdef/abcde/",
+ "abcdef/abcdef",
+ "abcdef/abcdef/",
+ "abcdef/abcdefg",
+ "abcdef/abcdefg/",
+ "abcdef/abcdefgh",
+ "abcdef/abcdefgh/",
+
+ "abcdefg/",
+ "abcdefg//",
+ "abcdefg/a",
+ "abcdefg/a/",
+ "abcdefg/ab",
+ "abcdefg/ab/",
+ "abcdefg/abc",
+ "abcdefg/abc/",
+ "abcdefg/abcd",
+ "abcdefg/abcd/",
+ "abcdefg/abcde",
+ "abcdefg/abcde/",
+ "abcdefg/abcdef",
+ "abcdefg/abcdef/",
+ "abcdefg/abcdefg",
+ "abcdefg/abcdefg/",
+ "abcdefg/abcdefgh",
+ "abcdefg/abcdefgh/",
+
+ "abcdefgh/",
+ "abcdefgh//",
+ "abcdefgh/a",
+ "abcdefgh/a/",
+ "abcdefgh/ab",
+ "abcdefgh/ab/",
+ "abcdefgh/abc",
+ "abcdefgh/abc/",
+ "abcdefgh/abcd",
+ "abcdefgh/abcd/",
+ "abcdefgh/abcde",
+ "abcdefgh/abcde/",
+ "abcdefgh/abcdef",
+ "abcdefgh/abcdef/",
+ "abcdefgh/abcdefg",
+ "abcdefgh/abcdefg/",
+ "abcdefgh/abcdefgh",
+ "abcdefgh/abcdefgh/",
+ };
+
+
+ strchr_fn = dlsym(dlopen(0, RTLD_LAZY), "test_strchr");
+ if (!strchr_fn)
+ strchr_fn = strchr;
+
+ for (a = 3; a < 3 + sizeof(long); ++a) {
+ /* Put char and a \0 before the buffer */
+ buf[a-1] = '/';
+ buf[a-2] = '0';
+ buf[a-3] = 0xff;
+ for (t = 0; t < (sizeof(tab) / sizeof(tab[0])); ++t) {
+ int len = strlen(tab[t]) + 1;
+ memcpy(&buf[a], tab[t], len);
+
+ /* Put the char we are looking for after the \0 */
+ buf[a + len] = '/';
+
+ /* Check search for NUL at end of string */
+ verify_strchr(buf + a, 0, t, a);
+
+ /* Then for the '/' in the strings */
+ verify_strchr(buf + a, '/', t, a);
+
+ /* check zero extension of char arg */
+ verify_strchr(buf + a, 0xffffff00 | '/', t, a);
+
+ /* Replace all the '/' with 0xff */
+ while ((off = slow_strchr(buf + a, '/')) != NULL)
+ *off = 0xff;
+
+ buf[a + len] = 0xff;
+
+ /* Check we can search for 0xff as well as '/' */
+ verify_strchr(buf + a, 0xff, t, a);
+ }
+ }
+}
+
+ATF_TC(check_strcmp);
+
+ATF_TC_HEAD(check_strcmp, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Test strcmp results");
+}
+
+ATF_TC_BODY(check_strcmp, tc)
+{
+ /* try to trick the compiler */
+ int (*f)(const char *, const char *s) = strcmp;
+
+ unsigned int a0, a1, t;
+ char buf0[64];
+ char buf1[64];
+ int ret;
+
+ struct tab {
+ const char* val0;
+ const char* val1;
+ int ret;
+ };
+
+ const struct tab tab[] = {
+ { "", "", 0 },
+
+ { "a", "a", 0 },
+ { "a", "b", -1 },
+ { "b", "a", +1 },
+ { "", "a", -1 },
+ { "a", "", +1 },
+
+ { "aa", "aa", 0 },
+ { "aa", "ab", -1 },
+ { "ab", "aa", +1 },
+ { "a", "aa", -1 },
+ { "aa", "a", +1 },
+
+ { "aaa", "aaa", 0 },
+ { "aaa", "aab", -1 },
+ { "aab", "aaa", +1 },
+ { "aa", "aaa", -1 },
+ { "aaa", "aa", +1 },
+
+ { "aaaa", "aaaa", 0 },
+ { "aaaa", "aaab", -1 },
+ { "aaab", "aaaa", +1 },
+ { "aaa", "aaaa", -1 },
+ { "aaaa", "aaa", +1 },
+
+ { "aaaaa", "aaaaa", 0 },
+ { "aaaaa", "aaaab", -1 },
+ { "aaaab", "aaaaa", +1 },
+ { "aaaa", "aaaaa", -1 },
+ { "aaaaa", "aaaa", +1 },
+
+ { "aaaaaa", "aaaaaa", 0 },
+ { "aaaaaa", "aaaaab", -1 },
+ { "aaaaab", "aaaaaa", +1 },
+ { "aaaaa", "aaaaaa", -1 },
+ { "aaaaaa", "aaaaa", +1 },
+ };
+
+ for (a0 = 0; a0 < sizeof(long); ++a0) {
+ for (a1 = 0; a1 < sizeof(long); ++a1) {
+ for (t = 0; t < __arraycount(tab); ++t) {
+ memcpy(&buf0[a0], tab[t].val0,
+ strlen(tab[t].val0) + 1);
+ memcpy(&buf1[a1], tab[t].val1,
+ strlen(tab[t].val1) + 1);
+
+ ret = f(&buf0[a0], &buf1[a1]);
+
+ if ((ret == 0 && tab[t].ret != 0) ||
+ (ret < 0 && tab[t].ret >= 0) ||
+ (ret > 0 && tab[t].ret <= 0)) {
+ fprintf(stderr, "a0 %d, a1 %d, t %d\n",
+ a0, a1, t);
+ fprintf(stderr, "\"%s\" \"%s\" %d\n",
+ &buf0[a0], &buf1[a1], ret);
+ atf_tc_fail("Check stderr for details");
+ }
+ }
+ }
+ }
+}
+
+ATF_TC(check_strcpy);
+
+ATF_TC_HEAD(check_strcpy, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Test strcpy results");
+}
+
+ATF_TC_BODY(check_strcpy, tc)
+{
+ /* try to trick the compiler */
+ char * (*f)(char *, const char *s) = strcpy;
+
+ unsigned int a0, a1, t;
+ char buf0[64];
+ char buf1[64];
+ char *ret;
+
+ struct tab {
+ const char* val;
+ size_t len;
+ };
+
+ const struct tab tab[] = {
+ /*
+ * patterns that check for all combinations of leading and
+ * trailing unaligned characters (on a 64 bit processor)
+ */
+
+ { "", 0 },
+ { "a", 1 },
+ { "ab", 2 },
+ { "abc", 3 },
+ { "abcd", 4 },
+ { "abcde", 5 },
+ { "abcdef", 6 },
+ { "abcdefg", 7 },
+ { "abcdefgh", 8 },
+ { "abcdefghi", 9 },
+ { "abcdefghij", 10 },
+ { "abcdefghijk", 11 },
+ { "abcdefghijkl", 12 },
+ { "abcdefghijklm", 13 },
+ { "abcdefghijklmn", 14 },
+ { "abcdefghijklmno", 15 },
+ { "abcdefghijklmnop", 16 },
+ { "abcdefghijklmnopq", 17 },
+ { "abcdefghijklmnopqr", 18 },
+ { "abcdefghijklmnopqrs", 19 },
+ { "abcdefghijklmnopqrst", 20 },
+ { "abcdefghijklmnopqrstu", 21 },
+ { "abcdefghijklmnopqrstuv", 22 },
+ { "abcdefghijklmnopqrstuvw", 23 },
+
+ /*
+ * patterns that check for the cases where the expression:
+ *
+ * ((word - 0x7f7f..7f) & 0x8080..80)
+ *
+ * returns non-zero even though there are no zero bytes in
+ * the word.
+ */
+
+ { "" "\xff\xff\xff\xff\xff\xff\xff\xff" "abcdefgh", 16 },
+ { "a" "\xff\xff\xff\xff\xff\xff\xff\xff" "bcdefgh", 16 },
+ { "ab" "\xff\xff\xff\xff\xff\xff\xff\xff" "cdefgh", 16 },
+ { "abc" "\xff\xff\xff\xff\xff\xff\xff\xff" "defgh", 16 },
+ { "abcd" "\xff\xff\xff\xff\xff\xff\xff\xff" "efgh", 16 },
+ { "abcde" "\xff\xff\xff\xff\xff\xff\xff\xff" "fgh", 16 },
+ { "abcdef" "\xff\xff\xff\xff\xff\xff\xff\xff" "gh", 16 },
+ { "abcdefg" "\xff\xff\xff\xff\xff\xff\xff\xff" "h", 16 },
+ { "abcdefgh" "\xff\xff\xff\xff\xff\xff\xff\xff" "", 16 },
+ };
+
+ for (a0 = 0; a0 < sizeof(long); ++a0) {
+ for (a1 = 0; a1 < sizeof(long); ++a1) {
+ for (t = 0; t < (sizeof(tab) / sizeof(tab[0])); ++t) {
+
+ memcpy(&buf1[a1], tab[t].val, tab[t].len + 1);
+ ret = f(&buf0[a0], &buf1[a1]);
+
+ /*
+ * verify strcpy returns address of
+ * first parameter
+ */
+ if (&buf0[a0] != ret) {
+ fprintf(stderr, "a0 %d, a1 %d, t %d\n",
+ a0, a1, t);
+ atf_tc_fail("strcpy did not return "
+ "its first arg");
+ }
+
+ /*
+ * verify string was copied correctly
+ */
+ if (memcmp(&buf0[a0], &buf1[a1],
+ tab[t].len + 1) != 0) {
+ fprintf(stderr, "a0 %d, a1 %d, t %d\n",
+ a0, a1, t);
+ atf_tc_fail("not correctly copied");
+ }
+ }
+ }
+ }
+}
+
+static void
+write_num(int val)
+{
+ char buf[20];
+ int i;
+
+ for (i = sizeof buf; --i >= 0;) {
+ buf[i] = '0' + val % 10;
+ val /= 10;
+ if (val == 0) {
+ write(2, buf + i, sizeof buf - i);
+ return;
+ }
+ }
+ write(2, "overflow", 8);
+}
+
+ATF_TC(check_strlen);
+
+ATF_TC_HEAD(check_strlen, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Test strlen results");
+}
+
+ATF_TC_BODY(check_strlen, tc)
+{
+ /* try to trick the compiler */
+ size_t (*strlen_fn)(const char *);
+
+ unsigned int a, t;
+ size_t len;
+ char buf[64];
+
+ struct tab {
+ const char* val;
+ size_t len;
+ };
+
+ const struct tab tab[] = {
+ /*
+ * patterns that check for all combinations of leading and
+ * trailing unaligned characters (on a 64 bit processor)
+ */
+
+ { "", 0 },
+ { "a", 1 },
+ { "ab", 2 },
+ { "abc", 3 },
+ { "abcd", 4 },
+ { "abcde", 5 },
+ { "abcdef", 6 },
+ { "abcdefg", 7 },
+ { "abcdefgh", 8 },
+ { "abcdefghi", 9 },
+ { "abcdefghij", 10 },
+ { "abcdefghijk", 11 },
+ { "abcdefghijkl", 12 },
+ { "abcdefghijklm", 13 },
+ { "abcdefghijklmn", 14 },
+ { "abcdefghijklmno", 15 },
+ { "abcdefghijklmnop", 16 },
+ { "abcdefghijklmnopq", 17 },
+ { "abcdefghijklmnopqr", 18 },
+ { "abcdefghijklmnopqrs", 19 },
+ { "abcdefghijklmnopqrst", 20 },
+ { "abcdefghijklmnopqrstu", 21 },
+ { "abcdefghijklmnopqrstuv", 22 },
+ { "abcdefghijklmnopqrstuvw", 23 },
+
+ /*
+ * patterns that check for the cases where the expression:
+ *
+ * ((word - 0x7f7f..7f) & 0x8080..80)
+ *
+ * returns non-zero even though there are no zero bytes in
+ * the word.
+ */
+
+ { "" "\xff\xff\xff\xff\xff\xff\xff\xff" "abcdefgh", 16 },
+ { "a" "\xff\xff\xff\xff\xff\xff\xff\xff" "bcdefgh", 16 },
+ { "ab" "\xff\xff\xff\xff\xff\xff\xff\xff" "cdefgh", 16 },
+ { "abc" "\xff\xff\xff\xff\xff\xff\xff\xff" "defgh", 16 },
+ { "abcd" "\xff\xff\xff\xff\xff\xff\xff\xff" "efgh", 16 },
+ { "abcde" "\xff\xff\xff\xff\xff\xff\xff\xff" "fgh", 16 },
+ { "abcdef" "\xff\xff\xff\xff\xff\xff\xff\xff" "gh", 16 },
+ { "abcdefg" "\xff\xff\xff\xff\xff\xff\xff\xff" "h", 16 },
+ { "abcdefgh" "\xff\xff\xff\xff\xff\xff\xff\xff" "", 16 },
+ };
+
+ /*
+ * During testing it is useful have the rest of the program
+ * use a known good version!
+ */
+ strlen_fn = dlsym(dlopen(NULL, RTLD_LAZY), "test_strlen");
+ if (!strlen_fn)
+ strlen_fn = strlen;
+
+ for (a = 0; a < sizeof(long); ++a) {
+ for (t = 0; t < (sizeof(tab) / sizeof(tab[0])); ++t) {
+
+ memcpy(&buf[a], tab[t].val, tab[t].len + 1);
+ len = strlen_fn(&buf[a]);
+
+ if (len != tab[t].len) {
+ /* Write error without using printf / strlen */
+ write(2, "alignment ", 10);
+ write_num(a);
+ write(2, ", test ", 7);
+ write_num(t);
+ write(2, ", got len ", 10);
+ write_num(len);
+ write(2, ", not ", 6);
+ write_num(tab[t].len);
+ write(2, ", for '", 7);
+ write(2, tab[t].val, tab[t].len);
+ write(2, "'\n", 2);
+ atf_tc_fail("See stderr for details");
+ }
+ }
+ }
+}
+
+ATF_TC(check_strrchr);
+
+ATF_TC_HEAD(check_strrchr, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Test strrchr results");
+}
+
+ATF_TC_BODY(check_strrchr, tc)
+{
+ /* try to trick the compiler */
+ char * (*f)(const char *, int) = strrchr;
+
+ unsigned int a, t;
+ char *off, *off2;
+ char buf[32];
+
+ struct tab {
+ const char* val;
+ char match;
+ ssize_t f_off; /* offset of first match */
+ ssize_t l_off; /* offset of last match */
+ };
+
+ const struct tab tab[] = {
+ { "", 0, 0, 0 },
+ { "a", 0, 0, 0 },
+ { "aa", 0, 0, 0 },
+ { "abc", 0, 0, 0 },
+ { "abcd", 0, 0, 0 },
+ { "abcde", 0, 0, 0 },
+ { "abcdef", 0, 0, 0 },
+ { "abcdefg", 0, 0, 0 },
+ { "abcdefgh", 0, 0, 0 },
+
+ { "/", 1, 0, 0 },
+ { "//", 1, 0, 1 },
+ { "/a", 1, 0, 0 },
+ { "/a/", 1, 0, 2 },
+ { "/ab", 1, 0, 0 },
+ { "/ab/", 1, 0, 3 },
+ { "/abc", 1, 0, 0 },
+ { "/abc/", 1, 0, 4 },
+ { "/abcd", 1, 0, 0 },
+ { "/abcd/", 1, 0, 5 },
+ { "/abcde", 1, 0, 0 },
+ { "/abcde/", 1, 0, 6 },
+ { "/abcdef", 1, 0, 0 },
+ { "/abcdef/", 1, 0, 7 },
+ { "/abcdefg", 1, 0, 0 },
+ { "/abcdefg/", 1, 0, 8 },
+ { "/abcdefgh", 1, 0, 0 },
+ { "/abcdefgh/", 1, 0, 9 },
+
+ { "a/", 1, 1, 1 },
+ { "a//", 1, 1, 2 },
+ { "a/a", 1, 1, 1 },
+ { "a/a/", 1, 1, 3 },
+ { "a/ab", 1, 1, 1 },
+ { "a/ab/", 1, 1, 4 },
+ { "a/abc", 1, 1, 1 },
+ { "a/abc/", 1, 1, 5 },
+ { "a/abcd", 1, 1, 1 },
+ { "a/abcd/", 1, 1, 6 },
+ { "a/abcde", 1, 1, 1 },
+ { "a/abcde/", 1, 1, 7 },
+ { "a/abcdef", 1, 1, 1 },
+ { "a/abcdef/", 1, 1, 8 },
+ { "a/abcdefg", 1, 1, 1 },
+ { "a/abcdefg/", 1, 1, 9 },
+ { "a/abcdefgh", 1, 1, 1 },
+ { "a/abcdefgh/", 1, 1, 10 },
+
+ { "ab/", 1, 2, 2 },
+ { "ab//", 1, 2, 3 },
+ { "ab/a", 1, 2, 2 },
+ { "ab/a/", 1, 2, 4 },
+ { "ab/ab", 1, 2, 2 },
+ { "ab/ab/", 1, 2, 5 },
+ { "ab/abc", 1, 2, 2 },
+ { "ab/abc/", 1, 2, 6 },
+ { "ab/abcd", 1, 2, 2 },
+ { "ab/abcd/", 1, 2, 7 },
+ { "ab/abcde", 1, 2, 2 },
+ { "ab/abcde/", 1, 2, 8 },
+ { "ab/abcdef", 1, 2, 2 },
+ { "ab/abcdef/", 1, 2, 9 },
+ { "ab/abcdefg", 1, 2, 2 },
+ { "ab/abcdefg/", 1, 2, 10 },
+ { "ab/abcdefgh", 1, 2, 2 },
+ { "ab/abcdefgh/", 1, 2, 11 },
+
+ { "abc/", 1, 3, 3 },
+ { "abc//", 1, 3, 4 },
+ { "abc/a", 1, 3, 3 },
+ { "abc/a/", 1, 3, 5 },
+ { "abc/ab", 1, 3, 3 },
+ { "abc/ab/", 1, 3, 6 },
+ { "abc/abc", 1, 3, 3 },
+ { "abc/abc/", 1, 3, 7 },
+ { "abc/abcd", 1, 3, 3 },
+ { "abc/abcd/", 1, 3, 8 },
+ { "abc/abcde", 1, 3, 3 },
+ { "abc/abcde/", 1, 3, 9 },
+ { "abc/abcdef", 1, 3, 3 },
+ { "abc/abcdef/", 1, 3, 10 },
+ { "abc/abcdefg", 1, 3, 3 },
+ { "abc/abcdefg/", 1, 3, 11 },
+ { "abc/abcdefgh", 1, 3, 3 },
+ { "abc/abcdefgh/", 1, 3, 12 },
+
+ { "abcd/", 1, 4, 4 },
+ { "abcd//", 1, 4, 5 },
+ { "abcd/a", 1, 4, 4 },
+ { "abcd/a/", 1, 4, 6 },
+ { "abcd/ab", 1, 4, 4 },
+ { "abcd/ab/", 1, 4, 7 },
+ { "abcd/abc", 1, 4, 4 },
+ { "abcd/abc/", 1, 4, 8 },
+ { "abcd/abcd", 1, 4, 4 },
+ { "abcd/abcd/", 1, 4, 9 },
+ { "abcd/abcde", 1, 4, 4 },
+ { "abcd/abcde/", 1, 4, 10 },
+ { "abcd/abcdef", 1, 4, 4 },
+ { "abcd/abcdef/", 1, 4, 11 },
+ { "abcd/abcdefg", 1, 4, 4 },
+ { "abcd/abcdefg/", 1, 4, 12 },
+ { "abcd/abcdefgh", 1, 4, 4 },
+ { "abcd/abcdefgh/", 1, 4, 13 },
+
+ { "abcde/", 1, 5, 5 },
+ { "abcde//", 1, 5, 6 },
+ { "abcde/a", 1, 5, 5 },
+ { "abcde/a/", 1, 5, 7 },
+ { "abcde/ab", 1, 5, 5 },
+ { "abcde/ab/", 1, 5, 8 },
+ { "abcde/abc", 1, 5, 5 },
+ { "abcde/abc/", 1, 5, 9 },
+ { "abcde/abcd", 1, 5, 5 },
+ { "abcde/abcd/", 1, 5, 10 },
+ { "abcde/abcde", 1, 5, 5 },
+ { "abcde/abcde/", 1, 5, 11 },
+ { "abcde/abcdef", 1, 5, 5 },
+ { "abcde/abcdef/", 1, 5, 12 },
+ { "abcde/abcdefg", 1, 5, 5 },
+ { "abcde/abcdefg/", 1, 5, 13 },
+ { "abcde/abcdefgh", 1, 5, 5 },
+ { "abcde/abcdefgh/", 1, 5, 14 },
+
+ { "abcdef/", 1, 6, 6 },
+ { "abcdef//", 1, 6, 7 },
+ { "abcdef/a", 1, 6, 6 },
+ { "abcdef/a/", 1, 6, 8 },
+ { "abcdef/ab", 1, 6, 6 },
+ { "abcdef/ab/", 1, 6, 9 },
+ { "abcdef/abc", 1, 6, 6 },
+ { "abcdef/abc/", 1, 6, 10 },
+ { "abcdef/abcd", 1, 6, 6 },
+ { "abcdef/abcd/", 1, 6, 11 },
+ { "abcdef/abcde", 1, 6, 6 },
+ { "abcdef/abcde/", 1, 6, 12 },
+ { "abcdef/abcdef", 1, 6, 6 },
+ { "abcdef/abcdef/", 1, 6, 13 },
+ { "abcdef/abcdefg", 1, 6, 6 },
+ { "abcdef/abcdefg/", 1, 6, 14 },
+ { "abcdef/abcdefgh", 1, 6, 6 },
+ { "abcdef/abcdefgh/", 1, 6, 15 },
+
+ { "abcdefg/", 1, 7, 7 },
+ { "abcdefg//", 1, 7, 8 },
+ { "abcdefg/a", 1, 7, 7 },
+ { "abcdefg/a/", 1, 7, 9 },
+ { "abcdefg/ab", 1, 7, 7 },
+ { "abcdefg/ab/", 1, 7, 10 },
+ { "abcdefg/abc", 1, 7, 7 },
+ { "abcdefg/abc/", 1, 7, 11 },
+ { "abcdefg/abcd", 1, 7, 7 },
+ { "abcdefg/abcd/", 1, 7, 12 },
+ { "abcdefg/abcde", 1, 7, 7 },
+ { "abcdefg/abcde/", 1, 7, 13 },
+ { "abcdefg/abcdef", 1, 7, 7 },
+ { "abcdefg/abcdef/", 1, 7, 14 },
+ { "abcdefg/abcdefg", 1, 7, 7 },
+ { "abcdefg/abcdefg/", 1, 7, 15 },
+ { "abcdefg/abcdefgh", 1, 7, 7 },
+ { "abcdefg/abcdefgh/", 1, 7, 16 },
+
+ { "abcdefgh/", 1, 8, 8 },
+ { "abcdefgh//", 1, 8, 9 },
+ { "abcdefgh/a", 1, 8, 8 },
+ { "abcdefgh/a/", 1, 8, 10 },
+ { "abcdefgh/ab", 1, 8, 8 },
+ { "abcdefgh/ab/", 1, 8, 11 },
+ { "abcdefgh/abc", 1, 8, 8 },
+ { "abcdefgh/abc/", 1, 8, 12 },
+ { "abcdefgh/abcd", 1, 8, 8 },
+ { "abcdefgh/abcd/", 1, 8, 13 },
+ { "abcdefgh/abcde", 1, 8, 8 },
+ { "abcdefgh/abcde/", 1, 8, 14 },
+ { "abcdefgh/abcdef", 1, 8, 8 },
+ { "abcdefgh/abcdef/", 1, 8, 15 },
+ { "abcdefgh/abcdefg", 1, 8, 8 },
+ { "abcdefgh/abcdefg/", 1, 8, 16 },
+ { "abcdefgh/abcdefgh", 1, 8, 8 },
+ { "abcdefgh/abcdefgh/", 1, 8, 17 },
+ };
+
+ for (a = 0; a < sizeof(long); ++a) {
+ for (t = 0; t < (sizeof(tab) / sizeof(tab[0])); ++t) {
+ strcpy(&buf[a], tab[t].val);
+
+ off = f(&buf[a], '/');
+ if (tab[t].match == 0) {
+ if (off != 0) {
+ fprintf(stderr, "a %d, t %d\n", a, t);
+ atf_tc_fail("strrchr should not have "
+ "found the character");
+ }
+ } else if (tab[t].match == 1) {
+ if (tab[t].l_off != (off - &buf[a])) {
+ fprintf(stderr, "a %d, t %d\n", a, t);
+ atf_tc_fail("strrchr returns wrong "
+ "offset");
+ }
+ } else {
+ fprintf(stderr, "a %d, t %d\n", a, t);
+ atf_tc_fail("bad test case data");
+ }
+
+ /* check zero extension of char arg */
+ off2 = f(&buf[a], 0xffffff00 | '/');
+ if (off != off2) {
+ fprintf(stderr, "a %d, t %d\n", a, t);
+ atf_tc_fail("zero extension of char arg fails");
+ }
+ }
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, check_memchr);
+ ATF_TP_ADD_TC(tp, check_strcat);
+ ATF_TP_ADD_TC(tp, check_strchr);
+ ATF_TP_ADD_TC(tp, check_strcmp);
+ ATF_TP_ADD_TC(tp, check_strcpy);
+ ATF_TP_ADD_TC(tp, check_strlen);
+ ATF_TP_ADD_TC(tp, check_strrchr);
+
+ return atf_no_error();
+}