diff options
Diffstat (limited to 'lib/libc/tests')
247 files changed, 24735 insertions, 504 deletions
diff --git a/lib/libc/tests/Makefile b/lib/libc/tests/Makefile index 11c3a635339d..975c895770ee 100644 --- a/lib/libc/tests/Makefile +++ b/lib/libc/tests/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <src.opts.mk> SUBDIR= tls_dso @@ -14,9 +12,11 @@ TESTS_SUBDIRS+= nss TESTS_SUBDIRS+= regex TESTS_SUBDIRS+= resolv TESTS_SUBDIRS+= rpc +TESTS_SUBDIRS+= secure TESTS_SUBDIRS+= setjmp TESTS_SUBDIRS+= stdio TESTS_SUBDIRS+= stdlib +TESTS_SUBDIRS+= stdtime TESTS_SUBDIRS+= string TESTS_SUBDIRS+= sys TESTS_SUBDIRS+= termios diff --git a/lib/libc/tests/Makefile.depend b/lib/libc/tests/Makefile.depend index f80275d86ab1..11aba52f82cf 100644 --- a/lib/libc/tests/Makefile.depend +++ b/lib/libc/tests/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/Makefile.netbsd-tests b/lib/libc/tests/Makefile.netbsd-tests index 18b0276b7296..43710d39aca2 100644 --- a/lib/libc/tests/Makefile.netbsd-tests +++ b/lib/libc/tests/Makefile.netbsd-tests @@ -1,5 +1,3 @@ -# $FreeBSD$ - TESTSRC:= ${SRCTOP}/contrib/netbsd-tests/${RELDIR:C/libc\/tests/libc/} TESTSDIR:= ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/} diff --git a/lib/libc/tests/c063/Makefile b/lib/libc/tests/c063/Makefile index 3be612dcaa42..c1d8b01c1abd 100644 --- a/lib/libc/tests/c063/Makefile +++ b/lib/libc/tests/c063/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - NETBSD_ATF_TESTS_C= faccessat_test NETBSD_ATF_TESTS_C+= fchmodat_test NETBSD_ATF_TESTS_C+= fchownat_test diff --git a/lib/libc/tests/c063/Makefile.depend b/lib/libc/tests/c063/Makefile.depend index 10e58b789640..e89a5c52c82a 100644 --- a/lib/libc/tests/c063/Makefile.depend +++ b/lib/libc/tests/c063/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/db/Makefile b/lib/libc/tests/db/Makefile index 132cfb321a22..771569183584 100644 --- a/lib/libc/tests/db/Makefile +++ b/lib/libc/tests/db/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - PACKAGE= tests BINDIR= ${TESTSDIR} @@ -9,6 +7,10 @@ PROGS+= h_lfsr ${PACKAGE}FILES+= README +ATF_TESTS_C+= dbm_open_test +ATF_TESTS_C+= dbm_perm_test +ATF_TESTS_C+= dbm_nextkey_test + NETBSD_ATF_TESTS_C+= db_hash_seq_test NETBSD_ATF_TESTS_SH+= db_test ATF_TESTS_SH_SED_db_test= -e 's,/bin/csh,/bin/cat,g' diff --git a/lib/libc/tests/db/Makefile.depend b/lib/libc/tests/db/Makefile.depend index 10e58b789640..e89a5c52c82a 100644 --- a/lib/libc/tests/db/Makefile.depend +++ b/lib/libc/tests/db/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/db/dbm_nextkey_test.c b/lib/libc/tests/db/dbm_nextkey_test.c new file mode 100644 index 000000000000..67b745efb196 --- /dev/null +++ b/lib/libc/tests/db/dbm_nextkey_test.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <fcntl.h> +#include <ndbm.h> +#include <stdio.h> + +#include <atf-c.h> + +static const char *path = "tmp"; +static const char *dbname = "tmp.db"; + +ATF_TC(dbm_nextkey_test); +ATF_TC_HEAD(dbm_nextkey_test, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Check that dbm_nextkey always returns NULL after reaching the end of the database"); +} + +ATF_TC_BODY(dbm_nextkey_test, tc) +{ + DBM *db; + datum key, data; + + data.dptr = "bar"; + data.dsize = strlen("bar"); + key.dptr = "foo"; + key.dsize = strlen("foo"); + + db = dbm_open(path, O_RDWR | O_CREAT, 0755); + ATF_CHECK(db != NULL); + ATF_REQUIRE(atf_utils_file_exists(dbname)); + ATF_REQUIRE(dbm_store(db, key, data, DBM_INSERT) != -1); + + key = dbm_firstkey(db); + ATF_REQUIRE(key.dptr != NULL); + key = dbm_nextkey(db); + ATF_REQUIRE(key.dptr == NULL); + key = dbm_nextkey(db); + ATF_REQUIRE(key.dptr == NULL); + + dbm_close(db); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, dbm_nextkey_test); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/db/dbm_open_test.c b/lib/libc/tests/db/dbm_open_test.c new file mode 100644 index 000000000000..8a3e888bf72c --- /dev/null +++ b/lib/libc/tests/db/dbm_open_test.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <fcntl.h> +#include <ndbm.h> +#include <stdio.h> + +#include <atf-c.h> + +static const char *path = "tmp"; +static const char *dbname = "tmp.db"; + +ATF_TC(dbm_open_missing_test); +ATF_TC_HEAD(dbm_open_missing_test, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test dbm_open when creating a new database"); +} + +ATF_TC_BODY(dbm_open_missing_test, tc) +{ + + /* + * POSIX.1 specifies that a missing database file should + * always get created if O_CREAT is present, except when + * O_EXCL is specified as well. + */ + ATF_CHECK(dbm_open(path, O_RDONLY, 0755) == NULL); + ATF_REQUIRE(!atf_utils_file_exists(dbname)); + ATF_CHECK(dbm_open(path, O_RDONLY | O_CREAT, 0755) != NULL); + ATF_REQUIRE(atf_utils_file_exists(dbname)); + ATF_CHECK(dbm_open(path, O_RDONLY | O_CREAT | O_EXCL, 0755) == NULL); +} + +ATF_TC_WITHOUT_HEAD(dbm_open_wronly_test); +ATF_TC_BODY(dbm_open_wronly_test, tc) +{ + ATF_CHECK(dbm_open(path, O_WRONLY, 0755) == NULL); + ATF_REQUIRE(!atf_utils_file_exists(dbname)); + ATF_CHECK(dbm_open(path, O_WRONLY | O_CREAT, 0755) != NULL); + ATF_REQUIRE(atf_utils_file_exists(dbname)); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, dbm_open_missing_test); + ATF_TP_ADD_TC(tp, dbm_open_wronly_test); + return (atf_no_error()); +} diff --git a/lib/libc/tests/db/dbm_perm_test.c b/lib/libc/tests/db/dbm_perm_test.c new file mode 100644 index 000000000000..c07210292014 --- /dev/null +++ b/lib/libc/tests/db/dbm_perm_test.c @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <errno.h> +#include <fcntl.h> +#include <ndbm.h> +#include <stdio.h> + +#include <atf-c.h> + +static const char *path = "tmp"; +static const char *dbname = "tmp.db"; + +static void +create_db(void) +{ + DB *db; + datum data, key; + + data.dptr = "bar"; + data.dsize = strlen("bar"); + key.dptr = "foo"; + key.dsize = strlen("foo"); + + db = dbm_open(path, O_RDWR | O_CREAT, 0755); + ATF_CHECK(db != NULL); + ATF_REQUIRE(atf_utils_file_exists(dbname)); + ATF_REQUIRE(dbm_store(db, key, data, DBM_INSERT) != -1); + dbm_close(db); +} + +ATF_TC_WITHOUT_HEAD(dbm_rdonly_test); +ATF_TC_BODY(dbm_rdonly_test, tc) +{ + DB *db; + datum data, key; + + bzero(&data, sizeof(data)); + key.dptr = "foo"; + key.dsize = strlen("foo"); + create_db(); + + db = dbm_open(path, O_RDONLY, 0755); + data = dbm_fetch(db, key); + ATF_REQUIRE(data.dptr != NULL); + ATF_REQUIRE(strncmp((const char*)data.dptr, "bar", data.dsize) == 0); + ATF_REQUIRE(dbm_store(db, key, data, DBM_REPLACE) == -1); + ATF_REQUIRE(errno == EPERM); +} + +ATF_TC_WITHOUT_HEAD(dbm_wronly_test); +ATF_TC_BODY(dbm_wronly_test, tc) +{ + DB *db; + datum data, key; + + key.dptr = "foo"; + key.dsize = strlen("foo"); + data.dptr = "baz"; + data.dsize = strlen("baz"); + create_db(); + + db = dbm_open(path, O_WRONLY, 0755); + data = dbm_fetch(db, key); + ATF_REQUIRE(data.dptr == NULL); + ATF_REQUIRE(errno == EPERM); + ATF_REQUIRE(dbm_store(db, key, data, DBM_REPLACE) != -1); +} + +ATF_TC_WITHOUT_HEAD(dbm_rdwr_test); +ATF_TC_BODY(dbm_rdwr_test, tc) +{ + DB *db; + datum data, key; + + key.dptr = "foo"; + key.dsize = strlen("foo"); + create_db(); + + db = dbm_open(path, O_RDWR, 0755); + data = dbm_fetch(db, key); + ATF_REQUIRE(data.dptr != NULL); + data.dptr = "baz"; + data.dsize = strlen("baz"); + ATF_REQUIRE(dbm_store(db, key, data, DBM_REPLACE) != -1); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, dbm_rdonly_test); + ATF_TP_ADD_TC(tp, dbm_wronly_test); + ATF_TP_ADD_TC(tp, dbm_rdwr_test); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile index a808f6617ec7..8c2151105209 100644 --- a/lib/libc/tests/gen/Makefile +++ b/lib/libc/tests/gen/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> ATF_TESTS_C+= arc4random_test @@ -9,14 +7,28 @@ ATF_TESTS_C+= fmtcheck2_test ATF_TESTS_C+= fmtmsg_test ATF_TESTS_C+= fnmatch2_test ATF_TESTS_C+= fpclassify2_test +.if ${COMPILER_FEATURES:Mblocks} +ATF_TESTS_C+= fts_blocks_test +.endif +ATF_TESTS_C+= fts_misc_test +ATF_TESTS_C+= fts_options_test ATF_TESTS_C+= ftw_test ATF_TESTS_C+= getentropy_test ATF_TESTS_C+= getmntinfo_test ATF_TESTS_C+= glob2_test +.if ${COMPILER_FEATURES:Mblocks} +ATF_TESTS_C+= glob_blocks_test +.endif ATF_TESTS_C+= makecontext_test +ATF_TESTS_C+= opendir_test ATF_TESTS_C+= popen_test ATF_TESTS_C+= posix_spawn_test ATF_TESTS_C+= realpath2_test +ATF_TESTS_C+= scandir_test +.if ${COMPILER_FEATURES:Mblocks} +ATF_TESTS_C+= scandir_blocks_test +.endif +ATF_TESTS_C+= sig2str_test ATF_TESTS_C+= sigsetops_test ATF_TESTS_C+= wordexp_test @@ -94,6 +106,20 @@ TEST_METADATA.setdomainname_test+= is_exclusive=true TESTS_SUBDIRS= execve TESTS_SUBDIRS+= posix_spawn +# Tests that require address sanitizer +.if ${COMPILER_FEATURES:Masan} +.for t in scandir_test realpath2_test +CFLAGS.${t}.c+= -fsanitize=address +LDFLAGS.${t}+= -fsanitize=address +.endfor +.endif + +# Tests that require blocks support +.for t in fts_blocks_test glob_blocks_test scandir_blocks_test +CFLAGS.${t}.c+= -fblocks +LIBADD.${t}+= BlocksRuntime +.endfor + # The old testcase name TEST_FNMATCH= test-fnmatch CLEANFILES+= ${GEN_SH_CASE_TESTCASES} diff --git a/lib/libc/tests/gen/Makefile.depend b/lib/libc/tests/gen/Makefile.depend index a359c100b4e2..33d10e940cd0 100644 --- a/lib/libc/tests/gen/Makefile.depend +++ b/lib/libc/tests/gen/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/gen/arc4random_test.c b/lib/libc/tests/gen/arc4random_test.c index a28db303e88c..79139f29f8fa 100644 --- a/lib/libc/tests/gen/arc4random_test.c +++ b/lib/libc/tests/gen/arc4random_test.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2011 David Schultz + * Copyright (c) 2024 Robert Clausecker <fuz@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,14 +25,12 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/types.h> #include <sys/mman.h> #include <sys/wait.h> #include <errno.h> #include <stdio.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -80,10 +79,34 @@ ATF_TC_BODY(test_arc4random, tc) "sequences are the same"); } +/* + * Test whether arc4random_uniform() returns a number below the given threshold. + * Test with various thresholds. + */ +ATF_TC_WITHOUT_HEAD(test_arc4random_uniform); +ATF_TC_BODY(test_arc4random_uniform, tc) +{ + size_t i, j; + static const uint32_t thresholds[] = { + 1, 2, 3, 4, 5, 10, 100, 1000, + INT32_MAX, (uint32_t)INT32_MAX + 1, + UINT32_MAX - 1000000000, UINT32_MAX - 1000000, UINT32_MAX - 1, 0 + }; + + for (i = 0; thresholds[i] != 0; i++) + for (j = 0; j < 10000; j++) + ATF_CHECK(arc4random_uniform(thresholds[i]) < thresholds[i]); + + /* for a threshold of zero, just check that we get zero every time */ + for (j = 0; j < 1000; j++) + ATF_CHECK_EQ(0, arc4random_uniform(0)); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, test_arc4random); + ATF_TP_ADD_TC(tp, test_arc4random_uniform); return (atf_no_error()); } diff --git a/lib/libc/tests/gen/dir2_test.c b/lib/libc/tests/gen/dir2_test.c index 3322a5e5086c..4ec5a1759d06 100644 --- a/lib/libc/tests/gen/dir2_test.c +++ b/lib/libc/tests/gen/dir2_test.c @@ -31,9 +31,6 @@ * opendir, readdir, seekdir, telldir, closedir, etc */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <dirent.h> #include <fcntl.h> #include <stdio.h> diff --git a/lib/libc/tests/gen/dlopen_empty_test.c b/lib/libc/tests/gen/dlopen_empty_test.c index 42f9269a10b2..6fb3bf8d8343 100644 --- a/lib/libc/tests/gen/dlopen_empty_test.c +++ b/lib/libc/tests/gen/dlopen_empty_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/stat.h> #include <dlfcn.h> #include <errno.h> diff --git a/lib/libc/tests/gen/execve/Makefile b/lib/libc/tests/gen/execve/Makefile index 5e8bc6fb7640..7bf911d1cb47 100644 --- a/lib/libc/tests/gen/execve/Makefile +++ b/lib/libc/tests/gen/execve/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> NETBSD_ATF_TESTS_C= execve_test diff --git a/lib/libc/tests/gen/execve/Makefile.depend b/lib/libc/tests/gen/execve/Makefile.depend index 10e58b789640..e89a5c52c82a 100644 --- a/lib/libc/tests/gen/execve/Makefile.depend +++ b/lib/libc/tests/gen/execve/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/gen/fmtcheck_test.c b/lib/libc/tests/gen/fmtcheck_test.c index 3e180c9ca2e6..27a12217e81e 100644 --- a/lib/libc/tests/gen/fmtcheck_test.c +++ b/lib/libc/tests/gen/fmtcheck_test.c @@ -28,9 +28,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <err.h> #include <stdio.h> diff --git a/lib/libc/tests/gen/fmtmsg_test.c b/lib/libc/tests/gen/fmtmsg_test.c index aa3ca19425fe..30a5156cdcc8 100644 --- a/lib/libc/tests/gen/fmtmsg_test.c +++ b/lib/libc/tests/gen/fmtmsg_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/wait.h> #include <err.h> diff --git a/lib/libc/tests/gen/fnmatch_test.c b/lib/libc/tests/gen/fnmatch_test.c index 8d9ead2eff91..0ff7400a4a4f 100644 --- a/lib/libc/tests/gen/fnmatch_test.c +++ b/lib/libc/tests/gen/fnmatch_test.c @@ -24,11 +24,9 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <errno.h> +#include <locale.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -179,10 +177,90 @@ ATF_TC_BODY(fnmatch_test, tc) } +ATF_TC(fnmatch_characterclass); +ATF_TC_HEAD(fnmatch_characterclass, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test fnmatch with character classes"); +} + +ATF_TC_BODY(fnmatch_characterclass, tc) +{ + ATF_CHECK(fnmatch("[[:alnum:]]", "a", 0) == 0); + ATF_CHECK(fnmatch("[[:cntrl:]]", "\a", 0) == 0); + ATF_CHECK(fnmatch("[[:lower:]]", "a", 0) == 0); + ATF_CHECK(fnmatch("[[:space:]]", " ", 0) == 0); + ATF_CHECK(fnmatch("[[:alpha:]]", "a", 0) == 0); + ATF_CHECK(fnmatch("[[:digit:]]", "0", 0) == 0); + ATF_CHECK(fnmatch("[[:print:]]", "a", 0) == 0); + ATF_CHECK(fnmatch("[[:upper:]]", "A", 0) == 0); + ATF_CHECK(fnmatch("[[:blank:]]", " ", 0) == 0); + ATF_CHECK(fnmatch("[[:graph:]]", "a", 0) == 0); + ATF_CHECK(fnmatch("[[:punct:]]", ".", 0) == 0); + ATF_CHECK(fnmatch("[[:xdigit:]]", "f", 0) == 0); + + /* + * POSIX.1, section 9.3.5. states that '[:' and ':]' + * should be interpreted as character classes symbol only + * when part of a bracket expression. + */ + ATF_CHECK(fnmatch("[:alnum:]", "a", 0) == 0); + ATF_CHECK(fnmatch("[:alnum:]", ":", 0) == 0); + ATF_CHECK(fnmatch("[:alnum:]", "1", 0) != 0); +} + +ATF_TC(fnmatch_collsym); +ATF_TC_HEAD(fnmatch_collsym, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test fnmatch with collating symbols"); +} + +ATF_TC_BODY(fnmatch_collsym, tc) +{ + setlocale(LC_ALL, "cs_CZ.UTF-8"); + ATF_CHECK(fnmatch("[ch]", "ch", 0) != 0); + ATF_CHECK(fnmatch("[[.ch.]]", "ch", 0) == 0); + ATF_CHECK(fnmatch("[[.ch.]]h", "chh", 0) == 0); + + /* + * POSIX.1, section 9.3.5. states that '[.' and '.]' + * should be interpreted as a collating symbol only + * when part of a bracket expression. + */ + ATF_CHECK(fnmatch("[.ch.]", "c", 0) == 0); + ATF_CHECK(fnmatch("[.ch.]", "h", 0) == 0); + ATF_CHECK(fnmatch("[.ch.]", ".", 0) == 0); +} + +ATF_TC(fnmatch_equivclass); +ATF_TC_HEAD(fnmatch_equivclass, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test fnmatch with equivalence classes"); +} + +ATF_TC_BODY(fnmatch_equivclass, tc) +{ + setlocale(LC_ALL, "en_US.UTF-8"); + ATF_CHECK(fnmatch("[[=a=]]b", "ab", 0) == 0); + ATF_CHECK(fnmatch("[[=a=]]b", "Ab", 0) == 0); + ATF_CHECK(fnmatch("[[=à =]]b", "ab", 0) == 0); + ATF_CHECK(fnmatch("[[=a=]]b", "à b", 0) == 0); + + /* + * POSIX.1, section 9.3.5. states that '[=' and '=]' + * should be interpreted as an equivalence class only + * when part of a bracket expression. + */ + ATF_CHECK(fnmatch("[=a=]b", "=b", 0) == 0); + ATF_CHECK(fnmatch("[=a=]b", "ab", 0) == 0); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, fnmatch_test); + ATF_TP_ADD_TC(tp, fnmatch_collsym); + ATF_TP_ADD_TC(tp, fnmatch_characterclass); + ATF_TP_ADD_TC(tp, fnmatch_equivclass); return (atf_no_error()); } diff --git a/lib/libc/tests/gen/fnmatch_testcases.h b/lib/libc/tests/gen/fnmatch_testcases.h index 996e13c7756b..196160a4801b 100644 --- a/lib/libc/tests/gen/fnmatch_testcases.h +++ b/lib/libc/tests/gen/fnmatch_testcases.h @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <fnmatch.h> struct testcase { diff --git a/lib/libc/tests/gen/fpclassify2_test.c b/lib/libc/tests/gen/fpclassify2_test.c index a6bb1df3c9f2..45180ac5be42 100644 --- a/lib/libc/tests/gen/fpclassify2_test.c +++ b/lib/libc/tests/gen/fpclassify2_test.c @@ -22,8 +22,6 @@ * 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. - * - * $FreeBSD$ */ #include <math.h> diff --git a/lib/libc/tests/gen/fts_blocks_test.c b/lib/libc/tests/gen/fts_blocks_test.c new file mode 100644 index 000000000000..f020dd8dea45 --- /dev/null +++ b/lib/libc/tests/gen/fts_blocks_test.c @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <fcntl.h> +#include <fts.h> + +#include <atf-c.h> + +/* + * Create two directories with three files each in lexicographical order, + * then call FTS with a sort block that sorts in reverse lexicographical + * order. This has the least chance of getting a false positive due to + * differing file system semantics. UFS will return the files in the + * order they were created while ZFS will sort them lexicographically; in + * both cases, the order we expect is the reverse. + */ +ATF_TC(fts_blocks_test); +ATF_TC_HEAD(fts_blocks_test, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test FTS with a block in lieu of a comparison function"); +} +ATF_TC_BODY(fts_blocks_test, tc) +{ + char *args[] = { + "bar", "foo", NULL + }; + char *paths[] = { + "foo", "z", "y", "x", "foo", + "bar", "c", "b", "a", "bar", + NULL + }; + char **expect = paths; + FTS *fts; + FTSENT *ftse; + + ATF_REQUIRE_EQ(0, mkdir("bar", 0755)); + ATF_REQUIRE_EQ(0, close(creat("bar/a", 0644))); + ATF_REQUIRE_EQ(0, close(creat("bar/b", 0644))); + ATF_REQUIRE_EQ(0, close(creat("bar/c", 0644))); + ATF_REQUIRE_EQ(0, mkdir("foo", 0755)); + ATF_REQUIRE_EQ(0, close(creat("foo/x", 0644))); + ATF_REQUIRE_EQ(0, close(creat("foo/y", 0644))); + ATF_REQUIRE_EQ(0, close(creat("foo/z", 0644))); + fts = fts_open_b(args, 0, + ^(const FTSENT * const *a, const FTSENT * const *b) { + return (strcmp((*b)->fts_name, (*a)->fts_name)); + }); + ATF_REQUIRE_MSG(fts != NULL, "fts_open_b(): %m"); + while ((ftse = fts_read(fts)) != NULL && *expect != NULL) { + ATF_CHECK_STREQ(*expect, ftse->fts_name); + expect++; + } + ATF_CHECK_EQ(NULL, ftse); + ATF_CHECK_EQ(NULL, *expect); + ATF_REQUIRE_EQ_MSG(0, fts_close(fts), "fts_close(): %m"); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, fts_blocks_test); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/fts_misc_test.c b/lib/libc/tests/gen/fts_misc_test.c new file mode 100644 index 000000000000..91640078f63c --- /dev/null +++ b/lib/libc/tests/gen/fts_misc_test.c @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <fcntl.h> +#include <fts.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <atf-c.h> + +#include "fts_test.h" + +ATF_TC(fts_unrdir); +ATF_TC_HEAD(fts_unrdir, tc) +{ + atf_tc_set_md_var(tc, "descr", "unreadable directories"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} +ATF_TC_BODY(fts_unrdir, tc) +{ + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + ATF_REQUIRE_EQ(0, mkdir("dir/unr", 0100)); + ATF_REQUIRE_EQ(0, mkdir("dir/unx", 0400)); + fts_test(tc, &(struct fts_testcase){ + (char *[]){ "dir", NULL }, + FTS_PHYSICAL, + (struct fts_expect[]){ + { FTS_D, "dir", "dir" }, + { FTS_D, "unr", "unr" }, + { FTS_DNR, "unr", "unr" }, + { FTS_D, "unx", "unx" }, + { FTS_DP, "unx", "unx" }, + { FTS_DP, "dir", "dir" }, + { 0 } + }, + }); +} + +ATF_TC(fts_unrdir_nochdir); +ATF_TC_HEAD(fts_unrdir_nochdir, tc) +{ + atf_tc_set_md_var(tc, "descr", "unreadable directories (nochdir)"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} +ATF_TC_BODY(fts_unrdir_nochdir, tc) +{ + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + ATF_REQUIRE_EQ(0, mkdir("dir/unr", 0100)); + ATF_REQUIRE_EQ(0, mkdir("dir/unx", 0400)); + fts_test(tc, &(struct fts_testcase){ + (char *[]){ "dir", NULL }, + FTS_PHYSICAL | FTS_NOCHDIR, + (struct fts_expect[]){ + { FTS_D, "dir", "dir" }, + { FTS_D, "unr", "dir/unr" }, + { FTS_DNR, "unr", "dir/unr" }, + { FTS_D, "unx", "dir/unx" }, + { FTS_DP, "unx", "dir/unx" }, + { FTS_DP, "dir", "dir" }, + { 0 } + }, + }); +} + +ATF_TP_ADD_TCS(tp) +{ + fts_check_debug(); + ATF_TP_ADD_TC(tp, fts_unrdir); + ATF_TP_ADD_TC(tp, fts_unrdir_nochdir); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/fts_options_test.c b/lib/libc/tests/gen/fts_options_test.c new file mode 100644 index 000000000000..fc3015138a49 --- /dev/null +++ b/lib/libc/tests/gen/fts_options_test.c @@ -0,0 +1,394 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <fcntl.h> +#include <fts.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <atf-c.h> + +#include "fts_test.h" + +static char *all_paths[] = { + "dir", + "dirl", + "file", + "filel", + "dead", + "noent", + NULL +}; + +/* + * Prepare the files and directories we will be inspecting. + */ +static void +fts_options_prepare(const struct atf_tc *tc) +{ + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + ATF_REQUIRE_EQ(0, close(creat("file", 0644))); + ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644))); + ATF_REQUIRE_EQ(0, symlink("..", "dir/up")); + ATF_REQUIRE_EQ(0, symlink("dir", "dirl")); + ATF_REQUIRE_EQ(0, symlink("file", "filel")); + ATF_REQUIRE_EQ(0, symlink("noent", "dead")); +} + +ATF_TC(fts_options_logical); +ATF_TC_HEAD(fts_options_logical, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_LOGICAL"); +} +ATF_TC_BODY(fts_options_logical, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_LOGICAL, + (struct fts_expect[]){ + { FTS_DL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_F, "file", "dir/file" }, + { FTS_D, "up", "dir/up" }, + { FTS_DL, "dead", "dir/up/dead" }, + { FTS_DC, "dir", "dir/up/dir" }, + { FTS_DC, "dirl", "dir/up/dirl" }, + { FTS_F, "file", "dir/up/file" }, + { FTS_F, "filel", "dir/up/filel" }, + { FTS_DP, "up", "dir/up" }, + { FTS_DP, "dir", "dir" }, + { FTS_D, "dirl", "dirl" }, + { FTS_F, "file", "dirl/file" }, + { FTS_D, "up", "dirl/up" }, + { FTS_DL, "dead", "dirl/up/dead" }, + { FTS_DC, "dir", "dirl/up/dir" }, + { FTS_DC, "dirl", "dirl/up/dirl" }, + { FTS_F, "file", "dirl/up/file" }, + { FTS_F, "filel", "dirl/up/filel" }, + { FTS_DP, "up", "dirl/up" }, + { FTS_DP, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_F, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_logical_nostat); +ATF_TC_HEAD(fts_options_logical_nostat, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_LOGICAL | FTS_NOSTAT"); +} +ATF_TC_BODY(fts_options_logical_nostat, tc) +{ + /* + * While FTS_LOGICAL is not documented as being incompatible with + * FTS_NOSTAT, and FTS does not clear FTS_NOSTAT if FTS_LOGICAL is + * set, FTS_LOGICAL effectively nullifies FTS_NOSTAT by overriding + * the follow check in fts_stat(). In theory, FTS could easily be + * changed to only stat links (to check what they point to) in the + * FTS_LOGICAL | FTS_NOSTAT case, which would produce a different + * result here, so keep the test around in case that ever happens. + */ + atf_tc_expect_fail("FTS_LOGICAL nullifies FTS_NOSTAT"); + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_LOGICAL | FTS_NOSTAT, + (struct fts_expect[]){ + { FTS_DL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_NSOK, "file", "dir/file" }, + { FTS_D, "up", "dir/up" }, + { FTS_DL, "dead", "dir/up/dead" }, + { FTS_DC, "dir", "dir/up/dir" }, + { FTS_DC, "dirl", "dir/up/dirl" }, + { FTS_NSOK, "file", "dir/up/file" }, + { FTS_NSOK, "filel", "dir/up/filel" }, + { FTS_DP, "up", "dir/up" }, + { FTS_DP, "dir", "dir" }, + { FTS_D, "dirl", "dirl" }, + { FTS_NSOK, "file", "dirl/file" }, + { FTS_D, "up", "dirl/up" }, + { FTS_DL, "dead", "dirl/up/dead" }, + { FTS_DC, "dir", "dirl/up/dir" }, + { FTS_DC, "dirl", "dirl/up/dirl" }, + { FTS_NSOK, "file", "dirl/up/file" }, + { FTS_NSOK, "filel", "dirl/up/filel" }, + { FTS_DP, "up", "dirl/up" }, + { FTS_DP, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_F, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_logical_seedot); +ATF_TC_HEAD(fts_options_logical_seedot, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_LOGICAL | FTS_SEEDOT"); +} +ATF_TC_BODY(fts_options_logical_seedot, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_LOGICAL | FTS_SEEDOT, + (struct fts_expect[]){ + { FTS_DL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_DOT, ".", "dir/." }, + { FTS_DOT, "..", "dir/.." }, + { FTS_F, "file", "dir/file" }, + { FTS_D, "up", "dir/up" }, + { FTS_DOT, ".", "dir/up/." }, + { FTS_DOT, "..", "dir/up/.." }, + { FTS_DL, "dead", "dir/up/dead" }, + { FTS_DC, "dir", "dir/up/dir" }, + { FTS_DC, "dirl", "dir/up/dirl" }, + { FTS_F, "file", "dir/up/file" }, + { FTS_F, "filel", "dir/up/filel" }, + { FTS_DP, "up", "dir/up" }, + { FTS_DP, "dir", "dir" }, + { FTS_D, "dirl", "dirl" }, + { FTS_DOT, ".", "dirl/." }, + { FTS_DOT, "..", "dirl/.." }, + { FTS_F, "file", "dirl/file" }, + { FTS_D, "up", "dirl/up" }, + { FTS_DOT, ".", "dirl/up/." }, + { FTS_DOT, "..", "dirl/up/.." }, + { FTS_DL, "dead", "dirl/up/dead" }, + { FTS_DC, "dir", "dirl/up/dir" }, + { FTS_DC, "dirl", "dirl/up/dirl" }, + { FTS_F, "file", "dirl/up/file" }, + { FTS_F, "filel", "dirl/up/filel" }, + { FTS_DP, "up", "dirl/up" }, + { FTS_DP, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_F, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical); +ATF_TC_HEAD(fts_options_physical, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL"); +} +ATF_TC_BODY(fts_options_physical, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL, + (struct fts_expect[]){ + { FTS_SL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dir", "dir" }, + { FTS_SL, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical_nochdir); +ATF_TC_HEAD(fts_options_physical_nochdir, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_NOCHDIR"); +} +ATF_TC_BODY(fts_options_physical_nochdir, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL | FTS_NOCHDIR, + (struct fts_expect[]){ + { FTS_SL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_F, "file", "dir/file" }, + { FTS_SL, "up", "dir/up" }, + { FTS_DP, "dir", "dir" }, + { FTS_SL, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical_comfollow); +ATF_TC_HEAD(fts_options_physical_comfollow, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_COMFOLLOW"); +} +ATF_TC_BODY(fts_options_physical_comfollow, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL | FTS_COMFOLLOW, + (struct fts_expect[]){ + { FTS_DL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dir", "dir" }, + { FTS_D, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_F, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical_comfollowdir); +ATF_TC_HEAD(fts_options_physical_comfollowdir, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_COMFOLLOWDIR"); +} +ATF_TC_BODY(fts_options_physical_comfollowdir, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL | FTS_COMFOLLOWDIR, + (struct fts_expect[]){ + { FTS_DL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dir", "dir" }, + { FTS_D, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical_nostat); +ATF_TC_HEAD(fts_options_physical_nostat, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_NOSTAT"); +} +ATF_TC_BODY(fts_options_physical_nostat, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL | FTS_NOSTAT, + (struct fts_expect[]){ + { FTS_SL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_NSOK, "file", "file" }, + { FTS_NSOK, "up", "up" }, + { FTS_DP, "dir", "dir" }, + { FTS_SL, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical_nostat_type); +ATF_TC_HEAD(fts_options_physical_nostat_type, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_NOSTAT_TYPE"); +} +ATF_TC_BODY(fts_options_physical_nostat_type, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL | FTS_NOSTAT_TYPE, + (struct fts_expect[]){ + { FTS_SL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dir", "dir" }, + { FTS_SL, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical_seedot); +ATF_TC_HEAD(fts_options_physical_seedot, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_SEEDOT"); +} +ATF_TC_BODY(fts_options_physical_seedot, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL | FTS_SEEDOT, + (struct fts_expect[]){ + { FTS_SL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_DOT, ".", "." }, + { FTS_DOT, "..", ".." }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dir", "dir" }, + { FTS_SL, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +/* + * TODO: Add tests for FTS_XDEV and FTS_WHITEOUT + */ + +ATF_TP_ADD_TCS(tp) +{ + fts_check_debug(); + ATF_TP_ADD_TC(tp, fts_options_logical); + ATF_TP_ADD_TC(tp, fts_options_logical_nostat); + ATF_TP_ADD_TC(tp, fts_options_logical_seedot); + ATF_TP_ADD_TC(tp, fts_options_physical); + ATF_TP_ADD_TC(tp, fts_options_physical_nochdir); + ATF_TP_ADD_TC(tp, fts_options_physical_comfollow); + ATF_TP_ADD_TC(tp, fts_options_physical_comfollowdir); + ATF_TP_ADD_TC(tp, fts_options_physical_nostat); + ATF_TP_ADD_TC(tp, fts_options_physical_nostat_type); + ATF_TP_ADD_TC(tp, fts_options_physical_seedot); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/fts_test.h b/lib/libc/tests/gen/fts_test.h new file mode 100644 index 000000000000..b3f15050f265 --- /dev/null +++ b/lib/libc/tests/gen/fts_test.h @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef FTS_TEST_H_INCLUDED +#define FTS_TEST_H_INCLUDED + +struct fts_expect { + int fts_info; + const char *fts_name; + const char *fts_accpath; +}; + +struct fts_testcase { + char **paths; + int fts_options; + struct fts_expect *fts_expect; +}; + +/* shorter name for dead links */ +#define FTS_DL FTS_SLNONE + +/* are we being debugged? */ +static bool fts_test_debug; + +/* + * Set debug flag if appropriate. + */ +static void +fts_check_debug(void) +{ + fts_test_debug = !getenv("__RUNNING_INSIDE_ATF_RUN") && + isatty(STDERR_FILENO); +} + +/* + * Lexical order for reproducability. + */ +static int +fts_lexical_compar(const FTSENT * const *a, const FTSENT * const *b) +{ + return (strcmp((*a)->fts_name, (*b)->fts_name)); +} + +/* + * Run FTS with the specified paths and options and verify that it + * produces the expected result in the correct order. + */ +static void +fts_test(const struct atf_tc *tc, const struct fts_testcase *fts_tc) +{ + FTS *fts; + FTSENT *ftse; + const struct fts_expect *expect = fts_tc->fts_expect; + long level = 0; + + fts = fts_open(fts_tc->paths, fts_tc->fts_options, fts_lexical_compar); + ATF_REQUIRE_MSG(fts != NULL, "fts_open(): %m"); + while ((ftse = fts_read(fts)) != NULL && expect->fts_name != NULL) { + if (expect->fts_info == FTS_DP || expect->fts_info == FTS_DNR) + level--; + if (fts_test_debug) { + fprintf(stderr, "%2ld %2d %s\n", level, + ftse->fts_info, ftse->fts_name); + } + ATF_CHECK_STREQ(expect->fts_name, ftse->fts_name); + ATF_CHECK_STREQ(expect->fts_accpath, ftse->fts_accpath); + ATF_CHECK_INTEQ(expect->fts_info, ftse->fts_info); + ATF_CHECK_INTEQ(level, ftse->fts_level); + if (expect->fts_info == FTS_D) + level++; + expect++; + } + ATF_CHECK_EQ(NULL, ftse); + ATF_CHECK_EQ(NULL, expect->fts_name); + ATF_REQUIRE_EQ_MSG(0, fts_close(fts), "fts_close(): %m"); +} + +#endif /* FTS_TEST_H_INCLUDED */ diff --git a/lib/libc/tests/gen/ftw_test.c b/lib/libc/tests/gen/ftw_test.c index b120f01ff4f1..3d2cf3446dee 100644 --- a/lib/libc/tests/gen/ftw_test.c +++ b/lib/libc/tests/gen/ftw_test.c @@ -28,9 +28,6 @@ * Limited test program for nftw() as specified by IEEE Std. 1003.1-2008. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/wait.h> #include <err.h> #include <errno.h> diff --git a/lib/libc/tests/gen/getentropy_test.c b/lib/libc/tests/gen/getentropy_test.c index 1290e6e50529..6ac9d5678ea6 100644 --- a/lib/libc/tests/gen/getentropy_test.c +++ b/lib/libc/tests/gen/getentropy_test.c @@ -1,5 +1,5 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 Conrad Meyer <cem@FreeBSD.org> * All rights reserved. @@ -26,11 +26,9 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <errno.h> +#include <limits.h> #include <signal.h> #include <unistd.h> @@ -65,13 +63,13 @@ ATF_TC_BODY(getentropy_sizes, tc) char buf[512]; ATF_REQUIRE_EQ(getentropy(buf, sizeof(buf)), -1); - ATF_REQUIRE_EQ(errno, EIO); - ATF_REQUIRE_EQ(getentropy(buf, 257), -1); - ATF_REQUIRE_EQ(errno, EIO); + ATF_REQUIRE_EQ(errno, EINVAL); + ATF_REQUIRE_EQ(getentropy(buf, GETENTROPY_MAX + 1), -1); + ATF_REQUIRE_EQ(errno, EINVAL); /* Smaller sizes always succeed: */ - ATF_REQUIRE_EQ(getentropy(buf, 256), 0); - ATF_REQUIRE_EQ(getentropy(buf, 128), 0); + ATF_REQUIRE_EQ(getentropy(buf, GETENTROPY_MAX), 0); + ATF_REQUIRE_EQ(getentropy(buf, GETENTROPY_MAX / 2), 0); ATF_REQUIRE_EQ(getentropy(buf, 0), 0); } diff --git a/lib/libc/tests/gen/getmntinfo_test.c b/lib/libc/tests/gen/getmntinfo_test.c index 183fa84ed0e6..06e1091d8a15 100644 --- a/lib/libc/tests/gen/getmntinfo_test.c +++ b/lib/libc/tests/gen/getmntinfo_test.c @@ -28,9 +28,6 @@ * Limited test program for getmntinfo(3), a non-standard BSDism. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/mount.h> #include <sys/ucred.h> diff --git a/lib/libc/tests/gen/glob2_test.c b/lib/libc/tests/gen/glob2_test.c index dfcce0eed3da..ff1b36b830b8 100644 --- a/lib/libc/tests/gen/glob2_test.c +++ b/lib/libc/tests/gen/glob2_test.c @@ -24,13 +24,13 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> +#include <sys/stat.h> + #include <errno.h> #include <fcntl.h> #include <glob.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -105,10 +105,80 @@ ATF_TC_BODY(glob_pathological_test, tc) } } +ATF_TC(glob_period); +ATF_TC_HEAD(glob_period, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test behaviour when matching files that start with a period" + "(documented in the glob(3) CAVEATS section)."); +} +ATF_TC_BODY(glob_period, tc) +{ + int i; + glob_t g; + + atf_utils_create_file(".test", ""); + glob(".", 0, NULL, &g); + ATF_REQUIRE_MSG(g.gl_matchc == 1, + "glob(3) shouldn't match files starting with a period when using '.'"); + for (i = 0; i < g.gl_matchc; i++) + printf("%s\n", g.gl_pathv[i]); + glob(".*", 0, NULL, &g); + ATF_REQUIRE_MSG(g.gl_matchc == 3 && strcmp(g.gl_pathv[2], ".test") == 0, + "glob(3) should match files starting with a period when using '.*'"); +} + +static bool glob_callback_invoked; + +static int +errfunc(const char *path, int err) +{ + ATF_CHECK_STREQ(path, "test/"); + ATF_CHECK(err == EACCES); + glob_callback_invoked = true; + /* Suppress EACCES errors. */ + return (0); +} + +ATF_TC(glob_callback); +ATF_TC_HEAD(glob_callback, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test ability of callback function to suppress errors"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} +ATF_TC_BODY(glob_callback, tc) +{ + glob_t g; + int rv; + + ATF_REQUIRE_EQ(0, mkdir("test", 0755)); + ATF_REQUIRE_EQ(0, symlink("foo", "test/foo")); + ATF_REQUIRE_EQ(0, chmod("test", 0)); + + glob_callback_invoked = false; + rv = glob("test/*", 0, errfunc, &g); + ATF_CHECK_MSG(glob_callback_invoked, + "glob(3) failed to invoke callback function"); + ATF_CHECK_EQ_MSG(GLOB_NOMATCH, rv, + "callback function failed to suppress EACCES"); + globfree(&g); + + /* GLOB_ERR should ignore the suppressed error. */ + glob_callback_invoked = false; + rv = glob("test/*", GLOB_ERR, errfunc, &g); + ATF_CHECK_MSG(glob_callback_invoked, + "glob(3) failed to invoke callback function"); + ATF_CHECK_EQ_MSG(GLOB_ABORTED, rv, + "GLOB_ERR didn't override callback function"); + globfree(&g); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, glob_pathological_test); - + ATF_TP_ADD_TC(tp, glob_period); + ATF_TP_ADD_TC(tp, glob_callback); return (atf_no_error()); } diff --git a/lib/libc/tests/gen/glob_blocks_test.c b/lib/libc/tests/gen/glob_blocks_test.c new file mode 100644 index 000000000000..629b90bee762 --- /dev/null +++ b/lib/libc/tests/gen/glob_blocks_test.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <errno.h> +#include <glob.h> +#include <stdbool.h> + +#include <atf-c.h> + +ATF_TC(glob_b_callback); +ATF_TC_HEAD(glob_b_callback, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test ability of callback block to suppress errors"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} +ATF_TC_BODY(glob_b_callback, tc) +{ + static bool glob_callback_invoked; + static int (^errblk)(const char *, int) = + ^(const char *path, int err) { + ATF_CHECK_STREQ(path, "test/"); + ATF_CHECK(err == EACCES); + glob_callback_invoked = true; + /* Suppress EACCES errors. */ + return (0); + }; + glob_t g; + int rv; + + ATF_REQUIRE_EQ(0, mkdir("test", 0755)); + ATF_REQUIRE_EQ(0, symlink("foo", "test/foo")); + ATF_REQUIRE_EQ(0, chmod("test", 0)); + + glob_callback_invoked = false; + rv = glob_b("test/*", 0, errblk, &g); + ATF_CHECK_MSG(glob_callback_invoked, + "glob(3) failed to invoke callback block"); + ATF_CHECK_EQ_MSG(GLOB_NOMATCH, rv, + "callback function failed to suppress EACCES"); + globfree(&g); + + /* GLOB_ERR should ignore the suppressed error. */ + glob_callback_invoked = false; + rv = glob_b("test/*", GLOB_ERR, errblk, &g); + ATF_CHECK_MSG(glob_callback_invoked, + "glob(3) failed to invoke callback block"); + ATF_CHECK_EQ_MSG(GLOB_ABORTED, rv, + "GLOB_ERR didn't override callback block"); + globfree(&g); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, glob_b_callback); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/makecontext_test.c b/lib/libc/tests/gen/makecontext_test.c index 50d835d15cbe..23e3cf85f677 100644 --- a/lib/libc/tests/gen/makecontext_test.c +++ b/lib/libc/tests/gen/makecontext_test.c @@ -1,5 +1,5 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 John H. Baldwin <jhb@FreeBSD.org> * @@ -25,9 +25,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <atf-c.h> #include <ucontext.h> diff --git a/lib/libc/tests/gen/opendir_test.c b/lib/libc/tests/gen/opendir_test.c new file mode 100644 index 000000000000..b7481255654f --- /dev/null +++ b/lib/libc/tests/gen/opendir_test.c @@ -0,0 +1,145 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + +#include <atf-c.h> + +/* + * Create a directory with a single subdirectory. + */ +static void +opendir_prepare(const struct atf_tc *tc) +{ + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + ATF_REQUIRE_EQ(0, mkdir("dir/subdir", 0755)); +} + +/* + * Assuming dirp represents the directory created by opendir_prepare(), + * verify that readdir() returns what we expected to see there. + */ +static void +opendir_check(const struct atf_tc *tc, DIR *dirp) +{ + struct dirent *ent; + + ATF_REQUIRE((ent = readdir(dirp)) != NULL); + ATF_CHECK_EQ(1, ent->d_namlen); + ATF_CHECK_STREQ(".", ent->d_name); + ATF_CHECK_EQ(DT_DIR, ent->d_type); + ATF_REQUIRE((ent = readdir(dirp)) != NULL); + ATF_CHECK_EQ(2, ent->d_namlen); + ATF_CHECK_STREQ("..", ent->d_name); + ATF_CHECK_EQ(DT_DIR, ent->d_type); + ATF_REQUIRE((ent = readdir(dirp)) != NULL); + ATF_CHECK_EQ(sizeof("subdir") - 1, ent->d_namlen); + ATF_CHECK_STREQ("subdir", ent->d_name); + ATF_CHECK_EQ(DT_DIR, ent->d_type); + ATF_CHECK(readdir(dirp) == NULL); + ATF_CHECK(readdir(dirp) == NULL); +} + +ATF_TC(opendir_ok); +ATF_TC_HEAD(opendir_ok, tc) +{ + atf_tc_set_md_var(tc, "descr", "Open a directory."); +} +ATF_TC_BODY(opendir_ok, tc) +{ + DIR *dirp; + + opendir_prepare(tc); + ATF_REQUIRE((dirp = opendir("dir")) != NULL); + opendir_check(tc, dirp); + ATF_CHECK_EQ(0, closedir(dirp)); +} + +ATF_TC(opendir_fifo); +ATF_TC_HEAD(opendir_fifo, tc) +{ + atf_tc_set_md_var(tc, "descr", "Do not hang if given a named pipe."); +} +ATF_TC_BODY(opendir_fifo, tc) +{ + DIR *dirp; + int fd; + + ATF_REQUIRE((fd = mkfifo("fifo", 0644)) >= 0); + ATF_REQUIRE_EQ(0, close(fd)); + ATF_REQUIRE((dirp = opendir("fifo")) == NULL); + ATF_CHECK_EQ(ENOTDIR, errno); +} + +ATF_TC(fdopendir_ok); +ATF_TC_HEAD(fdopendir_ok, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Open a directory from a directory descriptor."); +} +ATF_TC_BODY(fdopendir_ok, tc) +{ + DIR *dirp; + int dd; + + opendir_prepare(tc); + ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); + ATF_REQUIRE((dirp = fdopendir(dd)) != NULL); + opendir_check(tc, dirp); + ATF_CHECK_EQ(dd, fdclosedir(dirp)); + ATF_CHECK_EQ(0, close(dd)); +} + +ATF_TC(fdopendir_ebadf); +ATF_TC_HEAD(fdopendir_ebadf, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Open a directory from an invalid descriptor."); +} +ATF_TC_BODY(fdopendir_ebadf, tc) +{ + DIR *dirp; + int dd; + + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); + ATF_CHECK_EQ(0, close(dd)); + ATF_REQUIRE((dirp = fdopendir(dd)) == NULL); + ATF_CHECK_EQ(EBADF, errno); +} + +ATF_TC(fdopendir_enotdir); +ATF_TC_HEAD(fdopendir_enotdir, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Open a directory from a non-directory descriptor."); +} +ATF_TC_BODY(fdopendir_enotdir, tc) +{ + DIR *dirp; + int fd; + + ATF_REQUIRE((fd = open("file", O_CREAT | O_RDWR, 0644)) >= 0); + ATF_REQUIRE((dirp = fdopendir(fd)) == NULL); + ATF_CHECK_EQ(ENOTDIR, errno); + ATF_CHECK_EQ(0, close(fd)); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, opendir_ok); + ATF_TP_ADD_TC(tp, fdopendir_ok); + ATF_TP_ADD_TC(tp, fdopendir_ebadf); + ATF_TP_ADD_TC(tp, fdopendir_enotdir); + ATF_TP_ADD_TC(tp, opendir_fifo); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/popen_test.c b/lib/libc/tests/gen/popen_test.c index 5c615b7146e9..43eadd380f39 100644 --- a/lib/libc/tests/gen/popen_test.c +++ b/lib/libc/tests/gen/popen_test.c @@ -29,9 +29,6 @@ * with BSD extensions. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/wait.h> #include <errno.h> diff --git a/lib/libc/tests/gen/posix_spawn/Makefile b/lib/libc/tests/gen/posix_spawn/Makefile index 21feba9dce05..df428876708b 100644 --- a/lib/libc/tests/gen/posix_spawn/Makefile +++ b/lib/libc/tests/gen/posix_spawn/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> BINDIR= ${TESTSDIR} diff --git a/lib/libc/tests/gen/posix_spawn/Makefile.depend b/lib/libc/tests/gen/posix_spawn/Makefile.depend index 10e58b789640..e89a5c52c82a 100644 --- a/lib/libc/tests/gen/posix_spawn/Makefile.depend +++ b/lib/libc/tests/gen/posix_spawn/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/gen/posix_spawn_test.c b/lib/libc/tests/gen/posix_spawn_test.c index 46259cbf8cde..22133cf1d59a 100644 --- a/lib/libc/tests/gen/posix_spawn_test.c +++ b/lib/libc/tests/gen/posix_spawn_test.c @@ -29,11 +29,11 @@ * IEEE Std. 1003.1-2008. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - +#include <sys/param.h> +#include <sys/stat.h> #include <sys/wait.h> #include <errno.h> +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -41,6 +41,10 @@ __FBSDID("$FreeBSD$"); #include <atf-c.h> +static const char true_script[] = + "#!/usr/bin/env\n" + "/usr/bin/true\n"; + char *myenv[2] = { "answer=42", NULL }; ATF_TC_WITHOUT_HEAD(posix_spawn_simple_test); @@ -127,6 +131,48 @@ ATF_TC_BODY(posix_spawnp_enoexec_fallback_null_argv0, tc) ATF_REQUIRE(error == EINVAL); } +ATF_TC(posix_spawnp_eacces); +ATF_TC_HEAD(posix_spawnp_eacces, tc) +{ + atf_tc_set_md_var(tc, "descr", "Verify EACCES behavior in posix_spawnp"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} +ATF_TC_BODY(posix_spawnp_eacces, tc) +{ + const struct spawnp_eacces_tc { + const char *pathvar; + int error_expected; + } spawnp_eacces_tests[] = { + { ".", EACCES }, /* File exists, but not +x */ + { "unsearchable", ENOENT }, /* File exists, dir not +x */ + }; + char *myargs[2] = { "eacces", NULL }; + int error; + + error = mkdir("unsearchable", 0755); + ATF_REQUIRE(error == 0); + error = symlink("/usr/bin/true", "unsearchable/eacces"); + ATF_REQUIRE(error == 0); + + (void)chmod("unsearchable", 0444); + + /* this will create a non-executable file */ + atf_utils_create_file("eacces", true_script); + + for (size_t i = 0; i < nitems(spawnp_eacces_tests); i++) { + const struct spawnp_eacces_tc *tc = &spawnp_eacces_tests[i]; + pid_t pid; + + error = setenv("PATH", tc->pathvar, 1); + ATF_REQUIRE_EQ(0, error); + + error = posix_spawnp(&pid, myargs[0], NULL, NULL, myargs, + myenv); + ATF_CHECK_INTEQ_MSG(tc->error_expected, error, + "path '%s'", tc->pathvar); + } +} + ATF_TP_ADD_TCS(tp) { @@ -134,6 +180,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, posix_spawn_no_such_command_negative_test); ATF_TP_ADD_TC(tp, posix_spawnp_enoexec_fallback); ATF_TP_ADD_TC(tp, posix_spawnp_enoexec_fallback_null_argv0); + ATF_TP_ADD_TC(tp, posix_spawnp_eacces); return (atf_no_error()); } diff --git a/lib/libc/tests/gen/realpath2_test.c b/lib/libc/tests/gen/realpath2_test.c index 82ad7f870697..f89dd99cbb72 100644 --- a/lib/libc/tests/gen/realpath2_test.c +++ b/lib/libc/tests/gen/realpath2_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <errno.h> #include <fcntl.h> diff --git a/lib/libc/tests/gen/scandir_blocks_test.c b/lib/libc/tests/gen/scandir_blocks_test.c new file mode 100644 index 000000000000..b94270bc410e --- /dev/null +++ b/lib/libc/tests/gen/scandir_blocks_test.c @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <dirent.h> +#include <fcntl.h> +#include <stdlib.h> + +#include <atf-c.h> + +static void +scandir_blocks_prepare(const struct atf_tc *tc) +{ + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + ATF_REQUIRE_EQ(0, mkdir("dir/dir", 0755)); + ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644))); + ATF_REQUIRE_EQ(0, symlink("file", "dir/link")); + ATF_REQUIRE_EQ(0, mkdir("dir/skip", 0755)); +} + +static void +scandir_blocks_verify(const struct atf_tc *tc, int n, struct dirent **namelist) +{ + ATF_REQUIRE_EQ_MSG(5, n, "return value is %d", n); + ATF_CHECK_STREQ("link", namelist[0]->d_name); + ATF_CHECK_STREQ("file", namelist[1]->d_name); + ATF_CHECK_STREQ("dir", namelist[2]->d_name); + ATF_CHECK_STREQ("..", namelist[3]->d_name); + ATF_CHECK_STREQ(".", namelist[4]->d_name); +} + +ATF_TC(scandir_b_test); +ATF_TC_HEAD(scandir_b_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test scandir_b()"); +} +ATF_TC_BODY(scandir_b_test, tc) +{ + struct dirent **namelist = NULL; + int i, ret; + + scandir_blocks_prepare(tc); + ret = scandir_b("dir", &namelist, + ^(const struct dirent *ent) { + return (strcmp(ent->d_name, "skip") != 0); + }, + ^(const struct dirent **a, const struct dirent **b) { + return (strcmp((*b)->d_name, (*a)->d_name)); + }); + scandir_blocks_verify(tc, ret, namelist); + for (i = 0; i < ret; i++) + free(namelist[i]); + free(namelist); +} + +ATF_TC(fdscandir_b_test); +ATF_TC_HEAD(fdscandir_b_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test fdscandir_b()"); +} +ATF_TC_BODY(fdscandir_b_test, tc) +{ + struct dirent **namelist = NULL; + int fd, i, ret; + + scandir_blocks_prepare(tc); + ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); + ret = fdscandir_b(fd, &namelist, + ^(const struct dirent *ent) { + return (strcmp(ent->d_name, "skip") != 0); + }, + ^(const struct dirent **a, const struct dirent **b) { + return (strcmp((*b)->d_name, (*a)->d_name)); + }); + scandir_blocks_verify(tc, ret, namelist); + for (i = 0; i < ret; i++) + free(namelist[i]); + free(namelist); + ATF_REQUIRE_EQ(0, close(fd)); +} + +ATF_TC(scandirat_b_test); +ATF_TC_HEAD(scandirat_b_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test scandirat_b()"); +} +ATF_TC_BODY(scandirat_b_test, tc) +{ + struct dirent **namelist = NULL; + int fd, i, ret; + + scandir_blocks_prepare(tc); + ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_SEARCH)) >= 0); + ret = scandirat_b(fd, ".", &namelist, + ^(const struct dirent *ent) { + return (strcmp(ent->d_name, "skip") != 0); + }, + ^(const struct dirent **a, const struct dirent **b) { + return (strcmp((*b)->d_name, (*a)->d_name)); + }); + scandir_blocks_verify(tc, ret, namelist); + for (i = 0; i < ret; i++) + free(namelist[i]); + free(namelist); + ATF_REQUIRE_EQ(0, close(fd)); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, scandir_b_test); + ATF_TP_ADD_TC(tp, fdscandir_b_test); + ATF_TP_ADD_TC(tp, scandirat_b_test); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/scandir_test.c b/lib/libc/tests/gen/scandir_test.c new file mode 100644 index 000000000000..afd25bf7c0b2 --- /dev/null +++ b/lib/libc/tests/gen/scandir_test.c @@ -0,0 +1,195 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + +#include <atf-c.h> + +static void +scandir_prepare(const struct atf_tc *tc) +{ + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + ATF_REQUIRE_EQ(0, mkdir("dir/dir", 0755)); + ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644))); + ATF_REQUIRE_EQ(0, symlink("file", "dir/link")); + ATF_REQUIRE_EQ(0, mkdir("dir/skip", 0755)); +} + +static void +scandir_verify(const struct atf_tc *tc, int n, struct dirent **namelist) +{ + ATF_REQUIRE_EQ_MSG(5, n, "return value is %d", n); + ATF_CHECK_STREQ("link", namelist[0]->d_name); + ATF_CHECK_STREQ("file", namelist[1]->d_name); + ATF_CHECK_STREQ("dir", namelist[2]->d_name); + ATF_CHECK_STREQ("..", namelist[3]->d_name); + ATF_CHECK_STREQ(".", namelist[4]->d_name); +} + +static int +scandir_select(const struct dirent *ent) +{ + return (strcmp(ent->d_name, "skip") != 0); +} + +static int +scandir_compare(const struct dirent **a, const struct dirent **b) +{ + return (strcmp((*b)->d_name, (*a)->d_name)); +} + +ATF_TC(scandir_test); +ATF_TC_HEAD(scandir_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test scandir()"); +} +ATF_TC_BODY(scandir_test, tc) +{ + struct dirent **namelist = NULL; + int i, ret; + + scandir_prepare(tc); + ret = scandir("dir", &namelist, scandir_select, scandir_compare); + scandir_verify(tc, ret, namelist); + for (i = 0; i < ret; i++) + free(namelist[i]); + free(namelist); +} + +ATF_TC(fdscandir_test); +ATF_TC_HEAD(fdscandir_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test fdscandir()"); +} +ATF_TC_BODY(fdscandir_test, tc) +{ + struct dirent **namelist = NULL; + int fd, i, ret; + + scandir_prepare(tc); + ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); + ret = fdscandir(fd, &namelist, scandir_select, scandir_compare); + scandir_verify(tc, ret, namelist); + for (i = 0; i < ret; i++) + free(namelist[i]); + free(namelist); + ATF_REQUIRE_EQ(0, close(fd)); +} + +ATF_TC(scandirat_test); +ATF_TC_HEAD(scandirat_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test scandirat()"); +} +ATF_TC_BODY(scandirat_test, tc) +{ + struct dirent **namelist = NULL; + int fd, i, ret; + + scandir_prepare(tc); + ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_SEARCH)) >= 0); + ret = scandirat(fd, ".", &namelist, scandir_select, scandir_compare); + scandir_verify(tc, ret, namelist); + for (i = 0; i < ret; i++) + free(namelist[i]); + free(namelist); + ATF_REQUIRE_EQ(0, close(fd)); +} + +static int +scandir_none(const struct dirent *ent __unused) +{ + return (0); +} + +ATF_TC(scandir_none); +ATF_TC_HEAD(scandir_none, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test scandir() when no entries are selected"); +} +ATF_TC_BODY(scandir_none, tc) +{ + struct dirent **namelist = NULL; + + ATF_REQUIRE_EQ(0, scandir(".", &namelist, scandir_none, alphasort)); + ATF_REQUIRE(namelist); + free(namelist); +} + +/* + * Test that scandir() propagates errors from readdir(): we create a + * directory with enough entries that it can't be read in a single + * getdirentries() call, then abuse the selection callback to close the + * file descriptor scandir() is using after the first call, causing the + * next one to fail, and verify that readdir() returns an error instead of + * a partial result. We make two passes, one in which nothing was + * selected before the error occurred, and one in which everything was. + */ +static int scandir_error_count; +static int scandir_error_fd; +static int scandir_error_select_return; + +static int +scandir_error_select(const struct dirent *ent __unused) +{ + if (scandir_error_count++ == 0) + close(scandir_error_fd); + return (scandir_error_select_return); +} + +ATF_TC(scandir_error); +ATF_TC_HEAD(scandir_error, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test that scandir() propagates errors from readdir()"); +} +ATF_TC_BODY(scandir_error, tc) +{ + char path[16]; + struct dirent **namelist = NULL; + int fd, i; + + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + for (i = 0; i < 1024; i++) { + snprintf(path, sizeof(path), "dir/%04x", i); + ATF_REQUIRE_EQ(0, symlink(path + 4, path)); + } + + /* first pass, select nothing */ + ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); + scandir_error_count = 0; + scandir_error_fd = fd; + scandir_error_select_return = 0; + ATF_CHECK_ERRNO(EBADF, + fdscandir(fd, &namelist, scandir_error_select, NULL) < 0); + ATF_CHECK_EQ(NULL, namelist); + + /* second pass, select everything */ + ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); + scandir_error_count = 0; + scandir_error_fd = fd; + scandir_error_select_return = 1; + ATF_CHECK_ERRNO(EBADF, + fdscandir(fd, &namelist, scandir_error_select, NULL) < 0); + ATF_CHECK_EQ(NULL, namelist); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, scandir_test); + ATF_TP_ADD_TC(tp, fdscandir_test); + ATF_TP_ADD_TC(tp, scandirat_test); + ATF_TP_ADD_TC(tp, scandir_none); + ATF_TP_ADD_TC(tp, scandir_error); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/sig2str_test.c b/lib/libc/tests/gen/sig2str_test.c new file mode 100644 index 000000000000..00b6ebb2349a --- /dev/null +++ b/lib/libc/tests/gen/sig2str_test.c @@ -0,0 +1,213 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Ricardo Branco <rbranco@suse.de> + * All rights reserved. + * + * 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 <ctype.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> + +#include <atf-c.h> + +static void +test_roundtrip(int signum) +{ + char str[SIG2STR_MAX]; + int sig; + + ATF_REQUIRE_EQ_MSG(sig2str(signum, str), 0, + "sig2str(%d) failed", signum); + ATF_REQUIRE_EQ_MSG(str2sig(str, &sig), 0, + "str2sig(\"%s\") failed", str); + ATF_REQUIRE_INTEQ_MSG(sig, signum, + "Mismatch: roundtrip conversion gave %d instead of %d", + sig, signum); +} + +ATF_TC_WITHOUT_HEAD(sig2str_valid); +ATF_TC_BODY(sig2str_valid, tc) +{ + int sig; + + for (sig = 1; sig < sys_nsig; sig++) { + test_roundtrip(sig); + } +} + +ATF_TC_WITHOUT_HEAD(sig2str_invalid); +ATF_TC_BODY(sig2str_invalid, tc) +{ + char buf[SIG2STR_MAX]; + + ATF_CHECK(sig2str(0, buf) != 0); + ATF_CHECK(sig2str(-1, buf) != 0); + ATF_CHECK(sig2str(SIGRTMAX + 1, buf) != 0); +} + +ATF_TC_WITHOUT_HEAD(str2sig_rtmin_rtmax); +ATF_TC_BODY(str2sig_rtmin_rtmax, tc) +{ + int sig; + + ATF_CHECK_MSG(str2sig("RTMIN", &sig) == 0, + "str2sig(\"RTMIN\") failed"); + ATF_CHECK_INTEQ_MSG(sig, SIGRTMIN, + "RTMIN mapped to %d, expected %d", sig, SIGRTMIN); + + ATF_CHECK_MSG(str2sig("RTMAX", &sig) == 0, + "str2sig(\"RTMAX\") failed"); + ATF_CHECK_INTEQ_MSG(sig, SIGRTMAX, + "RTMAX mapped to %d, expected %d", sig, SIGRTMAX); + + ATF_CHECK_MSG(str2sig("RTMIN+1", &sig) == 0, + "str2sig(\"RTMIN+1\") failed"); + ATF_CHECK_INTEQ_MSG(sig, SIGRTMIN + 1, + "RTMIN+1 mapped to %d, expected %d", sig, SIGRTMIN + 1); + + ATF_CHECK_MSG(str2sig("RTMAX-1", &sig) == 0, + "str2sig(\"RTMAX-1\") failed"); + ATF_CHECK_INTEQ_MSG(sig, SIGRTMAX - 1, + "RTMAX-1 mapped to %d, expected %d", sig, SIGRTMAX - 1); +} + +ATF_TC_WITHOUT_HEAD(str2sig_invalid_rt); +ATF_TC_BODY(str2sig_invalid_rt, tc) +{ + int i, sig; + + const char *invalid[] = { + "RTMIN+0", + "RTMAX-0", + "RTMIN-777", + "RTMIN+777", + "RTMAX-777", + "RTMAX+777", + "RTMIN-", + "RTMAX-", + "RTMIN0", + "RTMAX1", + "RTMIN+abc", + "RTMIN-abc", + NULL + }; + + for (i = 0; invalid[i] != NULL; i++) { + ATF_CHECK_MSG(str2sig(invalid[i], &sig) != 0, + "str2sig(\"%s\") unexpectedly succeeded", invalid[i]); + } +} + +ATF_TC_WITHOUT_HEAD(str2sig_fullname); +ATF_TC_BODY(str2sig_fullname, tc) +{ + char fullname[SIG2STR_MAX + 3]; + int n, sig; + + for (sig = 1; sig < sys_nsig; sig++) { + snprintf(fullname, sizeof(fullname), "SIG%s", sys_signame[sig]); + + ATF_CHECK_MSG(str2sig(fullname, &n) == 0, + "str2sig(\"%s\") failed with errno %d (%s)", + fullname, errno, strerror(errno)); + + ATF_CHECK_INTEQ_MSG(n, sig, + "Mismatch: %s = %d, str2sig(\"%s\") = %d", + sys_signame[sig], sig, fullname, n); + } +} + +ATF_TC_WITHOUT_HEAD(str2sig_lowercase); +ATF_TC_BODY(str2sig_lowercase, tc) +{ + char fullname[SIG2STR_MAX + 3]; + int n, sig; + + for (sig = 1; sig < sys_nsig; sig++) { + snprintf(fullname, sizeof(fullname), "sig%s", sys_signame[sig]); + for (size_t i = 3; i < strlen(fullname); i++) + fullname[i] = toupper((unsigned char)fullname[i]); + + ATF_CHECK_MSG(str2sig(fullname, &n) == 0, + "str2sig(\"%s\") failed with errno %d (%s)", + fullname, errno, strerror(errno)); + + ATF_CHECK_INTEQ_MSG(n, sig, + "Mismatch: %s = %d, str2sig(\"%s\") = %d", + sys_signame[sig], sig, fullname, n); + } +} + +ATF_TC_WITHOUT_HEAD(str2sig_numeric); +ATF_TC_BODY(str2sig_numeric, tc) +{ + char buf[16]; + int n, sig; + + for (sig = NSIG; sig < SIGRTMIN; sig++) { + snprintf(buf, sizeof(buf), "%d", sig); + ATF_CHECK_MSG(str2sig(buf, &n) == 0, + "str2sig(\"%s\") failed", buf); + ATF_CHECK_INTEQ_MSG(n, sig, + "Mismatch: str2sig(\"%s\") = %d, expected %d", + buf, n, sig); + } +} + +ATF_TC_WITHOUT_HEAD(str2sig_invalid); +ATF_TC_BODY(str2sig_invalid, tc) +{ + const char *invalid[] = { + "SIGDOESNOTEXIST", + "DOESNOTEXIST", + "INTERRUPT", + "", + "SIG", + "123abc", + "sig1extra", + NULL + }; + int i, sig; + + for (i = 0; invalid[i] != NULL; i++) { + ATF_CHECK_MSG(str2sig(invalid[i], &sig) != 0, + "str2sig(\"%s\") unexpectedly succeeded", invalid[i]); + } +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, sig2str_valid); + ATF_TP_ADD_TC(tp, sig2str_invalid); + ATF_TP_ADD_TC(tp, str2sig_rtmin_rtmax); + ATF_TP_ADD_TC(tp, str2sig_invalid_rt); + ATF_TP_ADD_TC(tp, str2sig_fullname); + ATF_TP_ADD_TC(tp, str2sig_lowercase); + ATF_TP_ADD_TC(tp, str2sig_numeric); + ATF_TP_ADD_TC(tp, str2sig_invalid); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/sigsetops_test.c b/lib/libc/tests/gen/sigsetops_test.c index ba9abed403b0..a22c4b3f4f59 100644 --- a/lib/libc/tests/gen/sigsetops_test.c +++ b/lib/libc/tests/gen/sigsetops_test.c @@ -1,5 +1,5 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org> * All rights reserved. @@ -26,9 +26,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <signal.h> #include <stdbool.h> diff --git a/lib/libc/tests/gen/spawnp_enoexec.sh b/lib/libc/tests/gen/spawnp_enoexec.sh index 02941633e108..1050b7a6f944 100755 --- a/lib/libc/tests/gen/spawnp_enoexec.sh +++ b/lib/libc/tests/gen/spawnp_enoexec.sh @@ -1,4 +1,3 @@ -# $FreeBSD$ # Intentionally no interpreter exit 42 diff --git a/lib/libc/tests/gen/test-fnmatch.c b/lib/libc/tests/gen/test-fnmatch.c index 7771ab37f0a0..1a6c6ed7efdf 100644 --- a/lib/libc/tests/gen/test-fnmatch.c +++ b/lib/libc/tests/gen/test-fnmatch.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <stdio.h> #include <stdlib.h> diff --git a/lib/libc/tests/gen/wordexp_test.c b/lib/libc/tests/gen/wordexp_test.c index 3ccc67774c7f..a8b9d5509633 100644 --- a/lib/libc/tests/gen/wordexp_test.c +++ b/lib/libc/tests/gen/wordexp_test.c @@ -29,9 +29,6 @@ * IEEE Std. 1003.1-2001. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/wait.h> #include <errno.h> #include <signal.h> @@ -295,6 +292,31 @@ ATF_TC_BODY(with_SIGCHILD_handler_test, tc) ATF_REQUIRE(r == 0); } +ATF_TC_WITHOUT_HEAD(with_SIGCHILD_ignore_test); +ATF_TC_BODY(with_SIGCHILD_ignore_test, tc) +{ + struct sigaction sa; + wordexp_t we; + int r; + + /* With SIGCHLD set to ignore so that the kernel auto-reaps zombies. */ + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_IGN; + r = sigaction(SIGCHLD, &sa, NULL); + ATF_REQUIRE(r == 0); + r = wordexp("hello world", &we, 0); + ATF_REQUIRE(r == 0); + ATF_REQUIRE(we.we_wordc == 2); + ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0); + ATF_REQUIRE(we.we_wordv[2] == NULL); + wordfree(&we); + sa.sa_handler = SIG_DFL; + r = sigaction(SIGCHLD, &sa, NULL); + ATF_REQUIRE(r == 0); +} + ATF_TC_WITHOUT_HEAD(with_unused_non_default_IFS_test); ATF_TC_BODY(with_unused_non_default_IFS_test, tc) { @@ -353,6 +375,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, WRDE_BADCHAR_test); ATF_TP_ADD_TC(tp, WRDE_SYNTAX_test); ATF_TP_ADD_TC(tp, with_SIGCHILD_handler_test); + ATF_TP_ADD_TC(tp, with_SIGCHILD_ignore_test); ATF_TP_ADD_TC(tp, with_unused_non_default_IFS_test); ATF_TP_ADD_TC(tp, with_used_non_default_IFS_test); diff --git a/lib/libc/tests/hash/Makefile b/lib/libc/tests/hash/Makefile index 7811d455cdc3..d09d87b7cd8b 100644 --- a/lib/libc/tests/hash/Makefile +++ b/lib/libc/tests/hash/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - PACKAGE= tests .include <src.opts.mk> diff --git a/lib/libc/tests/hash/Makefile.depend b/lib/libc/tests/hash/Makefile.depend index 81f787db80e9..c969d41de00c 100644 --- a/lib/libc/tests/hash/Makefile.depend +++ b/lib/libc/tests/hash/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/iconv/Makefile b/lib/libc/tests/iconv/Makefile index 635c26c7cfb7..dc2dc5a925b9 100644 --- a/lib/libc/tests/iconv/Makefile +++ b/lib/libc/tests/iconv/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - TESTSDIR= ${TESTSBASE}/lib/libc/iconv ATF_TESTS_C+= iconvctl_test diff --git a/lib/libc/tests/iconv/Makefile.depend b/lib/libc/tests/iconv/Makefile.depend index c062f6026d94..1af0c88e099c 100644 --- a/lib/libc/tests/iconv/Makefile.depend +++ b/lib/libc/tests/iconv/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/iconv/iconvctl_test.c b/lib/libc/tests/iconv/iconvctl_test.c index 993629e6b4bd..f534218cf294 100644 --- a/lib/libc/tests/iconv/iconvctl_test.c +++ b/lib/libc/tests/iconv/iconvctl_test.c @@ -23,9 +23,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <iconv.h> #include <atf-c.h> diff --git a/lib/libc/tests/inet/Makefile b/lib/libc/tests/inet/Makefile index fa4499c9d11b..3ceadfb8868c 100644 --- a/lib/libc/tests/inet/Makefile +++ b/lib/libc/tests/inet/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> NETBSD_ATF_TESTS_C+= inet_addr_test diff --git a/lib/libc/tests/inet/Makefile.depend b/lib/libc/tests/inet/Makefile.depend index 4be488723cf3..d0eb7a0f9f74 100644 --- a/lib/libc/tests/inet/Makefile.depend +++ b/lib/libc/tests/inet/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/locale/Makefile b/lib/libc/tests/locale/Makefile index 83caf8cb3bd3..70905cc58d24 100644 --- a/lib/libc/tests/locale/Makefile +++ b/lib/libc/tests/locale/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> ATF_TESTS_C+= btowc_test @@ -13,6 +11,7 @@ ATF_TESTS_C+= mbsnrtowcs_2_test ATF_TESTS_C+= mbsrtowcs_test ATF_TESTS_C+= mbstowcs_2_test ATF_TESTS_C+= mbtowc_2_test +ATF_TESTS_C+= newlocale_test ATF_TESTS_C+= towctrans_test ATF_TESTS_C+= wcrtomb_test ATF_TESTS_C+= wcsnrtombs_test diff --git a/lib/libc/tests/locale/Makefile.depend b/lib/libc/tests/locale/Makefile.depend index 45823695c1bb..e5ddbc552be2 100644 --- a/lib/libc/tests/locale/Makefile.depend +++ b/lib/libc/tests/locale/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/locale/btowc_test.c b/lib/libc/tests/locale/btowc_test.c index 01a1133e89d5..27e6ff533621 100644 --- a/lib/libc/tests/locale/btowc_test.c +++ b/lib/libc/tests/locale/btowc_test.c @@ -31,9 +31,6 @@ * The function is tested in the "C" and "ja_JP.eucJP" locales. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <limits.h> #include <locale.h> #include <stdio.h> diff --git a/lib/libc/tests/locale/c16rtomb_test.c b/lib/libc/tests/locale/c16rtomb_test.c index ea1f64f7d308..6812fbbc5164 100644 --- a/lib/libc/tests/locale/c16rtomb_test.c +++ b/lib/libc/tests/locale/c16rtomb_test.c @@ -30,9 +30,6 @@ * Test program for c16rtomb() as specified by ISO/IEC 9899:2011. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <limits.h> #include <locale.h> diff --git a/lib/libc/tests/locale/iswctype_test.c b/lib/libc/tests/locale/iswctype_test.c index 14e57b4e29a3..79b941522d2b 100644 --- a/lib/libc/tests/locale/iswctype_test.c +++ b/lib/libc/tests/locale/iswctype_test.c @@ -31,9 +31,6 @@ * The functions are tested in the "C" and "ja_JP.eucJP" locales. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <errno.h> #include <locale.h> diff --git a/lib/libc/tests/locale/mblen_test.c b/lib/libc/tests/locale/mblen_test.c index fbb938d3e5a6..e081b0d4246a 100644 --- a/lib/libc/tests/locale/mblen_test.c +++ b/lib/libc/tests/locale/mblen_test.c @@ -32,9 +32,6 @@ * "ja_JP.eucJP". Other encodings are not tested. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <limits.h> #include <locale.h> #include <stdio.h> diff --git a/lib/libc/tests/locale/mbrlen_test.c b/lib/libc/tests/locale/mbrlen_test.c index c2bc54832156..50088596fc89 100644 --- a/lib/libc/tests/locale/mbrlen_test.c +++ b/lib/libc/tests/locale/mbrlen_test.c @@ -32,9 +32,6 @@ * "ja_JP.eucJP". Other encodings are not tested. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <limits.h> #include <locale.h> diff --git a/lib/libc/tests/locale/mbrtoc16_test.c b/lib/libc/tests/locale/mbrtoc16_test.c index a6289e1004ca..98a140c56fc0 100644 --- a/lib/libc/tests/locale/mbrtoc16_test.c +++ b/lib/libc/tests/locale/mbrtoc16_test.c @@ -30,9 +30,6 @@ * Test program for mbrtoc16() as specified by ISO/IEC 9899:2011. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <limits.h> #include <locale.h> diff --git a/lib/libc/tests/locale/mbrtowc_test.c b/lib/libc/tests/locale/mbrtowc_test.c index 37e0bfd6fbaa..df611a7df573 100644 --- a/lib/libc/tests/locale/mbrtowc_test.c +++ b/lib/libc/tests/locale/mbrtowc_test.c @@ -32,9 +32,6 @@ * "ja_JP.eucJP". Other encodings are not tested. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <limits.h> #include <locale.h> diff --git a/lib/libc/tests/locale/mbsnrtowcs_test.c b/lib/libc/tests/locale/mbsnrtowcs_test.c index 4012b7e99720..a355bc7d7a6a 100644 --- a/lib/libc/tests/locale/mbsnrtowcs_test.c +++ b/lib/libc/tests/locale/mbsnrtowcs_test.c @@ -31,9 +31,6 @@ * "ja_JP.eucJP". Other encodings are not tested. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <limits.h> #include <locale.h> diff --git a/lib/libc/tests/locale/mbsrtowcs_test.c b/lib/libc/tests/locale/mbsrtowcs_test.c index 1b9d5c933af1..d8d215fda2ad 100644 --- a/lib/libc/tests/locale/mbsrtowcs_test.c +++ b/lib/libc/tests/locale/mbsrtowcs_test.c @@ -32,9 +32,6 @@ * "ja_JP.eucJP". Other encodings are not tested. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <limits.h> #include <locale.h> diff --git a/lib/libc/tests/locale/mbstowcs_test.c b/lib/libc/tests/locale/mbstowcs_test.c index 77b0e9e52f35..404adfd7b19a 100644 --- a/lib/libc/tests/locale/mbstowcs_test.c +++ b/lib/libc/tests/locale/mbstowcs_test.c @@ -32,9 +32,6 @@ * "ja_JP.eucJP". Other encodings are not tested. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <limits.h> #include <locale.h> diff --git a/lib/libc/tests/locale/mbtowc_test.c b/lib/libc/tests/locale/mbtowc_test.c index 7c7f80eb5cc4..e5ff276b4610 100644 --- a/lib/libc/tests/locale/mbtowc_test.c +++ b/lib/libc/tests/locale/mbtowc_test.c @@ -32,9 +32,6 @@ * "ja_JP.eucJP". Other encodings are not tested. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <limits.h> #include <locale.h> #include <stdio.h> diff --git a/lib/libc/tests/locale/newlocale_test.c b/lib/libc/tests/locale/newlocale_test.c new file mode 100644 index 000000000000..cb0ebb323a42 --- /dev/null +++ b/lib/libc/tests/locale/newlocale_test.c @@ -0,0 +1,111 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2023 Yuri Pankov <yuripv@FreeBSD.org> + * + * 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/param.h> + +#include <locale.h> + +#include <atf-c.h> + +struct { + int lpmask; + const char *lpname; +} lparts[] = { + { LC_COLLATE_MASK, "LC_COLLATE" }, + { LC_CTYPE_MASK, "LC_CTYPE" }, + { LC_MONETARY_MASK, "LC_MONETARY" }, + { LC_NUMERIC_MASK, "LC_NUMERIC" }, + { LC_TIME_MASK, "LC_TIME" }, + { LC_MESSAGES_MASK, "LC_MESSAGES" }, +}; + +static void +check_lparts(const char *expected) +{ + int i; + + for (i = 0; i < nitems(lparts); i++) { + const char *actual; + + actual = querylocale(lparts[i].lpmask, uselocale(NULL)); + ATF_CHECK_STREQ_MSG(expected, actual, "wrong value for %s", + lparts[i].lpname); + } +} + +static void +do_locale_switch(const char *loc1, const char *loc2) +{ + locale_t l1, l2; + + /* Create and use the first locale */ + l1 = newlocale(LC_ALL_MASK, loc1, NULL); + ATF_REQUIRE(l1 != NULL); + ATF_REQUIRE(uselocale(l1) != NULL); + check_lparts(loc1); + /* + * Create and use second locale, creation deliberately done only after + * the first locale check as newlocale() call would previously clobber + * the first locale contents. + */ + l2 = newlocale(LC_ALL_MASK, loc2, NULL); + ATF_REQUIRE(l2 != NULL); + ATF_REQUIRE(uselocale(l2) != NULL); + check_lparts(loc2); + /* Switch back to first locale */ + ATF_REQUIRE(uselocale(l1) != NULL); + check_lparts(loc1); + + freelocale(l1); + freelocale(l2); +} + +/* + * PR 255646, 269375: Check that newlocale()/uselocale() used to switch between + * C, POSIX, and C.UTF-8 locales (and only these) do not stomp on other locale + * contents (collate part specifically). + * The issue is cosmetic only as all three have empty collate parts, but we need + * to correctly report the one in use in any case. + */ + +ATF_TC_WITHOUT_HEAD(newlocale_c_posix_cu8_test); +ATF_TC_BODY(newlocale_c_posix_cu8_test, tc) +{ + do_locale_switch("C", "POSIX"); + do_locale_switch("C", "C.UTF-8"); + do_locale_switch("POSIX", "C"); + do_locale_switch("POSIX", "C.UTF-8"); + do_locale_switch("C.UTF-8", "C"); + do_locale_switch("C.UTF-8", "POSIX"); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, newlocale_c_posix_cu8_test); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/locale/towctrans_test.c b/lib/libc/tests/locale/towctrans_test.c index bb9d97ca2e54..f34eb554f283 100644 --- a/lib/libc/tests/locale/towctrans_test.c +++ b/lib/libc/tests/locale/towctrans_test.c @@ -31,9 +31,6 @@ * The functions are tested in the "C" and "ja_JP.eucJP" locales. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <locale.h> #include <stdio.h> #include <string.h> diff --git a/lib/libc/tests/locale/wcrtomb_test.c b/lib/libc/tests/locale/wcrtomb_test.c index 09199ba97c99..2bc7cbc2365f 100644 --- a/lib/libc/tests/locale/wcrtomb_test.c +++ b/lib/libc/tests/locale/wcrtomb_test.c @@ -32,9 +32,6 @@ * "ja_JP.eucJP". Other encodings are not tested. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <limits.h> #include <locale.h> diff --git a/lib/libc/tests/locale/wcsnrtombs_test.c b/lib/libc/tests/locale/wcsnrtombs_test.c index 2e330a10ad83..8764c1567066 100644 --- a/lib/libc/tests/locale/wcsnrtombs_test.c +++ b/lib/libc/tests/locale/wcsnrtombs_test.c @@ -31,9 +31,6 @@ * "ja_JP.eucJP". Other encodings are not tested. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <limits.h> #include <locale.h> diff --git a/lib/libc/tests/locale/wcsrtombs_test.c b/lib/libc/tests/locale/wcsrtombs_test.c index 4c3455a87769..dcb111dfd87c 100644 --- a/lib/libc/tests/locale/wcsrtombs_test.c +++ b/lib/libc/tests/locale/wcsrtombs_test.c @@ -32,9 +32,6 @@ * "ja_JP.eucJP". Other encodings are not tested. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <limits.h> #include <locale.h> diff --git a/lib/libc/tests/locale/wcstombs_test.c b/lib/libc/tests/locale/wcstombs_test.c index f3fcd81001f1..2506be2806f6 100644 --- a/lib/libc/tests/locale/wcstombs_test.c +++ b/lib/libc/tests/locale/wcstombs_test.c @@ -32,9 +32,6 @@ * "ja_JP.eucJP". Other encodings are not tested. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <limits.h> #include <locale.h> diff --git a/lib/libc/tests/locale/wctomb_test.c b/lib/libc/tests/locale/wctomb_test.c index 255cda432d7d..ef2a6dcbe1e3 100644 --- a/lib/libc/tests/locale/wctomb_test.c +++ b/lib/libc/tests/locale/wctomb_test.c @@ -32,9 +32,6 @@ * "ja_JP.eucJP". Other encodings are not tested. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <limits.h> #include <locale.h> @@ -44,6 +41,18 @@ __FBSDID("$FreeBSD$"); #include <atf-c.h> +ATF_TC_WITHOUT_HEAD(euccs1_test); +ATF_TC_BODY(euccs1_test, tc) +{ + wchar_t wc = 0x8e000000; + char buf[MB_LEN_MAX]; + + ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "zh_CN.eucCN"), + "zh_CN.eucCN") == 0); + + ATF_REQUIRE(wctomb(&buf[0], wc) == 4); +} + ATF_TC_WITHOUT_HEAD(wctomb_test); ATF_TC_BODY(wctomb_test, tc) { @@ -107,6 +116,7 @@ ATF_TC_BODY(wctomb_test, tc) ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, euccs1_test); ATF_TP_ADD_TC(tp, wctomb_test); return (atf_no_error()); diff --git a/lib/libc/tests/net/Makefile b/lib/libc/tests/net/Makefile index 14ab914e67ef..24cff61e8d24 100644 --- a/lib/libc/tests/net/Makefile +++ b/lib/libc/tests/net/Makefile @@ -1,10 +1,11 @@ -# $FreeBSD$ - PACKAGE= tests ATF_TESTS_C+= ether_test ATF_TESTS_C+= eui64_aton_test ATF_TESTS_C+= eui64_ntoa_test +ATF_TESTS_CXX+= link_addr_test + +CXXSTD.link_addr_test= c++20 CFLAGS+= -I${.CURDIR} @@ -33,8 +34,7 @@ aton_ether_subr.c: gen_ether_subr ${SRCTOP}/sys/net/if_ethersubr.c .include "../Makefile.netbsd-tests" -# TODO: the testcases needs to be ported to FreeBSD -#TESTS_SUBDIRS= getaddrinfo +TESTS_SUBDIRS= getaddrinfo ${PACKAGE}FILES+= hosts ${PACKAGE}FILES+= resolv.conf diff --git a/lib/libc/tests/net/Makefile.depend b/lib/libc/tests/net/Makefile.depend index 22a01a72015a..daaf971bd513 100644 --- a/lib/libc/tests/net/Makefile.depend +++ b/lib/libc/tests/net/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/net/ether_test.c b/lib/libc/tests/net/ether_test.c index 5b596f01a439..fbeed15efaa7 100644 --- a/lib/libc/tests/net/ether_test.c +++ b/lib/libc/tests/net/ether_test.c @@ -22,8 +22,6 @@ * 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. - * - * $FreeBSD$ */ #include <sys/types.h> diff --git a/lib/libc/tests/net/eui64_aton_test.c b/lib/libc/tests/net/eui64_aton_test.c index 7b97d7fb0521..a4b09695fda9 100644 --- a/lib/libc/tests/net/eui64_aton_test.c +++ b/lib/libc/tests/net/eui64_aton_test.c @@ -24,8 +24,6 @@ * 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. - * - * $FreeBSD$ */ #include <sys/types.h> diff --git a/lib/libc/tests/net/eui64_ntoa_test.c b/lib/libc/tests/net/eui64_ntoa_test.c index 4158e7a42cce..1da80fc2ea02 100644 --- a/lib/libc/tests/net/eui64_ntoa_test.c +++ b/lib/libc/tests/net/eui64_ntoa_test.c @@ -24,8 +24,6 @@ * 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. - * - * $FreeBSD$ */ #include <sys/types.h> diff --git a/lib/libc/tests/net/getaddrinfo/Makefile b/lib/libc/tests/net/getaddrinfo/Makefile index edf335cd222f..1299e91615b7 100644 --- a/lib/libc/tests/net/getaddrinfo/Makefile +++ b/lib/libc/tests/net/getaddrinfo/Makefile @@ -1,16 +1,11 @@ -# $FreeBSD$ - PACKAGE= tests -TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libc/net/${.CURDIR:T} - .include <bsd.own.mk> BINDIR= ${TESTSDIR} -.error This testcase needs to be ported to FreeBSD (the output from getaddrinfo_test differs from NetBSD) - -NETBSD_ATF_TESTS_SH= getaddrinfo_test +ATF_TESTS_SH= getaddrinfo_test +ATF_TESTS_C= getaddrinfo PROGS= h_gai @@ -19,13 +14,33 @@ ${PACKAGE}DATA_FILESPACKAGE= tests ${PACKAGE}DATA_FILESDIR= ${TESTSDIR}/data -${PACKAGE}DATA_FILES+= basics_v4.exp basics_v4v6.exp -${PACKAGE}DATA_FILES+= no_host_v4.exp no_host_v4v6.exp -${PACKAGE}DATA_FILES+= no_serv_v4.exp no_serv_v4v6.exp -${PACKAGE}DATA_FILES+= sock_raw_v4.exp sock_raw_v4v6.exp -${PACKAGE}DATA_FILES+= spec_fam_v4.exp spec_fam_v4v6.exp -${PACKAGE}DATA_FILES+= scoped.exp -${PACKAGE}DATA_FILES+= unsup_fam.exp +${PACKAGE}DATA_FILES+= data/basics_v4.exp +${PACKAGE}DATA_FILES+= data/basics_v4_only.exp +${PACKAGE}DATA_FILES+= data/basics_v4v6.exp +${PACKAGE}DATA_FILES+= data/basics_v4v6_prefer_v4.exp +${PACKAGE}DATA_FILES+= data/no_host_v4.exp +${PACKAGE}DATA_FILES+= data/no_host_v4_only.exp +${PACKAGE}DATA_FILES+= data/no_host_v4v6.exp +${PACKAGE}DATA_FILES+= data/no_host_v4v6_prefer_v4.exp +${PACKAGE}DATA_FILES+= data/no_serv_v4.exp +${PACKAGE}DATA_FILES+= data/no_serv_v4_only.exp +${PACKAGE}DATA_FILES+= data/no_serv_v4v6.exp +${PACKAGE}DATA_FILES+= data/no_serv_v4v6_prefer_v4.exp +${PACKAGE}DATA_FILES+= data/scoped.exp +${PACKAGE}DATA_FILES+= data/scoped_v4_only.exp +${PACKAGE}DATA_FILES+= data/scoped_v4v6_prefer_v4.exp +${PACKAGE}DATA_FILES+= data/sock_raw_v4.exp +${PACKAGE}DATA_FILES+= data/sock_raw_v4_only.exp +${PACKAGE}DATA_FILES+= data/sock_raw_v4v6.exp +${PACKAGE}DATA_FILES+= data/sock_raw_v4v6_prefer_v4.exp +${PACKAGE}DATA_FILES+= data/spec_fam_v4.exp +${PACKAGE}DATA_FILES+= data/spec_fam_v4_only.exp +${PACKAGE}DATA_FILES+= data/spec_fam_v4v6.exp +${PACKAGE}DATA_FILES+= data/spec_fam_v4v6_prefer_v4.exp +${PACKAGE}DATA_FILES+= data/unsup_fam.exp +${PACKAGE}DATA_FILES+= data/unsup_fam_v4_only.exp +${PACKAGE}DATA_FILES+= data/unsup_fam_v4v6_prefer_v4.exp + .include "../../Makefile.netbsd-tests" diff --git a/lib/libc/tests/net/getaddrinfo/data/basics_v4.exp b/lib/libc/tests/net/getaddrinfo/data/basics_v4.exp new file mode 100644 index 000000000000..4f1ee3517211 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/basics_v4.exp @@ -0,0 +1,42 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv http +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv http +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv tftp +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv tftp +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv tftp +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv echo +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv echo +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv echo +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo + diff --git a/lib/libc/tests/net/getaddrinfo/data/basics_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/basics_v4_only.exp new file mode 100644 index 000000000000..0a37d3212649 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/basics_v4_only.exp @@ -0,0 +1,50 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv http +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv http +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http +ai4: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai5: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai6: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv tftp +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv tftp +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv tftp +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp +ai3: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp +ai4: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv echo +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv echo +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv echo +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo +ai4: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo +ai5: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo +ai6: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo + diff --git a/lib/libc/tests/net/getaddrinfo/data/basics_v4v6.exp b/lib/libc/tests/net/getaddrinfo/data/basics_v4v6.exp new file mode 100644 index 000000000000..b74758e93e2e --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/basics_v4v6.exp @@ -0,0 +1,50 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv http +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http +ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv tftp +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv tftp +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv tftp +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp +ai3: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp +ai4: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv echo +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv echo +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv echo +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo +ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo +ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo +ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo + diff --git a/lib/libc/tests/net/getaddrinfo/data/basics_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/basics_v4v6_prefer_v4.exp new file mode 100644 index 000000000000..0a37d3212649 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/basics_v4v6_prefer_v4.exp @@ -0,0 +1,50 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv http +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv http +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http +ai4: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai5: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai6: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv tftp +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv tftp +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv tftp +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp +ai3: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp +ai4: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv echo +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv echo +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv echo +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo +ai4: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo +ai5: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo +ai6: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo + diff --git a/lib/libc/tests/net/getaddrinfo/data/generate_testdata.sh b/lib/libc/tests/net/getaddrinfo/data/generate_testdata.sh new file mode 100755 index 000000000000..f0425a3b0283 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/generate_testdata.sh @@ -0,0 +1,45 @@ +#service ip6addrctl prefer_ipv4 +TEST=./h_gai +family=v4_only + +( $TEST ::1 http + $TEST 127.0.0.1 http + $TEST localhost http + $TEST ::1 tftp + $TEST 127.0.0.1 tftp + $TEST localhost tftp + $TEST ::1 echo + $TEST 127.0.0.1 echo + $TEST localhost echo ) > basics_${family}.exp + +( $TEST -4 localhost http + $TEST -6 localhost http ) > spec_fam_${family}.exp + +( $TEST '' http + $TEST '' echo + $TEST '' tftp + $TEST '' 80 + $TEST -P '' http + $TEST -P '' echo + $TEST -P '' tftp + $TEST -P '' 80 + $TEST -S '' 80 + $TEST -D '' 80 ) > no_host_${family}.exp + +( $TEST ::1 '' + $TEST 127.0.0.1 '' + $TEST localhost '' + $TEST '' '' ) > no_serv_${family}.exp + +( $TEST -R -p 0 localhost '' + $TEST -R -p 59 localhost '' + $TEST -R -p 59 localhost 80 + $TEST -R -p 59 localhost www + $TEST -R -p 59 ::1 '' ) > sock_raw_${family}.exp + +( $TEST -f 99 localhost '' ) > unsup_fam_${family}.exp + +( $TEST fe80::1%lo0 http +# IF=`ifconfig -a | grep -v '^ ' | sed -e 's/:.*//' | head -1 | awk '{print $1}'` +# $TEST fe80::1%$IF http +) > scoped_${family}.exp diff --git a/lib/libc/tests/net/getaddrinfo/data/no_host_v4.exp b/lib/libc/tests/net/getaddrinfo/data/no_host_v4.exp new file mode 100644 index 000000000000..7ed41cd9d88a --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/no_host_v4.exp @@ -0,0 +1,44 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http +ai1: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http +ai2: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http +ai3: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo +ai1: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv echo +ai2: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv echo +ai3: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv echo + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp +ai1: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv tftp +ai2: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv tftp + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http +ai2: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http +ai3: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http + +arg: flags 0x2 family 0 socktype 1 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 2 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http + diff --git a/lib/libc/tests/net/getaddrinfo/data/no_host_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/no_host_v4_only.exp new file mode 100644 index 000000000000..596799305117 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/no_host_v4_only.exp @@ -0,0 +1,68 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http +ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo +ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo +ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo +ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp +ai3: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp +ai4: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http +ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http +ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv http +ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv http +ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv http +ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http +ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http +ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo +ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv echo +ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv echo +ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv echo +ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv echo +ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv echo +ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv echo + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp +ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv tftp +ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv tftp +ai3: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv tftp +ai4: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv tftp + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv http +ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv http +ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv http +ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http +ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http +ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http + +arg: flags 0x2 family 0 socktype 1 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 2 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http + diff --git a/lib/libc/tests/net/getaddrinfo/data/no_host_v4v6.exp b/lib/libc/tests/net/getaddrinfo/data/no_host_v4v6.exp new file mode 100644 index 000000000000..596799305117 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/no_host_v4v6.exp @@ -0,0 +1,68 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http +ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo +ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo +ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo +ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp +ai3: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp +ai4: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http +ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http +ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv http +ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv http +ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv http +ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http +ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http +ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo +ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv echo +ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv echo +ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv echo +ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv echo +ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv echo +ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv echo + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp +ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv tftp +ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv tftp +ai3: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv tftp +ai4: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv tftp + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv http +ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv http +ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv http +ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http +ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http +ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http + +arg: flags 0x2 family 0 socktype 1 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 2 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http + diff --git a/lib/libc/tests/net/getaddrinfo/data/no_host_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/no_host_v4v6_prefer_v4.exp new file mode 100644 index 000000000000..596799305117 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/no_host_v4v6_prefer_v4.exp @@ -0,0 +1,68 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http +ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo +ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo +ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo +ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp +ai3: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp +ai4: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http +ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http +ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv http +ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv http +ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv http +ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http +ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http +ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo +ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv echo +ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv echo +ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv echo +ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv echo +ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv echo +ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv echo + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp +ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv tftp +ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv tftp +ai3: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv tftp +ai4: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv tftp + +arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv http +ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv http +ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv http +ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http +ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http +ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http + +arg: flags 0x2 family 0 socktype 1 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 0 socktype 2 protocol 0 addrlen 0 host (empty) serv 80 +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http + diff --git a/lib/libc/tests/net/getaddrinfo/data/no_serv_v4.exp b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4.exp new file mode 100644 index 000000000000..667234d2161f --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4.exp @@ -0,0 +1,17 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv (empty) +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0 +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0 +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0 + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv (empty) +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0 +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0 +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0 + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv (empty) +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0 +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0 +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0 + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv (empty) +Name does not resolve diff --git a/lib/libc/tests/net/getaddrinfo/data/no_serv_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4_only.exp new file mode 100644 index 000000000000..0d28490c8d81 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4_only.exp @@ -0,0 +1,20 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv (empty) +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0 +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0 +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0 + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv (empty) +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0 +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0 +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0 + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv (empty) +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0 +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0 +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0 +ai4: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0 +ai5: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0 +ai6: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0 + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv (empty) +Name does not resolve diff --git a/lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6.exp b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6.exp new file mode 100644 index 000000000000..53502547c40e --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6.exp @@ -0,0 +1,20 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv (empty) +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0 +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0 +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0 + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv (empty) +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0 +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0 +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0 + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv (empty) +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0 +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0 +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0 +ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0 +ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0 +ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0 + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv (empty) +Name does not resolve diff --git a/lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6_prefer_v4.exp new file mode 100644 index 000000000000..0d28490c8d81 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6_prefer_v4.exp @@ -0,0 +1,20 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv (empty) +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0 +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0 +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0 + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv (empty) +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0 +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0 +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0 + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv (empty) +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0 +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0 +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0 +ai4: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0 +ai5: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0 +ai6: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0 + +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv (empty) +Name does not resolve diff --git a/lib/libc/tests/net/getaddrinfo/data/scoped.exp b/lib/libc/tests/net/getaddrinfo/data/scoped.exp new file mode 100644 index 000000000000..f5ddb4bf6feb --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/scoped.exp @@ -0,0 +1,5 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host fe80::1%lo0 serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host fe80::1%lo0 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host fe80::1%lo0 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host fe80::1%lo0 serv http + diff --git a/lib/libc/tests/net/getaddrinfo/data/scoped_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/scoped_v4_only.exp new file mode 100644 index 000000000000..f5ddb4bf6feb --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/scoped_v4_only.exp @@ -0,0 +1,5 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host fe80::1%lo0 serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host fe80::1%lo0 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host fe80::1%lo0 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host fe80::1%lo0 serv http + diff --git a/lib/libc/tests/net/getaddrinfo/data/scoped_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/scoped_v4v6_prefer_v4.exp new file mode 100644 index 000000000000..f5ddb4bf6feb --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/scoped_v4v6_prefer_v4.exp @@ -0,0 +1,5 @@ +arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host fe80::1%lo0 serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host fe80::1%lo0 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host fe80::1%lo0 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host fe80::1%lo0 serv http + diff --git a/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4.exp b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4.exp new file mode 100644 index 000000000000..021038b81dcc --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4.exp @@ -0,0 +1,13 @@ +arg: flags 0x2 family 0 socktype 3 protocol 0 addrlen 0 host localhost serv (empty) +ai1: flags 0x2 family 2 socktype 3 protocol 0 addrlen 16 host 127.0.0.1 serv 0 + +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv (empty) +ai1: flags 0x2 family 2 socktype 3 protocol 59 addrlen 16 host 127.0.0.1 serv 0 + +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv 80 +Service was not recognized for socket type +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv www +Service was not recognized for socket type +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host ::1 serv (empty) +ai1: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0 + diff --git a/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4_only.exp new file mode 100644 index 000000000000..932c1faab0d3 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4_only.exp @@ -0,0 +1,15 @@ +arg: flags 0x2 family 0 socktype 3 protocol 0 addrlen 0 host localhost serv (empty) +ai1: flags 0x2 family 2 socktype 3 protocol 0 addrlen 16 host 127.0.0.1 serv 0 +ai2: flags 0x2 family 28 socktype 3 protocol 0 addrlen 28 host ::1 serv 0 + +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv (empty) +ai1: flags 0x2 family 2 socktype 3 protocol 59 addrlen 16 host 127.0.0.1 serv 0 +ai2: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0 + +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv 80 +Service was not recognized for socket type +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv www +Service was not recognized for socket type +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host ::1 serv (empty) +ai1: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0 + diff --git a/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6.exp b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6.exp new file mode 100644 index 000000000000..e494271a3d35 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6.exp @@ -0,0 +1,15 @@ +arg: flags 0x2 family 0 socktype 3 protocol 0 addrlen 0 host localhost serv (empty) +ai1: flags 0x2 family 28 socktype 3 protocol 0 addrlen 28 host ::1 serv 0 +ai2: flags 0x2 family 2 socktype 3 protocol 0 addrlen 16 host 127.0.0.1 serv 0 + +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv (empty) +ai1: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0 +ai2: flags 0x2 family 2 socktype 3 protocol 59 addrlen 16 host 127.0.0.1 serv 0 + +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv 80 +Service was not recognized for socket type +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv www +Service was not recognized for socket type +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host ::1 serv (empty) +ai1: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0 + diff --git a/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6_prefer_v4.exp new file mode 100644 index 000000000000..932c1faab0d3 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6_prefer_v4.exp @@ -0,0 +1,15 @@ +arg: flags 0x2 family 0 socktype 3 protocol 0 addrlen 0 host localhost serv (empty) +ai1: flags 0x2 family 2 socktype 3 protocol 0 addrlen 16 host 127.0.0.1 serv 0 +ai2: flags 0x2 family 28 socktype 3 protocol 0 addrlen 28 host ::1 serv 0 + +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv (empty) +ai1: flags 0x2 family 2 socktype 3 protocol 59 addrlen 16 host 127.0.0.1 serv 0 +ai2: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0 + +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv 80 +Service was not recognized for socket type +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv www +Service was not recognized for socket type +arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host ::1 serv (empty) +ai1: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0 + diff --git a/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4.exp b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4.exp new file mode 100644 index 000000000000..924d2a16f47c --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4.exp @@ -0,0 +1,7 @@ +arg: flags 0x2 family 2 socktype 0 protocol 0 addrlen 0 host localhost serv http +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 28 socktype 0 protocol 0 addrlen 0 host localhost serv http +Address family for hostname not supported diff --git a/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4_only.exp new file mode 100644 index 000000000000..af3506938503 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4_only.exp @@ -0,0 +1,10 @@ +arg: flags 0x2 family 2 socktype 0 protocol 0 addrlen 0 host localhost serv http +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 28 socktype 0 protocol 0 addrlen 0 host localhost serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http + diff --git a/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6.exp b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6.exp new file mode 100644 index 000000000000..af3506938503 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6.exp @@ -0,0 +1,10 @@ +arg: flags 0x2 family 2 socktype 0 protocol 0 addrlen 0 host localhost serv http +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 28 socktype 0 protocol 0 addrlen 0 host localhost serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http + diff --git a/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6_prefer_v4.exp new file mode 100644 index 000000000000..af3506938503 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6_prefer_v4.exp @@ -0,0 +1,10 @@ +arg: flags 0x2 family 2 socktype 0 protocol 0 addrlen 0 host localhost serv http +ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http +ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http +ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http + +arg: flags 0x2 family 28 socktype 0 protocol 0 addrlen 0 host localhost serv http +ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http +ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http +ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http + diff --git a/lib/libc/tests/net/getaddrinfo/data/unsup_fam.exp b/lib/libc/tests/net/getaddrinfo/data/unsup_fam.exp new file mode 100644 index 000000000000..69e6b48a854b --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/unsup_fam.exp @@ -0,0 +1,2 @@ +arg: flags 0x2 family 99 socktype 0 protocol 0 addrlen 0 host localhost serv (empty) +Address family not recognized diff --git a/lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4_only.exp new file mode 100644 index 000000000000..69e6b48a854b --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4_only.exp @@ -0,0 +1,2 @@ +arg: flags 0x2 family 99 socktype 0 protocol 0 addrlen 0 host localhost serv (empty) +Address family not recognized diff --git a/lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4v6_prefer_v4.exp new file mode 100644 index 000000000000..69e6b48a854b --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4v6_prefer_v4.exp @@ -0,0 +1,2 @@ +arg: flags 0x2 family 99 socktype 0 protocol 0 addrlen 0 host localhost serv (empty) +Address family not recognized diff --git a/lib/libc/tests/net/getaddrinfo/getaddrinfo.c b/lib/libc/tests/net/getaddrinfo/getaddrinfo.c new file mode 100644 index 000000000000..1e066add3119 --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/getaddrinfo.c @@ -0,0 +1,271 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org> + * + * 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 <dlfcn.h> +#include <errno.h> +#include <netdb.h> +#include <stdlib.h> +#include <string.h> +#include <resolv.h> + +#include <atf-c.h> + +static const char goodname[] = "www.freebsd.org"; +static const char goodname_dot[] = "www.freebsd.org."; +static const char badname[] = "does-not-exist.freebsd.org"; +static const char badname_dot[] = "does-not-exist.freebsd.org."; +static const char ipv6onlyname[] = "beefy15.nyi.freebsd.org"; +static const char ipv6onlyname_dot[] = "beefy15.nyi.freebsd.org."; +static const char ipv4onlyname[] = "ipv4only.arpa"; +static const char ipv4onlyname_dot[] = "ipv4only.arpa."; +/* + * We need an IP address that doesn't exist, but not reported with ICMP + * unreachable by the nearest router. Let's try TEST-NET-3. + */ +static char badresolvconf[] = "nameserver 203.0.113.1"; +static char badresolvconf2[] = "nameserver 203.0.113.1\n" + "nameserver 203.0.113.2"; +static char *resconf = NULL; +FILE * +fopen(const char * restrict path, const char * restrict mode) +{ + static FILE *(*orig)(const char *, const char *); + + if (orig == NULL && (orig = dlsym(RTLD_NEXT, "fopen")) == NULL) + atf_libc_error(ENOENT, "dlsym(fopen): %s", dlerror()); + if (resconf != NULL && strcmp(path, _PATH_RESCONF) == 0) + return (fmemopen(resconf, strlen(resconf), mode)); + else + return (orig(path, mode)); +} + +static int send_error = 0; +ssize_t +send(int s, const void *msg, size_t len, int flags) +{ + static ssize_t (*orig)(int, const void *, size_t, int); + + if (orig == NULL && (orig = dlsym(RTLD_NEXT, "send")) == NULL) + atf_libc_error(ENOENT, "dlsym(send): %s", dlerror()); + if (send_error != 0) { + errno = send_error; + return (-1); + } else { + return (orig(s, msg, len, flags)); + } +} + +ATF_TC(basic); +ATF_TC_HEAD(basic, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} + +ATF_TC_BODY(basic, tc) +{ + static const struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_flags = AI_CANONNAME, + }; + struct addrinfo *res; + int rv; + + rv = getaddrinfo(goodname, NULL, &hints, &res); + ATF_REQUIRE_MSG(rv == 0, + "Expected 0, got %d (%s)", rv, gai_strerror(rv)); + freeaddrinfo(res); + + rv = getaddrinfo(goodname_dot, NULL, &hints, &res); + ATF_REQUIRE_MSG(rv == 0, + "Expected 0, got %d (%s)", rv, gai_strerror(rv)); + freeaddrinfo(res); + + rv = getaddrinfo(badname, NULL, &hints, &res); + ATF_REQUIRE_MSG(rv == EAI_NONAME, + "Expected %d (EAI_NONAME), got %d (%s)", + EAI_NONAME, rv, gai_strerror(rv)); + + rv = getaddrinfo(badname_dot, NULL, &hints, &res); + ATF_REQUIRE_MSG(rv == EAI_NONAME, + "Expected %d (EAI_NONAME), got %d (%s)", + EAI_NONAME, rv, gai_strerror(rv)); +} + +ATF_TC_WITHOUT_HEAD(timeout); +ATF_TC_BODY(timeout, tc) +{ + static const struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_flags = AI_CANONNAME, + }; + struct addrinfo *res; + int rv; + + resconf = badresolvconf; + rv = getaddrinfo(goodname, NULL, &hints, &res); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); + + rv = getaddrinfo(goodname_dot, NULL, &hints, &res); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); +} + +ATF_TC_WITHOUT_HEAD(timeout_specific); +ATF_TC_BODY(timeout_specific, tc) +{ + static const struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM, + .ai_flags = AI_CANONNAME, + }; + struct addrinfo *res; + int rv; + + resconf = badresolvconf; + rv = getaddrinfo(goodname, "666", &hints, &res); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); + + rv = getaddrinfo(goodname_dot, "666", &hints, &res); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); +} + +ATF_TC_WITHOUT_HEAD(timeout2); +ATF_TC_BODY(timeout2, tc) +{ + static const struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_flags = AI_CANONNAME, + }; + struct addrinfo *res; + int rv; + + resconf = badresolvconf2; + rv = getaddrinfo(goodname, NULL, &hints, &res); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); + + rv = getaddrinfo(goodname_dot, NULL, &hints, &res); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); +} + +/* + * Emulate interface/network down. + */ +ATF_TC_WITHOUT_HEAD(netdown); +ATF_TC_BODY(netdown, tc) +{ + static const struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_flags = AI_CANONNAME, + }; + struct addrinfo *res; + int rv; + + send_error = ENETDOWN; + rv = getaddrinfo(goodname, NULL, &hints, &res); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); + + rv = getaddrinfo(goodname_dot, NULL, &hints, &res); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); +} + +/* + * See https://reviews.freebsd.org/D37139. + */ +ATF_TC(nofamily); +ATF_TC_HEAD(nofamily, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} +ATF_TC_BODY(nofamily, tc) +{ + static const struct addrinfo hints4 = { + .ai_family = AF_INET, + .ai_flags = AI_CANONNAME, + }, hints6 = { + .ai_family = AF_INET6, + .ai_flags = AI_CANONNAME, + }; + struct addrinfo *res; + int rv; + + rv = getaddrinfo(ipv6onlyname, NULL, &hints4, &res); + ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY, + "Expected %d (EAI_ADDRFAMILY), got %d (%s)", + EAI_ADDRFAMILY, rv, gai_strerror(rv)); + + rv = getaddrinfo(ipv6onlyname_dot, NULL, &hints4, &res); + ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY, + "Expected %d (EAI_ADDRFAMILY), got %d (%s)", + EAI_ADDRFAMILY, rv, gai_strerror(rv)); + + rv = getaddrinfo(ipv4onlyname, NULL, &hints6, &res); + ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY, + "Expected %d (EAI_ADDRFAMILY), got %d (%s)", + EAI_ADDRFAMILY, rv, gai_strerror(rv)); + + rv = getaddrinfo(ipv4onlyname_dot, NULL, &hints6, &res); + ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY, + "Expected %d (EAI_ADDRFAMILY), got %d (%s)", + EAI_ADDRFAMILY, rv, gai_strerror(rv)); + + rv = getaddrinfo(badname, NULL, &hints4, &res); + ATF_REQUIRE_MSG(rv == EAI_NONAME, + "Expected %d (EAI_NONAME), got %d (%s)", + EAI_NONAME, rv, gai_strerror(rv)); + + rv = getaddrinfo(badname_dot, NULL, &hints6, &res); + ATF_REQUIRE_MSG(rv == EAI_NONAME, + "Expected %d (EAI_NONAME), got %d (%s)", + EAI_NONAME, rv, gai_strerror(rv)); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, basic); + ATF_TP_ADD_TC(tp, timeout); + ATF_TP_ADD_TC(tp, timeout_specific); + ATF_TP_ADD_TC(tp, timeout2); + ATF_TP_ADD_TC(tp, netdown); + ATF_TP_ADD_TC(tp, nofamily); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/net/getaddrinfo/getaddrinfo_test.sh b/lib/libc/tests/net/getaddrinfo/getaddrinfo_test.sh new file mode 100755 index 000000000000..dd17ab2e3f4a --- /dev/null +++ b/lib/libc/tests/net/getaddrinfo/getaddrinfo_test.sh @@ -0,0 +1,443 @@ +# $NetBSD: t_getaddrinfo.sh,v 1.2 2011/06/15 07:54:32 jmmv Exp $ + +# +# Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, and 2002 WIDE Project. +# All rights reserved. +# +# 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. +# 3. Neither the name of the project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. +# + +if [ "$(sysctl -i -n kern.features.vimage)" != 1 ]; then + atf_skip "This test requires VIMAGE" +fi + +vnet_mkjail() +{ + jailname=getaddrinfo_test_$1 + jail -c name=${jailname} persist vnet + ifconfig -j ${jailname} lo0 inet 127.0.0.1/8 + # For those machines not support IPv6 + ifconfig -j ${jailname} lo0 inet6 ::1/64 || true + service -j ${jailname} ip6addrctl $2 || true +} + +vnet_cleanup() +{ + jailname=getaddrinfo_test_$1 + jail -r ${jailname} +} + +check_output() +{ + if [ "$2" = "none" ]; then + if [ "$3" = "prefer_v6" ]; then + exp="${1}.exp" + else + exp="${1}_v4_only.exp" + fi + elif [ "$2" = "hosts" ]; then + lcl=$(cat /etc/hosts | sed -e 's/#.*$//' -e 's/[ ][ ]*/ /g' | awk '/ localhost($| )/ {printf "%s ", $1}') + if [ "${lcl%*::*}" = "${lcl}" ]; then + exp="${1}_v4_only.exp" + else + if [ "$3" = "prefer_v6" ]; then + exp="${1}_v4v6.exp" + else + exp="${1}_v4v6_prefer_v4.exp" + fi + fi + elif [ "$2" = "ifconfig" ]; then + lcl=$(ifconfig lo0 | grep inet6) + if [ -n "${lcl}" ]; then + if [ "$3" = "prefer_v6" ]; then + exp="${1}_v4v6.exp" + else + exp="${1}_v4v6_prefer_v4.exp" + fi + else + exp="${1}_v4_only.exp" + fi + else + atf_fail "Invalid family_match_type $2 requested." + fi + + cmp -s "$(atf_get_srcdir)/data/${exp}" out && return + diff -u "$(atf_get_srcdir)/data/${exp}" out || atf_fail "Actual output does not match expected output" +} + +atf_test_case basic_prefer_v4 cleanup +basic_prefer_v4_head() +{ + atf_set "descr" "Testing basic ones with prefer_v4" + atf_set "require.user" "root" +} +basic_prefer_v4_body() +{ + vnet_mkjail basic_prefer_v4 prefer_ipv4 + TEST="jexec getaddrinfo_test_basic_prefer_v4 $(atf_get_srcdir)/h_gai" + + ( $TEST ::1 http + $TEST 127.0.0.1 http + $TEST localhost http + $TEST ::1 tftp + $TEST 127.0.0.1 tftp + $TEST localhost tftp + $TEST ::1 echo + $TEST 127.0.0.1 echo + $TEST localhost echo ) > out 2>&1 + + check_output basics hosts prefer_v4 +} +basic_prefer_v4_cleanup() +{ + vnet_cleanup basic_prefer_v4 +} + +atf_test_case basic cleanup +basic_head() +{ + atf_set "descr" "Testing basic ones with prefer_v6" + atf_set "require.user" "root" +} +basic_body() +{ + vnet_mkjail basic prefer_ipv6 + TEST="jexec getaddrinfo_test_basic $(atf_get_srcdir)/h_gai" + + ( $TEST ::1 http + $TEST 127.0.0.1 http + $TEST localhost http + $TEST ::1 tftp + $TEST 127.0.0.1 tftp + $TEST localhost tftp + $TEST ::1 echo + $TEST 127.0.0.1 echo + $TEST localhost echo ) > out 2>&1 + + check_output basics ifconfig prefer_v6 +} +basic_cleanup() +{ + vnet_cleanup basic +} + +atf_test_case specific_prefer_v4 cleanup +specific_prefer_v4_head() +{ + atf_set "descr" "Testing specific address family with prefer_v4" + atf_set "require.user" "root" +} +specific_prefer_v4_body() +{ + vnet_mkjail specific_prefer_v4 prefer_ipv4 + TEST="jexec getaddrinfo_test_specific_prefer_v4 $(atf_get_srcdir)/h_gai" + + ( $TEST -4 localhost http + $TEST -6 localhost http ) > out 2>&1 + + check_output spec_fam hosts prefer_v4 +} +specific_prefer_v4_cleanup() +{ + vnet_cleanup specific_prefer_v4 +} + +atf_test_case specific cleanup +specific_head() +{ + atf_set "descr" "Testing specific address family with prefer_v6" + atf_set "require.user" "root" +} +specific_body() +{ + vnet_mkjail specific prefer_ipv6 + TEST="jexec getaddrinfo_test_specific $(atf_get_srcdir)/h_gai" + + ( $TEST -4 localhost http + $TEST -6 localhost http ) > out 2>&1 + + check_output spec_fam hosts prefer_v6 +} +specific_cleanup() +{ + vnet_cleanup specific +} + +atf_test_case empty_hostname_prefer_v4 cleanup +empty_hostname_prefer_v4_head() +{ + atf_set "descr" "Testing empty hostname with prefer_v4" + atf_set "require.user" "root" +} +empty_hostname_prefer_v4_body() +{ + vnet_mkjail empty_hostname_prefer_v4 prefer_ipv4 + TEST="jexec getaddrinfo_test_empty_hostname_prefer_v4 $(atf_get_srcdir)/h_gai" + + ( $TEST '' http + $TEST '' echo + $TEST '' tftp + $TEST '' 80 + $TEST -P '' http + $TEST -P '' echo + $TEST -P '' tftp + $TEST -P '' 80 + $TEST -S '' 80 + $TEST -D '' 80 ) > out 2>&1 + + check_output no_host ifconfig prefer_v4 +} +empty_hostname_prefer_v4_cleanup() +{ + vnet_cleanup empty_hostname_prefer_v4 +} + +atf_test_case empty_hostname cleanup +empty_hostname_head() +{ + atf_set "descr" "Testing empty hostname with prefer_v6" + atf_set "require.user" "root" +} +empty_hostname_body() +{ + vnet_mkjail empty_hostname prefer_ipv6 + TEST="jexec getaddrinfo_test_empty_hostname $(atf_get_srcdir)/h_gai" + + ( $TEST '' http + $TEST '' echo + $TEST '' tftp + $TEST '' 80 + $TEST -P '' http + $TEST -P '' echo + $TEST -P '' tftp + $TEST -P '' 80 + $TEST -S '' 80 + $TEST -D '' 80 ) > out 2>&1 + + check_output no_host ifconfig prefer_v6 +} +empty_hostname_cleanup() +{ + vnet_cleanup empty_hostname +} + +atf_test_case empty_servname_prefer_v4 cleanup +empty_servname_prefer_v4_head() +{ + atf_set "descr" "Testing empty service name with prefer_v4" + atf_set "require.user" "root" +} +empty_servname_prefer_v4_body() +{ + vnet_mkjail empty_servname_prefer_v4 prefer_ipv4 + TEST="jexec getaddrinfo_test_empty_servname_prefer_v4 $(atf_get_srcdir)/h_gai" + + ( $TEST ::1 '' + $TEST 127.0.0.1 '' + $TEST localhost '' + $TEST '' '' ) > out 2>&1 + + check_output no_serv hosts prefer_v4 +} +empty_servname_prefer_v4_cleanup() +{ + vnet_cleanup empty_servname_prefer_v4 +} + +atf_test_case empty_servname cleanup +empty_servname_head() +{ + atf_set "descr" "Testing empty service name with prefer_v6" + atf_set "require.user" "root" +} +empty_servname_body() +{ + vnet_mkjail empty_servname prefer_ipv6 + TEST="jexec getaddrinfo_test_empty_servname $(atf_get_srcdir)/h_gai" + + ( $TEST ::1 '' + $TEST 127.0.0.1 '' + $TEST localhost '' + $TEST '' '' ) > out 2>&1 + + check_output no_serv ifconfig prefer_v6 +} +empty_servname_cleanup() +{ + vnet_cleanup empty_servname +} + +atf_test_case sock_raw_prefer_v4 cleanup +sock_raw_prefer_v4_head() +{ + atf_set "descr" "Testing raw socket with prefer_v4" + atf_set "require.user" "root" +} +sock_raw_prefer_v4_body() +{ + vnet_mkjail sock_raw_prefer_v4 prefer_ipv4 + TEST="jexec getaddrinfo_test_sock_raw_prefer_v4 $(atf_get_srcdir)/h_gai" + + ( $TEST -R -p 0 localhost '' + $TEST -R -p 59 localhost '' + $TEST -R -p 59 localhost 80 + $TEST -R -p 59 localhost www + $TEST -R -p 59 ::1 '' ) > out 2>&1 + + check_output sock_raw hosts prefer_v4 +} +sock_raw_prefer_v4_cleanup() +{ + vnet_cleanup sock_raw_prefer_v4 +} + +atf_test_case sock_raw cleanup +sock_raw_head() +{ + atf_set "descr" "Testing raw socket with prefer_v6" + atf_set "require.user" "root" +} +sock_raw_body() +{ + vnet_mkjail sock_raw prefer_ipv6 + TEST="jexec getaddrinfo_test_sock_raw $(atf_get_srcdir)/h_gai" + + ( $TEST -R -p 0 localhost '' + $TEST -R -p 59 localhost '' + $TEST -R -p 59 localhost 80 + $TEST -R -p 59 localhost www + $TEST -R -p 59 ::1 '' ) > out 2>&1 + + check_output sock_raw ifconfig prefer_v6 +} +sock_raw_cleanup() +{ + vnet_cleanup sock_raw +} + +atf_test_case unsupported_family_prefer_v4 cleanup +unsupported_family_prefer_v4_head() +{ + atf_set "descr" "Testing unsupported family with prefer_v4" + atf_set "require.user" "root" +} +unsupported_family_prefer_v4_body() +{ + vnet_mkjail unsupported_family_prefer_v4 prefer_ipv4 + TEST="jexec getaddrinfo_test_unsupported_family_prefer_v4 $(atf_get_srcdir)/h_gai" + + ( $TEST -f 99 localhost '' ) > out 2>&1 + + check_output unsup_fam ifconfig prefer_v4 +} +unsupported_family_prefer_v4_cleanup() +{ + vnet_cleanup unsupported_family_prefer_v4 +} + +atf_test_case unsupported_family cleanup +unsupported_family_head() +{ + atf_set "descr" "Testing unsupported family with prefer_v6" + atf_set "require.user" "root" +} +unsupported_family_body() +{ + vnet_mkjail unsupported_family prefer_ipv6 + TEST="jexec getaddrinfo_test_unsupported_family $(atf_get_srcdir)/h_gai" + + ( $TEST -f 99 localhost '' ) > out 2>&1 + + check_output unsup_fam none prefer_v6 +} +unsupported_family_cleanup() +{ + vnet_cleanup unsupported_family +} + +atf_test_case scopeaddr_prefer_v4 cleanup +scopeaddr_prefer_v4_head() +{ + atf_set "descr" "Testing scoped address format with prefer_v4" + atf_set "require.user" "root" +} +scopeaddr_prefer_v4_body() +{ + vnet_mkjail scopeaddr_prefer_v4 prefer_ipv4 + TEST="jexec getaddrinfo_test_scopeaddr_prefer_v4 $(atf_get_srcdir)/h_gai" + + ( $TEST fe80::1%lo0 http +# IF=ifconfig -a | grep -v '^ ' | sed -e 's/:.*//' | head -1 | awk '{print $1}' +# $TEST fe80::1%$IF http + ) > out 2>&1 + + check_output scoped ifconfig prefer_v4 +} +scopeaddr_prefer_v4_cleanup() +{ + vnet_cleanup scopeaddr_prefer_v4 +} + +atf_test_case scopeaddr cleanup +scopeaddr_head() +{ + atf_set "descr" "Testing scoped address format with prefer_v6" + atf_set "require.user" "root" +} +scopeaddr_body() +{ + vnet_mkjail scopeaddr prefer_ipv6 + TEST="jexec getaddrinfo_test_scopeaddr $(atf_get_srcdir)/h_gai" + + ( $TEST fe80::1%lo0 http +# IF=ifconfig -a | grep -v '^ ' | sed -e 's/:.*//' | head -1 | awk '{print $1}' +# $TEST fe80::1%$IF http + ) > out 2>&1 + + check_output scoped none prefer_v6 +} +scopeaddr_cleanup() +{ + vnet_cleanup scopeaddr +} + +atf_init_test_cases() +{ + atf_add_test_case basic_prefer_v4 + atf_add_test_case specific_prefer_v4 + atf_add_test_case empty_hostname_prefer_v4 + atf_add_test_case empty_servname_prefer_v4 + atf_add_test_case sock_raw_prefer_v4 + atf_add_test_case unsupported_family_prefer_v4 + atf_add_test_case scopeaddr_prefer_v4 + + atf_add_test_case basic + atf_add_test_case specific + atf_add_test_case empty_hostname + atf_add_test_case empty_servname + atf_add_test_case sock_raw + atf_add_test_case unsupported_family + atf_add_test_case scopeaddr +} diff --git a/lib/libc/tests/net/link_addr_test.cc b/lib/libc/tests/net/link_addr_test.cc new file mode 100644 index 000000000000..b973b924dc13 --- /dev/null +++ b/lib/libc/tests/net/link_addr_test.cc @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2025 Lexi Winter + * + * SPDX-License-Identifier: ISC + */ + +/* + * Tests for link_addr() and link_ntoa(). + * + * link_addr converts a string representing an (optionally null) interface name + * followed by an Ethernet address into a sockaddr_dl. The expected format is + * "[ifname]:lladdr". This means if ifname is not specified, the leading colon + * is still required. + * + * link_ntoa does the inverse of link_addr, returning a string representation + * of the address. + * + * Note that the output format of link_ntoa is not valid input for link_addr + * since the leading colon may be omitted. This is by design. + */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <net/ethernet.h> +#include <net/if_dl.h> + +#include <format> +#include <iostream> +#include <ranges> +#include <span> +#include <utility> +#include <vector> + +#include <cstddef> +#include <cstdint> + +#include <atf-c++.hpp> + +using namespace std::literals; + +/* + * Define operator== and operator<< for ether_addr so we can use them in + * ATF_EXPECT_EQ expressions. + */ + +bool +operator==(ether_addr a, ether_addr b) +{ + return (std::ranges::equal(a.octet, b.octet)); +} + +std::ostream & +operator<<(std::ostream &s, ether_addr a) +{ + for (unsigned i = 0; i < ETHER_ADDR_LEN; ++i) { + if (i > 0) + s << ":"; + + s << std::format("{:02x}", static_cast<int>(a.octet[i])); + } + + return (s); +} + +/* + * Create a sockaddr_dl from a string using link_addr(), and ensure the + * returned struct looks valid. + */ +sockaddr_dl +make_linkaddr(const std::string &addr) +{ + auto sdl = sockaddr_dl{}; + int ret; + + sdl.sdl_len = sizeof(sdl); + ret = ::link_addr(addr.c_str(), &sdl); + + ATF_REQUIRE_EQ(0, ret); + ATF_REQUIRE_EQ(AF_LINK, static_cast<int>(sdl.sdl_family)); + ATF_REQUIRE_EQ(true, sdl.sdl_len > 0); + ATF_REQUIRE_EQ(true, sdl.sdl_nlen >= 0); + + return (sdl); +} + +/* + * Return the data stored in a sockaddr_dl as a span. + */ +std::span<const char> +data(const sockaddr_dl &sdl) +{ + // sdl_len is the entire structure, but we only want the length of the + // data area. + auto dlen = sdl.sdl_len - offsetof(sockaddr_dl, sdl_data); + return {&sdl.sdl_data[0], dlen}; +} + +/* + * Return the interface name stored in a sockaddr_dl as a string. + */ +std::string_view +ifname(const sockaddr_dl &sdl) +{ + auto name = data(sdl).subspan(0, sdl.sdl_nlen); + return {name.begin(), name.end()}; +} + +/* + * Return the Ethernet address stored in a sockaddr_dl as an ether_addr. + */ +ether_addr +addr(const sockaddr_dl &sdl) +{ + ether_addr ret{}; + ATF_REQUIRE_EQ(ETHER_ADDR_LEN, sdl.sdl_alen); + std::ranges::copy(data(sdl).subspan(sdl.sdl_nlen, ETHER_ADDR_LEN), + &ret.octet[0]); + return (ret); +} + +/* + * Return the link address stored in a sockaddr_dl as a span of octets. + */ +std::span<const std::uint8_t> +lladdr(const sockaddr_dl &sdl) +{ + auto data = reinterpret_cast<const uint8_t *>(LLADDR(&sdl)); + return {data, data + sdl.sdl_alen}; +} + + +/* + * Some sample addresses we use for testing. Include at least one address for + * each format we want to support. + */ + +struct test_address { + std::string input; /* value passed to link_addr */ + std::string ntoa; /* expected return from link_ntoa */ + ether_addr addr{}; /* expected return from link_addr */ +}; + +std::vector<test_address> test_addresses{ + // No delimiter + {"001122334455"s, "0.11.22.33.44.55", + ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}}, + + // Colon delimiter + {"00:11:22:33:44:55"s, "0.11.22.33.44.55", + ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}}, + + // Dash delimiter + {"00-11-22-33-44-55"s, "0.11.22.33.44.55", + ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}}, + + // Period delimiter (link_ntoa format) + {"00.11.22.33.44.55"s, "0.11.22.33.44.55", + ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}}, + + // Period delimiter (Cisco format) + {"0011.2233.4455"s, "0.11.22.33.44.55", + ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}}, + + // An addresses without leading zeroes. + {"0:1:02:30:4:55"s, "0.1.2.30.4.55", + ether_addr{0x00, 0x01, 0x02, 0x30, 0x04, 0x55}}, + + // An address with some uppercase letters. + {"AA:B:cC:Dd:e0:1f"s, "aa.b.cc.dd.e0.1f", + ether_addr{0xaa, 0x0b, 0xcc, 0xdd, 0xe0, 0x1f}}, + + // Addresses composed only of letters, to make sure they're not + // confused with an interface name. + + {"aabbccddeeff"s, "aa.bb.cc.dd.ee.ff", + ether_addr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}, + + {"aa:bb:cc:dd:ee:ff"s, "aa.bb.cc.dd.ee.ff", + ether_addr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}, + + // Address with a blank octet; this is an old form of Ethernet address. + {"00:11::33:44:55"s, "0.11.0.33.44.55", + ether_addr{0x00, 0x11, 0x00, 0x33, 0x44, 0x55}}, +}; + +/* + * Test without an interface name. + */ +ATF_TEST_CASE_WITHOUT_HEAD(basic) +ATF_TEST_CASE_BODY(basic) +{ + for (const auto &ta : test_addresses) { + // This does basic tests on the returned value. + auto sdl = make_linkaddr(":" + ta.input); + + // Check the ifname and address. + ATF_REQUIRE_EQ(""s, ifname(sdl)); + ATF_REQUIRE_EQ(ETHER_ADDR_LEN, static_cast<int>(sdl.sdl_alen)); + ATF_REQUIRE_EQ(ta.addr, addr(sdl)); + + // Check link_ntoa returns the expected value. + auto ntoa = std::string(::link_ntoa(&sdl)); + ATF_REQUIRE_EQ(ta.ntoa, ntoa); + } + +} + +/* + * Test with an interface name. + */ +ATF_TEST_CASE_WITHOUT_HEAD(ifname) +ATF_TEST_CASE_BODY(ifname) +{ + for (const auto &ta : test_addresses) { + auto sdl = make_linkaddr("ix0:" + ta.input); + + ATF_REQUIRE_EQ("ix0", ifname(sdl)); + ATF_REQUIRE_EQ(ETHER_ADDR_LEN, static_cast<int>(sdl.sdl_alen)); + ATF_REQUIRE_EQ(ta.addr, addr(sdl)); + + auto ntoa = std::string(::link_ntoa(&sdl)); + ATF_REQUIRE_EQ("ix0:" + ta.ntoa, ntoa); + } + +} + +/* + * Test with some invalid addresses. + */ +ATF_TEST_CASE_WITHOUT_HEAD(invalid) +ATF_TEST_CASE_BODY(invalid) +{ + auto const invalid_addresses = std::vector{ + // Invalid separator + ":1/2/3"s, + "ix0:1/2/3"s, + + // Multiple different separators + ":1.2-3"s, + "ix0:1.2-3"s, + + // An IP address + ":10.1.2.200/28"s, + "ix0:10.1.2.200/28"s, + + // Valid address followed by garbage + ":1.2.3xxx"s, + ":1.2.3.xxx"s, + "ix0:1.2.3xxx"s, + "ix0:1.2.3.xxx"s, + }; + + for (auto const &addr : invalid_addresses) { + int ret; + + auto sdl = sockaddr_dl{}; + sdl.sdl_len = sizeof(sdl); + + ret = link_addr(addr.c_str(), &sdl); + ATF_REQUIRE_EQ(-1, ret); + } +} + +/* + * Test some non-Ethernet addresses. + */ +ATF_TEST_CASE_WITHOUT_HEAD(nonether) +ATF_TEST_CASE_BODY(nonether) +{ + sockaddr_dl sdl; + + /* A short address */ + sdl = make_linkaddr(":1:23:cc"); + ATF_REQUIRE_EQ("", ifname(sdl)); + ATF_REQUIRE_EQ("1.23.cc"s, ::link_ntoa(&sdl)); + ATF_REQUIRE_EQ(3, sdl.sdl_alen); + ATF_REQUIRE_EQ(true, + std::ranges::equal(std::vector{0x01u, 0x23u, 0xccu}, lladdr(sdl))); + + /* A long address */ + sdl = make_linkaddr(":1:23:cc:a:b:c:d:e:f"); + ATF_REQUIRE_EQ("", ifname(sdl)); + ATF_REQUIRE_EQ("1.23.cc.a.b.c.d.e.f"s, ::link_ntoa(&sdl)); + ATF_REQUIRE_EQ(9, sdl.sdl_alen); + ATF_REQUIRE_EQ(true, std::ranges::equal( + std::vector{0x01u, 0x23u, 0xccu, 0xau, 0xbu, 0xcu, 0xdu, 0xeu, 0xfu}, + lladdr(sdl))); +} + +/* + * Test link_addr behaviour with undersized buffers. + */ +ATF_TEST_CASE_WITHOUT_HEAD(smallbuf) +ATF_TEST_CASE_BODY(smallbuf) +{ + static constexpr auto garbage = std::byte{0xcc}; + auto buf = std::vector<std::byte>(); + sockaddr_dl *sdl; + int ret; + + /* + * Make an sdl with an sdl_data member of the appropriate size, and + * place it in buf. Ensure it's followed by a trailing byte of garbage + * so we can test that link_addr doesn't write past the end. + */ + auto mksdl = [&buf](std::size_t datalen) -> sockaddr_dl * { + auto actual_size = datalen + offsetof(sockaddr_dl, sdl_data); + + buf.resize(actual_size + 1); + std::ranges::fill(buf, garbage); + + auto *sdl = new(reinterpret_cast<sockaddr_dl *>(&buf[0])) + sockaddr_dl; + sdl->sdl_len = actual_size; + return (sdl); + }; + + /* An sdl large enough to store the interface name */ + sdl = mksdl(3); + ret = link_addr("ix0:1.2.3", sdl); + ATF_REQUIRE(*rbegin(buf) == garbage); + ATF_REQUIRE_EQ(-1, ret); + ATF_REQUIRE_EQ(ENOSPC, errno); + ATF_REQUIRE_EQ(3, sdl->sdl_nlen); + ATF_REQUIRE_EQ("ix0", ifname(*sdl)); + ATF_REQUIRE_EQ(0, static_cast<int>(sdl->sdl_alen)); + + /* + * For these tests, test both with and without an interface name, since + * that will overflow the buffer in different places. + */ + + /* An empty sdl. Nothing may grow on this cursed ground. */ + + sdl = mksdl(0); + ret = link_addr("ix0:1.2.3", sdl); + ATF_REQUIRE(*rbegin(buf) == garbage); + ATF_REQUIRE_EQ(-1, ret); + ATF_REQUIRE_EQ(ENOSPC, errno); + ATF_REQUIRE_EQ(0, sdl->sdl_nlen); + ATF_REQUIRE_EQ(0, static_cast<int>(sdl->sdl_alen)); + + sdl = mksdl(0); + ret = link_addr(":1.2.3", sdl); + ATF_REQUIRE(*rbegin(buf) == garbage); + ATF_REQUIRE_EQ(-1, ret); + ATF_REQUIRE_EQ(ENOSPC, errno); + ATF_REQUIRE_EQ(0, sdl->sdl_nlen); + ATF_REQUIRE_EQ(0, static_cast<int>(sdl->sdl_alen)); + + /* + * An sdl large enough to store the interface name and two octets of the + * address. + */ + + sdl = mksdl(5); + ret = link_addr("ix0:1.2.3", sdl); + ATF_REQUIRE(*rbegin(buf) == garbage); + ATF_REQUIRE_EQ(-1, ret); + ATF_REQUIRE_EQ(ENOSPC, errno); + ATF_REQUIRE_EQ("ix0", ifname(*sdl)); + ATF_REQUIRE(std::ranges::equal( + std::vector{ 0x01, 0x02 }, lladdr(*sdl))); + + sdl = mksdl(2); + ret = link_addr(":1.2.3", sdl); + ATF_REQUIRE(*rbegin(buf) == garbage); + ATF_REQUIRE_EQ(-1, ret); + ATF_REQUIRE_EQ(ENOSPC, errno); + ATF_REQUIRE_EQ("", ifname(*sdl)); + ATF_REQUIRE(std::ranges::equal( + std::vector{ 0x01, 0x02 }, lladdr(*sdl))); + + /* + * An sdl large enough to store the entire address. + */ + + sdl = mksdl(6); + ret = link_addr("ix0:1.2.3", sdl); + ATF_REQUIRE(*rbegin(buf) == garbage); + ATF_REQUIRE_EQ(0, ret); + ATF_REQUIRE_EQ("ix0", ifname(*sdl)); + ATF_REQUIRE(std::ranges::equal( + std::vector{ 0x01, 0x02, 0x03 }, lladdr(*sdl))); + + sdl = mksdl(3); + ret = link_addr(":1.2.3", sdl); + ATF_REQUIRE(*rbegin(buf) == garbage); + ATF_REQUIRE_EQ(0, ret); + ATF_REQUIRE_EQ("", ifname(*sdl)); + ATF_REQUIRE(std::ranges::equal( + std::vector{ 0x01, 0x02, 0x03 }, lladdr(*sdl))); +} + +/* + * Test an extremely long address which would overflow link_ntoa's internal + * buffer. It should handle this by truncating the output. + * (Test for SA-16:37.libc / CVE-2016-6559.) + */ +ATF_TEST_CASE_WITHOUT_HEAD(overlong) +ATF_TEST_CASE_BODY(overlong) +{ + auto sdl = make_linkaddr( + ":01.02.03.04.05.06.07.08.09.0a.0b.0c.0d.0e.0f." + "11.12.13.14.15.16.17.18.19.1a.1b.1c.1d.1e.1f." + "22.22.23.24.25.26.27.28.29.2a.2b.2c.2d.2e.2f"); + + ATF_REQUIRE_EQ( + "1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.11.12.13.14.15.16.17.18.19.1a.1b."s, + ::link_ntoa(&sdl)); +} + +/* + * Test link_ntoa_r, the re-entrant version of link_ntoa(). + */ +ATF_TEST_CASE_WITHOUT_HEAD(link_ntoa_r) +ATF_TEST_CASE_BODY(link_ntoa_r) +{ + static constexpr char garbage = 0x41; + std::vector<char> buf; + sockaddr_dl sdl; + size_t len; + int ret; + + // Return the contents of buf as a string, using the NUL terminator to + // determine length. This is to ensure we're using the return value in + // the same way C code would, but we do a bit more verification to + // elicit a test failure rather than a SEGV if it's broken. + auto bufstr = [&buf]() -> std::string_view { + // Find the NUL. + auto end = std::ranges::find(buf, '\0'); + ATF_REQUIRE(end != buf.end()); + + // Intentionally chopping the NUL off. + return {begin(buf), end}; + }; + + // Resize the buffer and set the contents to a known garbage value, so + // we don't accidentally have a NUL in the right place when link_ntoa_r + // didn't put it there. + auto resetbuf = [&buf, &len](std::size_t size) { + len = size; + buf.resize(len); + std::ranges::fill(buf, garbage); + }; + + // Test a short address with a large buffer. + sdl = make_linkaddr("ix0:1.2.3"); + resetbuf(64); + ret = ::link_ntoa_r(&sdl, &buf[0], &len); + ATF_REQUIRE_EQ(0, ret); + ATF_REQUIRE_EQ(10, len); + ATF_REQUIRE_EQ("ix0:1.2.3"s, bufstr()); + + // Test a buffer which is exactly the right size. + sdl = make_linkaddr("ix0:1.2.3"); + resetbuf(10); + ret = ::link_ntoa_r(&sdl, &buf[0], &len); + ATF_REQUIRE_EQ(0, ret); + ATF_REQUIRE_EQ(10, len); + ATF_REQUIRE_EQ("ix0:1.2.3"sv, bufstr()); + + // Test various short buffers, using a table of buffer length and the + // output we expect. All of these should produce valid but truncated + // strings, with a trailing NUL and with buflen set correctly. + + auto buftests = std::vector<std::pair<std::size_t, std::string_view>>{ + {1u, ""sv}, + {2u, ""sv}, + {3u, ""sv}, + {4u, "ix0"sv}, + {5u, "ix0:"sv}, + {6u, "ix0:1"sv}, + {7u, "ix0:1."sv}, + {8u, "ix0:1.2"sv}, + {9u, "ix0:1.2."sv}, + }; + + for (auto const &[buflen, expected] : buftests) { + sdl = make_linkaddr("ix0:1.2.3"); + resetbuf(buflen); + ret = ::link_ntoa_r(&sdl, &buf[0], &len); + ATF_REQUIRE_EQ(-1, ret); + ATF_REQUIRE_EQ(10, len); + ATF_REQUIRE_EQ(expected, bufstr()); + } + + // Test a NULL buffer, which should just set buflen. + sdl = make_linkaddr("ix0:1.2.3"); + len = 0; + ret = ::link_ntoa_r(&sdl, NULL, &len); + ATF_REQUIRE_EQ(-1, ret); + ATF_REQUIRE_EQ(10, len); + + // A NULL buffer with a non-zero length should also be accepted. + sdl = make_linkaddr("ix0:1.2.3"); + len = 64; + ret = ::link_ntoa_r(&sdl, NULL, &len); + ATF_REQUIRE_EQ(-1, ret); + ATF_REQUIRE_EQ(10, len); + + // Test a non-NULL buffer, but with a length of zero. + sdl = make_linkaddr("ix0:1.2.3"); + resetbuf(1); + len = 0; + ret = ::link_ntoa_r(&sdl, &buf[0], &len); + ATF_REQUIRE_EQ(-1, ret); + ATF_REQUIRE_EQ(10, len); + // Check we really didn't write anything. + ATF_REQUIRE_EQ(garbage, buf[0]); + + // Test a buffer which would be truncated in the middle of a two-digit + // hex octet, which should not write the truncated octet at all. + sdl = make_linkaddr("ix0:1.22.3"); + resetbuf(8); + ret = ::link_ntoa_r(&sdl, &buf[0], &len); + ATF_REQUIRE_EQ(-1, ret); + ATF_REQUIRE_EQ(11, len); + ATF_REQUIRE_EQ("ix0:1."sv, bufstr()); +} + +ATF_INIT_TEST_CASES(tcs) +{ + ATF_ADD_TEST_CASE(tcs, basic); + ATF_ADD_TEST_CASE(tcs, ifname); + ATF_ADD_TEST_CASE(tcs, smallbuf); + ATF_ADD_TEST_CASE(tcs, invalid); + ATF_ADD_TEST_CASE(tcs, nonether); + ATF_ADD_TEST_CASE(tcs, overlong); + ATF_ADD_TEST_CASE(tcs, link_ntoa_r); +} diff --git a/lib/libc/tests/net/test-eui64.h b/lib/libc/tests/net/test-eui64.h index ea82a10c1487..8bb5fbb956b7 100644 --- a/lib/libc/tests/net/test-eui64.h +++ b/lib/libc/tests/net/test-eui64.h @@ -24,8 +24,6 @@ * 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. - * - * $FreeBSD$ */ #ifndef _TEST_EUI64_H #define _TEST_EUI64_H diff --git a/lib/libc/tests/nss/Makefile b/lib/libc/tests/nss/Makefile index c2f6e0940c07..790af8c6312c 100644 --- a/lib/libc/tests/nss/Makefile +++ b/lib/libc/tests/nss/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .PATH: ${.CURDIR:H}/resolv PACKAGE= tests diff --git a/lib/libc/tests/nss/Makefile.depend b/lib/libc/tests/nss/Makefile.depend index d313b17d4486..f17dae18048f 100644 --- a/lib/libc/tests/nss/Makefile.depend +++ b/lib/libc/tests/nss/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/nss/getaddrinfo_test.c b/lib/libc/tests/nss/getaddrinfo_test.c index aeac04110510..4528e272a46f 100644 --- a/lib/libc/tests/nss/getaddrinfo_test.c +++ b/lib/libc/tests/nss/getaddrinfo_test.c @@ -25,9 +25,6 @@ * */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/socket.h> #include <arpa/inet.h> diff --git a/lib/libc/tests/nss/getgr_test.c b/lib/libc/tests/nss/getgr_test.c index 63dfea085095..974632d4b7c7 100644 --- a/lib/libc/tests/nss/getgr_test.c +++ b/lib/libc/tests/nss/getgr_test.c @@ -25,9 +25,6 @@ * */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <arpa/inet.h> #include <errno.h> #include <grp.h> @@ -296,6 +293,8 @@ group_fill_test_data(struct group_test_data *td, int (*cb)(struct group *, void *)) { struct group *grp; + const int limit = 1024; + int count = 0; setgroupent(1); while ((grp = getgrent()) != NULL) { @@ -306,6 +305,8 @@ group_fill_test_data(struct group_test_data *td, } else { return (-1); } + if (++count >= limit) + break; } endgrent(); diff --git a/lib/libc/tests/nss/gethostby_test.c b/lib/libc/tests/nss/gethostby_test.c index 39dbb9d9d55a..0ed96170fc6d 100644 --- a/lib/libc/tests/nss/gethostby_test.c +++ b/lib/libc/tests/nss/gethostby_test.c @@ -25,9 +25,6 @@ * */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/socket.h> #include <arpa/inet.h> diff --git a/lib/libc/tests/nss/getproto_test.c b/lib/libc/tests/nss/getproto_test.c index 8de4ee60fdac..9b8250e47032 100644 --- a/lib/libc/tests/nss/getproto_test.c +++ b/lib/libc/tests/nss/getproto_test.c @@ -25,9 +25,6 @@ * */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <arpa/inet.h> #include <assert.h> #include <errno.h> diff --git a/lib/libc/tests/nss/getpw_test.c b/lib/libc/tests/nss/getpw_test.c index 1d9ae6c1a5db..434d86a31591 100644 --- a/lib/libc/tests/nss/getpw_test.c +++ b/lib/libc/tests/nss/getpw_test.c @@ -25,9 +25,6 @@ * */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <pwd.h> #include <stdio.h> @@ -243,6 +240,8 @@ passwd_fill_test_data(struct passwd_test_data *td, int (*cb)(struct passwd *, void *)) { struct passwd *pwd; + const int limit = 1024; + int count = 0; setpassent(1); while ((pwd = getpwent()) != NULL) { @@ -253,6 +252,8 @@ passwd_fill_test_data(struct passwd_test_data *td, } else { return (-1); } + if (++count >= limit) + break; } endpwent(); diff --git a/lib/libc/tests/nss/getrpc_test.c b/lib/libc/tests/nss/getrpc_test.c index 9be2349f2f90..6cca3cab9e86 100644 --- a/lib/libc/tests/nss/getrpc_test.c +++ b/lib/libc/tests/nss/getrpc_test.c @@ -25,9 +25,6 @@ * */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <arpa/inet.h> #include <rpc/rpc.h> #include <errno.h> diff --git a/lib/libc/tests/nss/getserv_test.c b/lib/libc/tests/nss/getserv_test.c index 56dc6611f1ba..cc66fdb2fa52 100644 --- a/lib/libc/tests/nss/getserv_test.c +++ b/lib/libc/tests/nss/getserv_test.c @@ -25,9 +25,6 @@ * */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <arpa/inet.h> #include <errno.h> #include <netdb.h> @@ -286,6 +283,8 @@ static int servent_fill_test_data(struct servent_test_data *td) { struct servent *serv; + const int limit = 1024; + int count = 0; setservent(1); while ((serv = getservent()) != NULL) { @@ -293,6 +292,8 @@ servent_fill_test_data(struct servent_test_data *td) TEST_DATA_APPEND(servent, td, serv); else return (-1); + if (++count >= limit) + break; } endservent(); diff --git a/lib/libc/tests/nss/getusershell_test.c b/lib/libc/tests/nss/getusershell_test.c index e5c4b6755263..ac23792fde8e 100644 --- a/lib/libc/tests/nss/getusershell_test.c +++ b/lib/libc/tests/nss/getusershell_test.c @@ -25,9 +25,6 @@ * */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <assert.h> #include <errno.h> #include <stdio.h> diff --git a/lib/libc/tests/nss/testutil.h b/lib/libc/tests/nss/testutil.h index 7b55e16580d1..1f7b8086ec49 100644 --- a/lib/libc/tests/nss/testutil.h +++ b/lib/libc/tests/nss/testutil.h @@ -21,8 +21,6 @@ * 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. - * - * $FreeBSD$ */ #include <sys/queue.h> diff --git a/lib/libc/tests/regex/Makefile b/lib/libc/tests/regex/Makefile index 8c1c5d06961f..65675d94c59c 100644 --- a/lib/libc/tests/regex/Makefile +++ b/lib/libc/tests/regex/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - PACKAGE= tests # local test cases diff --git a/lib/libc/tests/regex/Makefile.depend b/lib/libc/tests/regex/Makefile.depend index 1b5e74fae1b0..9df74fa6efd2 100644 --- a/lib/libc/tests/regex/Makefile.depend +++ b/lib/libc/tests/regex/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/regex/Makefile.inc b/lib/libc/tests/regex/Makefile.inc index 9e0584bd73e3..aca7ae47be18 100644 --- a/lib/libc/tests/regex/Makefile.inc +++ b/lib/libc/tests/regex/Makefile.inc @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> BINDIR?= ${TESTSDIR} diff --git a/lib/libc/tests/regex/multibyte.sh b/lib/libc/tests/regex/multibyte.sh index 3ab02118f623..18323f500a2b 100755 --- a/lib/libc/tests/regex/multibyte.sh +++ b/lib/libc/tests/regex/multibyte.sh @@ -1,5 +1,3 @@ -# $FreeBSD$ - atf_test_case bmpat bmpat_head() { @@ -46,8 +44,50 @@ icase_body() echo $c | atf_check -o "inline:$c\n" sed -ne "/$a/Ip" } +atf_test_case mbset cleanup +mbset_head() +{ + atf_set "descr" "Check multibyte sets matching" +} +mbset_body() +{ + export LC_CTYPE="C.UTF-8" + + # This involved an erroneously implemented optimization which reduces + # single-element sets to an exact match with a single codepoint. + # Match sets record small-codepoint characters in a bitmap and + # large-codepoint characters in an array; the optimization would falsely + # trigger if either the bitmap or the array was a singleton, ignoring + # the members of the other side of the set. + # + # To exercise this, we construct sets which have one member of one side + # and one or more of the other, and verify that all members can be + # found. + printf "a" > mbset; atf_check -o not-empty sed -ne '/[aà ]/p' mbset + printf "à " > mbset; atf_check -o not-empty sed -ne '/[aà ]/p' mbset + printf "a" > mbset; atf_check -o not-empty sed -ne '/[aà á]/p' mbset + printf "à " > mbset; atf_check -o not-empty sed -ne '/[aà á]/p' mbset + printf "á" > mbset; atf_check -o not-empty sed -ne '/[aà á]/p' mbset + printf "à " > mbset; atf_check -o not-empty sed -ne '/[abà ]/p' mbset + printf "a" > mbset; atf_check -o not-empty sed -ne '/[abà ]/p' mbset + printf "b" > mbset; atf_check -o not-empty sed -ne '/[abà ]/p' mbset + printf "a" > mbset; atf_check -o not-empty sed -Ene '/[aà ]/p' mbset + printf "à " > mbset; atf_check -o not-empty sed -Ene '/[aà ]/p' mbset + printf "a" > mbset; atf_check -o not-empty sed -Ene '/[aà á]/p' mbset + printf "à " > mbset; atf_check -o not-empty sed -Ene '/[aà á]/p' mbset + printf "á" > mbset; atf_check -o not-empty sed -Ene '/[aà á]/p' mbset + printf "à " > mbset; atf_check -o not-empty sed -Ene '/[abà ]/p' mbset + printf "a" > mbset; atf_check -o not-empty sed -Ene '/[abà ]/p' mbset + printf "b" > mbset; atf_check -o not-empty sed -Ene '/[abà ]/p' mbset +} +mbset_cleanup() +{ + rm -f mbset +} + atf_init_test_cases() { atf_add_test_case bmpat atf_add_test_case icase + atf_add_test_case mbset } diff --git a/lib/libc/tests/resolv/Makefile b/lib/libc/tests/resolv/Makefile index cb82da67c4f7..25c659d56685 100644 --- a/lib/libc/tests/resolv/Makefile +++ b/lib/libc/tests/resolv/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - PACKAGE= tests TESTSDIR= ${TESTSBASE}/lib/libc/resolv diff --git a/lib/libc/tests/resolv/Makefile.depend b/lib/libc/tests/resolv/Makefile.depend index c3293e1c797c..e14b2568ac65 100644 --- a/lib/libc/tests/resolv/Makefile.depend +++ b/lib/libc/tests/resolv/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/resolv/mach b/lib/libc/tests/resolv/mach index 4b47ebb73448..df57df90e0a0 100644 --- a/lib/libc/tests/resolv/mach +++ b/lib/libc/tests/resolv/mach @@ -1,4 +1,3 @@ -# $FreeBSD$ localhost anoncvs.cirr.com anoncvs.netbsd.se diff --git a/lib/libc/tests/resolv/resolv_test.c b/lib/libc/tests/resolv/resolv_test.c index 4f17469fa0cb..d7b836ed8f3e 100644 --- a/lib/libc/tests/resolv/resolv_test.c +++ b/lib/libc/tests/resolv/resolv_test.c @@ -28,7 +28,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -/* $FreeBSD$ */ #include <sys/cdefs.h> __RCSID("$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $"); diff --git a/lib/libc/tests/rpc/Makefile b/lib/libc/tests/rpc/Makefile index d7780ef4b86c..621af96eb954 100644 --- a/lib/libc/tests/rpc/Makefile +++ b/lib/libc/tests/rpc/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - SRCS.xdr_test= ${RPCSRC:.x=_xdr.c} t_xdr.c ${RPCSRC:.x=.h} \ h_testbits.h diff --git a/lib/libc/tests/rpc/Makefile.depend b/lib/libc/tests/rpc/Makefile.depend index ad95e3223964..50e2a6c3c778 100644 --- a/lib/libc/tests/rpc/Makefile.depend +++ b/lib/libc/tests/rpc/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/secure/Makefile b/lib/libc/tests/secure/Makefile new file mode 100644 index 000000000000..515f8f53a43e --- /dev/null +++ b/lib/libc/tests/secure/Makefile @@ -0,0 +1,39 @@ +.include <bsd.own.mk> + +TESTSDIR:= ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/} + +# sys/ headers +FORTIFY_TCATS+= random +FORTIFY_TCATS+= select +FORTIFY_TCATS+= socket +FORTIFY_TCATS+= uio + +# non-sys/ headers +FORTIFY_TCATS+= poll +FORTIFY_TCATS+= signal +FORTIFY_TCATS+= stdlib +FORTIFY_TCATS+= stdio +FORTIFY_TCATS+= string +FORTIFY_TCATS+= strings +FORTIFY_TCATS+= unistd +FORTIFY_TCATS+= wchar + +# Manually run after updating the test generator. +lint-generator: .PHONY + @if ! which luacheck>/dev/null; then \ + 1>&2 echo "devel/lua-luacheck is required to regenerate and lint these tests"; \ + exit 1; \ + fi + luacheck ${.CURDIR}/generate-fortify-tests.lua + +generate-tests: .PHONY lint-generator +.for tcat in ${FORTIFY_TCATS} +ATF_TESTS_C+= fortify_${tcat}_test + +.ORDER: lint-generator generate-tests-${tcat} +generate-tests: generate-tests-${tcat} +generate-tests-${tcat}: .PHONY + ${.CURDIR}/generate-fortify-tests.lua ${tcat} > ${.CURDIR}/fortify_${tcat}_test.c +.endfor + +.include <bsd.test.mk> diff --git a/lib/libc/tests/secure/fortify_poll_test.c b/lib/libc/tests/secure/fortify_poll_test.c new file mode 100644 index 000000000000..3810c16c122f --- /dev/null +++ b/lib/libc/tests/secure/fortify_poll_test.c @@ -0,0 +1,617 @@ +/* @generated by `generate-fortify-tests.lua "poll"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +ATF_TC(poll_before_end); +ATF_TC_HEAD(poll_before_end, tc) +{ +} +ATF_TC_BODY(poll_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct pollfd __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } + + poll(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(poll_end); +ATF_TC_HEAD(poll_end, tc) +{ +} +ATF_TC_BODY(poll_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct pollfd __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } + + poll(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(poll_after_end); +ATF_TC_HEAD(poll_after_end, tc) +{ +} +ATF_TC_BODY(poll_after_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct pollfd __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } + + poll(__stack.__buf, __len, 0); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(poll_heap_before_end); +ATF_TC_HEAD(poll_heap_before_end, tc) +{ +} +ATF_TC_BODY(poll_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct pollfd * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } + + poll(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(poll_heap_end); +ATF_TC_HEAD(poll_heap_end, tc) +{ +} +ATF_TC_BODY(poll_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct pollfd * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } + + poll(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(poll_heap_after_end); +ATF_TC_HEAD(poll_heap_after_end, tc) +{ +} +ATF_TC_BODY(poll_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct pollfd * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } + + poll(__stack.__buf, __len, 0); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(ppoll_before_end); +ATF_TC_HEAD(ppoll_before_end, tc) +{ +} +ATF_TC_BODY(ppoll_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct pollfd __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + struct timespec tv = { 0 }; + + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } + + ppoll(__stack.__buf, __len, &tv, NULL); +#undef BUF + +} + +ATF_TC(ppoll_end); +ATF_TC_HEAD(ppoll_end, tc) +{ +} +ATF_TC_BODY(ppoll_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct pollfd __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + struct timespec tv = { 0 }; + + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } + + ppoll(__stack.__buf, __len, &tv, NULL); +#undef BUF + +} + +ATF_TC(ppoll_after_end); +ATF_TC_HEAD(ppoll_after_end, tc) +{ +} +ATF_TC_BODY(ppoll_after_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct pollfd __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + struct timespec tv = { 0 }; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } + + ppoll(__stack.__buf, __len, &tv, NULL); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(ppoll_heap_before_end); +ATF_TC_HEAD(ppoll_heap_before_end, tc) +{ +} +ATF_TC_BODY(ppoll_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct pollfd * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + struct timespec tv = { 0 }; + + __stack.__buf = malloc(__bufsz); + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } + + ppoll(__stack.__buf, __len, &tv, NULL); +#undef BUF + +} + +ATF_TC(ppoll_heap_end); +ATF_TC_HEAD(ppoll_heap_end, tc) +{ +} +ATF_TC_BODY(ppoll_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct pollfd * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + struct timespec tv = { 0 }; + + __stack.__buf = malloc(__bufsz); + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } + + ppoll(__stack.__buf, __len, &tv, NULL); +#undef BUF + +} + +ATF_TC(ppoll_heap_after_end); +ATF_TC_HEAD(ppoll_heap_after_end, tc) +{ +} +ATF_TC_BODY(ppoll_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct pollfd * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + struct timespec tv = { 0 }; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } + + ppoll(__stack.__buf, __len, &tv, NULL); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, poll_before_end); + ATF_TP_ADD_TC(tp, poll_end); + ATF_TP_ADD_TC(tp, poll_after_end); + ATF_TP_ADD_TC(tp, poll_heap_before_end); + ATF_TP_ADD_TC(tp, poll_heap_end); + ATF_TP_ADD_TC(tp, poll_heap_after_end); + ATF_TP_ADD_TC(tp, ppoll_before_end); + ATF_TP_ADD_TC(tp, ppoll_end); + ATF_TP_ADD_TC(tp, ppoll_after_end); + ATF_TP_ADD_TC(tp, ppoll_heap_before_end); + ATF_TP_ADD_TC(tp, ppoll_heap_end); + ATF_TP_ADD_TC(tp, ppoll_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/fortify_random_test.c b/lib/libc/tests/secure/fortify_random_test.c new file mode 100644 index 000000000000..2f47c981b5ae --- /dev/null +++ b/lib/libc/tests/secure/fortify_random_test.c @@ -0,0 +1,316 @@ +/* @generated by `generate-fortify-tests.lua "random"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +ATF_TC(getrandom_before_end); +ATF_TC_HEAD(getrandom_before_end, tc) +{ +} +ATF_TC_BODY(getrandom_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + getrandom(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(getrandom_end); +ATF_TC_HEAD(getrandom_end, tc) +{ +} +ATF_TC_BODY(getrandom_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + getrandom(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(getrandom_heap_before_end); +ATF_TC_HEAD(getrandom_heap_before_end, tc) +{ +} +ATF_TC_BODY(getrandom_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getrandom(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(getrandom_heap_end); +ATF_TC_HEAD(getrandom_heap_end, tc) +{ +} +ATF_TC_BODY(getrandom_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getrandom(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(getrandom_heap_after_end); +ATF_TC_HEAD(getrandom_heap_after_end, tc) +{ +} +ATF_TC_BODY(getrandom_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getrandom(__stack.__buf, __len, 0); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, getrandom_before_end); + ATF_TP_ADD_TC(tp, getrandom_end); + ATF_TP_ADD_TC(tp, getrandom_heap_before_end); + ATF_TP_ADD_TC(tp, getrandom_heap_end); + ATF_TP_ADD_TC(tp, getrandom_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/fortify_select_test.c b/lib/libc/tests/secure/fortify_select_test.c new file mode 100644 index 000000000000..5ee97a352e2e --- /dev/null +++ b/lib/libc/tests/secure/fortify_select_test.c @@ -0,0 +1,769 @@ +/* @generated by `generate-fortify-tests.lua "select"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +ATF_TC(FD_SET_before_end); +ATF_TC_HEAD(FD_SET_before_end, tc) +{ +} +ATF_TC_BODY(FD_SET_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + fd_set __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = FD_SETSIZE - 1; + const size_t __idx __unused = __len - 1; + + FD_SET(__idx, &__stack.__buf); +#undef BUF + +} + +ATF_TC(FD_SET_end); +ATF_TC_HEAD(FD_SET_end, tc) +{ +} +ATF_TC_BODY(FD_SET_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + fd_set __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = FD_SETSIZE; + const size_t __idx __unused = __len - 1; + + FD_SET(__idx, &__stack.__buf); +#undef BUF + +} + +ATF_TC(FD_SET_after_end); +ATF_TC_HEAD(FD_SET_after_end, tc) +{ +} +ATF_TC_BODY(FD_SET_after_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + fd_set __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = FD_SETSIZE + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + FD_SET(__idx, &__stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(FD_SET_heap_before_end); +ATF_TC_HEAD(FD_SET_heap_before_end, tc) +{ +} +ATF_TC_BODY(FD_SET_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + fd_set * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = FD_SETSIZE - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + FD_SET(__idx, __stack.__buf); +#undef BUF + +} + +ATF_TC(FD_SET_heap_end); +ATF_TC_HEAD(FD_SET_heap_end, tc) +{ +} +ATF_TC_BODY(FD_SET_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + fd_set * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = FD_SETSIZE; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + FD_SET(__idx, __stack.__buf); +#undef BUF + +} + +ATF_TC(FD_SET_heap_after_end); +ATF_TC_HEAD(FD_SET_heap_after_end, tc) +{ +} +ATF_TC_BODY(FD_SET_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + fd_set * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = FD_SETSIZE + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + FD_SET(__idx, __stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(FD_CLR_before_end); +ATF_TC_HEAD(FD_CLR_before_end, tc) +{ +} +ATF_TC_BODY(FD_CLR_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + fd_set __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = FD_SETSIZE - 1; + const size_t __idx __unused = __len - 1; + + FD_CLR(__idx, &__stack.__buf); +#undef BUF + +} + +ATF_TC(FD_CLR_end); +ATF_TC_HEAD(FD_CLR_end, tc) +{ +} +ATF_TC_BODY(FD_CLR_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + fd_set __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = FD_SETSIZE; + const size_t __idx __unused = __len - 1; + + FD_CLR(__idx, &__stack.__buf); +#undef BUF + +} + +ATF_TC(FD_CLR_after_end); +ATF_TC_HEAD(FD_CLR_after_end, tc) +{ +} +ATF_TC_BODY(FD_CLR_after_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + fd_set __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = FD_SETSIZE + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + FD_CLR(__idx, &__stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(FD_CLR_heap_before_end); +ATF_TC_HEAD(FD_CLR_heap_before_end, tc) +{ +} +ATF_TC_BODY(FD_CLR_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + fd_set * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = FD_SETSIZE - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + FD_CLR(__idx, __stack.__buf); +#undef BUF + +} + +ATF_TC(FD_CLR_heap_end); +ATF_TC_HEAD(FD_CLR_heap_end, tc) +{ +} +ATF_TC_BODY(FD_CLR_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + fd_set * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = FD_SETSIZE; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + FD_CLR(__idx, __stack.__buf); +#undef BUF + +} + +ATF_TC(FD_CLR_heap_after_end); +ATF_TC_HEAD(FD_CLR_heap_after_end, tc) +{ +} +ATF_TC_BODY(FD_CLR_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + fd_set * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = FD_SETSIZE + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + FD_CLR(__idx, __stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(FD_ISSET_before_end); +ATF_TC_HEAD(FD_ISSET_before_end, tc) +{ +} +ATF_TC_BODY(FD_ISSET_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + fd_set __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = FD_SETSIZE - 1; + const size_t __idx __unused = __len - 1; + + FD_ISSET(__idx, &__stack.__buf); +#undef BUF + +} + +ATF_TC(FD_ISSET_end); +ATF_TC_HEAD(FD_ISSET_end, tc) +{ +} +ATF_TC_BODY(FD_ISSET_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + fd_set __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = FD_SETSIZE; + const size_t __idx __unused = __len - 1; + + FD_ISSET(__idx, &__stack.__buf); +#undef BUF + +} + +ATF_TC(FD_ISSET_after_end); +ATF_TC_HEAD(FD_ISSET_after_end, tc) +{ +} +ATF_TC_BODY(FD_ISSET_after_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + fd_set __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = FD_SETSIZE + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + FD_ISSET(__idx, &__stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(FD_ISSET_heap_before_end); +ATF_TC_HEAD(FD_ISSET_heap_before_end, tc) +{ +} +ATF_TC_BODY(FD_ISSET_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + fd_set * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = FD_SETSIZE - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + FD_ISSET(__idx, __stack.__buf); +#undef BUF + +} + +ATF_TC(FD_ISSET_heap_end); +ATF_TC_HEAD(FD_ISSET_heap_end, tc) +{ +} +ATF_TC_BODY(FD_ISSET_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + fd_set * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = FD_SETSIZE; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + FD_ISSET(__idx, __stack.__buf); +#undef BUF + +} + +ATF_TC(FD_ISSET_heap_after_end); +ATF_TC_HEAD(FD_ISSET_heap_after_end, tc) +{ +} +ATF_TC_BODY(FD_ISSET_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + fd_set * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = FD_SETSIZE + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + FD_ISSET(__idx, __stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, FD_SET_before_end); + ATF_TP_ADD_TC(tp, FD_SET_end); + ATF_TP_ADD_TC(tp, FD_SET_after_end); + ATF_TP_ADD_TC(tp, FD_SET_heap_before_end); + ATF_TP_ADD_TC(tp, FD_SET_heap_end); + ATF_TP_ADD_TC(tp, FD_SET_heap_after_end); + ATF_TP_ADD_TC(tp, FD_CLR_before_end); + ATF_TP_ADD_TC(tp, FD_CLR_end); + ATF_TP_ADD_TC(tp, FD_CLR_after_end); + ATF_TP_ADD_TC(tp, FD_CLR_heap_before_end); + ATF_TP_ADD_TC(tp, FD_CLR_heap_end); + ATF_TP_ADD_TC(tp, FD_CLR_heap_after_end); + ATF_TP_ADD_TC(tp, FD_ISSET_before_end); + ATF_TP_ADD_TC(tp, FD_ISSET_end); + ATF_TP_ADD_TC(tp, FD_ISSET_after_end); + ATF_TP_ADD_TC(tp, FD_ISSET_heap_before_end); + ATF_TP_ADD_TC(tp, FD_ISSET_heap_end); + ATF_TP_ADD_TC(tp, FD_ISSET_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/fortify_signal_test.c b/lib/libc/tests/secure/fortify_signal_test.c new file mode 100644 index 000000000000..03cfb9a9a13a --- /dev/null +++ b/lib/libc/tests/secure/fortify_signal_test.c @@ -0,0 +1,316 @@ +/* @generated by `generate-fortify-tests.lua "signal"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +ATF_TC(sig2str_before_end); +ATF_TC_HEAD(sig2str_before_end, tc) +{ +} +ATF_TC_BODY(sig2str_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[SIG2STR_MAX + 1]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = SIG2STR_MAX + 1; + const size_t __idx __unused = __len - 1; + + sig2str(1, __stack.__buf); +#undef BUF + +} + +ATF_TC(sig2str_end); +ATF_TC_HEAD(sig2str_end, tc) +{ +} +ATF_TC_BODY(sig2str_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[SIG2STR_MAX]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = SIG2STR_MAX; + const size_t __idx __unused = __len - 1; + + sig2str(1, __stack.__buf); +#undef BUF + +} + +ATF_TC(sig2str_heap_before_end); +ATF_TC_HEAD(sig2str_heap_before_end, tc) +{ +} +ATF_TC_BODY(sig2str_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (SIG2STR_MAX + 1); + const size_t __len = SIG2STR_MAX + 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + sig2str(1, __stack.__buf); +#undef BUF + +} + +ATF_TC(sig2str_heap_end); +ATF_TC_HEAD(sig2str_heap_end, tc) +{ +} +ATF_TC_BODY(sig2str_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (SIG2STR_MAX); + const size_t __len = SIG2STR_MAX; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + sig2str(1, __stack.__buf); +#undef BUF + +} + +ATF_TC(sig2str_heap_after_end); +ATF_TC_HEAD(sig2str_heap_after_end, tc) +{ +} +ATF_TC_BODY(sig2str_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (SIG2STR_MAX - 1); + const size_t __len = SIG2STR_MAX - 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + sig2str(1, __stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, sig2str_before_end); + ATF_TP_ADD_TC(tp, sig2str_end); + ATF_TP_ADD_TC(tp, sig2str_heap_before_end); + ATF_TP_ADD_TC(tp, sig2str_heap_end); + ATF_TP_ADD_TC(tp, sig2str_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/fortify_socket_test.c b/lib/libc/tests/secure/fortify_socket_test.c new file mode 100644 index 000000000000..3d2dc86f4e1c --- /dev/null +++ b/lib/libc/tests/secure/fortify_socket_test.c @@ -0,0 +1,1971 @@ +/* @generated by `generate-fortify-tests.lua "socket"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +ATF_TC(getpeername_before_end); +ATF_TC_HEAD(getpeername_before_end, tc) +{ +} +ATF_TC_BODY(getpeername_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct sockaddr __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = sizeof(struct sockaddr) - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + socklen_t socklen; + new_socket(sock); + socklen = __len; + + getpeername(sock[0], &__stack.__buf, &socklen); +#undef BUF + +} + +ATF_TC(getpeername_end); +ATF_TC_HEAD(getpeername_end, tc) +{ +} +ATF_TC_BODY(getpeername_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct sockaddr __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = sizeof(struct sockaddr); + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + socklen_t socklen; + new_socket(sock); + socklen = __len; + + getpeername(sock[0], &__stack.__buf, &socklen); +#undef BUF + +} + +ATF_TC(getpeername_heap_before_end); +ATF_TC_HEAD(getpeername_heap_before_end, tc) +{ +} +ATF_TC_BODY(getpeername_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct sockaddr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = sizeof(struct sockaddr) - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + socklen_t socklen; + __stack.__buf = malloc(__bufsz); + new_socket(sock); + socklen = __len; + + getpeername(sock[0], __stack.__buf, &socklen); +#undef BUF + +} + +ATF_TC(getpeername_heap_end); +ATF_TC_HEAD(getpeername_heap_end, tc) +{ +} +ATF_TC_BODY(getpeername_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct sockaddr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = sizeof(struct sockaddr); + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + socklen_t socklen; + __stack.__buf = malloc(__bufsz); + new_socket(sock); + socklen = __len; + + getpeername(sock[0], __stack.__buf, &socklen); +#undef BUF + +} + +ATF_TC(getpeername_heap_after_end); +ATF_TC_HEAD(getpeername_heap_after_end, tc) +{ +} +ATF_TC_BODY(getpeername_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct sockaddr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = sizeof(struct sockaddr) + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int sock[2] = { -1, -1 }; + socklen_t socklen; + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + new_socket(sock); + socklen = __len; + + getpeername(sock[0], __stack.__buf, &socklen); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(getsockname_before_end); +ATF_TC_HEAD(getsockname_before_end, tc) +{ +} +ATF_TC_BODY(getsockname_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct sockaddr __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = sizeof(struct sockaddr) - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + socklen_t socklen; + new_socket(sock); + socklen = __len; + + getsockname(sock[0], &__stack.__buf, &socklen); +#undef BUF + +} + +ATF_TC(getsockname_end); +ATF_TC_HEAD(getsockname_end, tc) +{ +} +ATF_TC_BODY(getsockname_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct sockaddr __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = sizeof(struct sockaddr); + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + socklen_t socklen; + new_socket(sock); + socklen = __len; + + getsockname(sock[0], &__stack.__buf, &socklen); +#undef BUF + +} + +ATF_TC(getsockname_heap_before_end); +ATF_TC_HEAD(getsockname_heap_before_end, tc) +{ +} +ATF_TC_BODY(getsockname_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct sockaddr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = sizeof(struct sockaddr) - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + socklen_t socklen; + __stack.__buf = malloc(__bufsz); + new_socket(sock); + socklen = __len; + + getsockname(sock[0], __stack.__buf, &socklen); +#undef BUF + +} + +ATF_TC(getsockname_heap_end); +ATF_TC_HEAD(getsockname_heap_end, tc) +{ +} +ATF_TC_BODY(getsockname_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct sockaddr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = sizeof(struct sockaddr); + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + socklen_t socklen; + __stack.__buf = malloc(__bufsz); + new_socket(sock); + socklen = __len; + + getsockname(sock[0], __stack.__buf, &socklen); +#undef BUF + +} + +ATF_TC(getsockname_heap_after_end); +ATF_TC_HEAD(getsockname_heap_after_end, tc) +{ +} +ATF_TC_BODY(getsockname_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct sockaddr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = sizeof(struct sockaddr) + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int sock[2] = { -1, -1 }; + socklen_t socklen; + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + new_socket(sock); + socklen = __len; + + getsockname(sock[0], __stack.__buf, &socklen); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(recv_before_end); +ATF_TC_HEAD(recv_before_end, tc) +{ +} +ATF_TC_BODY(recv_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + + new_socket(sock); + + recv(sock[0], __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(recv_end); +ATF_TC_HEAD(recv_end, tc) +{ +} +ATF_TC_BODY(recv_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + + new_socket(sock); + + recv(sock[0], __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(recv_heap_before_end); +ATF_TC_HEAD(recv_heap_before_end, tc) +{ +} +ATF_TC_BODY(recv_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + + __stack.__buf = malloc(__bufsz); + new_socket(sock); + + recv(sock[0], __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(recv_heap_end); +ATF_TC_HEAD(recv_heap_end, tc) +{ +} +ATF_TC_BODY(recv_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + + __stack.__buf = malloc(__bufsz); + new_socket(sock); + + recv(sock[0], __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(recv_heap_after_end); +ATF_TC_HEAD(recv_heap_after_end, tc) +{ +} +ATF_TC_BODY(recv_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int sock[2] = { -1, -1 }; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + new_socket(sock); + + recv(sock[0], __stack.__buf, __len, 0); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(recvfrom_before_end); +ATF_TC_HEAD(recvfrom_before_end, tc) +{ +} +ATF_TC_BODY(recvfrom_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + + new_socket(sock); + + recvfrom(sock[0], __stack.__buf, __len, 0, NULL, NULL); +#undef BUF + +} + +ATF_TC(recvfrom_end); +ATF_TC_HEAD(recvfrom_end, tc) +{ +} +ATF_TC_BODY(recvfrom_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + + new_socket(sock); + + recvfrom(sock[0], __stack.__buf, __len, 0, NULL, NULL); +#undef BUF + +} + +ATF_TC(recvfrom_heap_before_end); +ATF_TC_HEAD(recvfrom_heap_before_end, tc) +{ +} +ATF_TC_BODY(recvfrom_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + + __stack.__buf = malloc(__bufsz); + new_socket(sock); + + recvfrom(sock[0], __stack.__buf, __len, 0, NULL, NULL); +#undef BUF + +} + +ATF_TC(recvfrom_heap_end); +ATF_TC_HEAD(recvfrom_heap_end, tc) +{ +} +ATF_TC_BODY(recvfrom_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + + __stack.__buf = malloc(__bufsz); + new_socket(sock); + + recvfrom(sock[0], __stack.__buf, __len, 0, NULL, NULL); +#undef BUF + +} + +ATF_TC(recvfrom_heap_after_end); +ATF_TC_HEAD(recvfrom_heap_after_end, tc) +{ +} +ATF_TC_BODY(recvfrom_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int sock[2] = { -1, -1 }; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + new_socket(sock); + + recvfrom(sock[0], __stack.__buf, __len, 0, NULL, NULL); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(recvfrom_sockaddr_before_end); +ATF_TC_HEAD(recvfrom_sockaddr_before_end, tc) +{ +} +ATF_TC_BODY(recvfrom_sockaddr_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct sockaddr __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = sizeof(struct sockaddr) - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + char data[16]; + socklen_t socklen; + + new_socket(sock); + socklen = __len; + + recvfrom(sock[0], data, sizeof(data), 0, &__stack.__buf, &socklen); +#undef BUF + +} + +ATF_TC(recvfrom_sockaddr_end); +ATF_TC_HEAD(recvfrom_sockaddr_end, tc) +{ +} +ATF_TC_BODY(recvfrom_sockaddr_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct sockaddr __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = sizeof(struct sockaddr); + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + char data[16]; + socklen_t socklen; + + new_socket(sock); + socklen = __len; + + recvfrom(sock[0], data, sizeof(data), 0, &__stack.__buf, &socklen); +#undef BUF + +} + +ATF_TC(recvfrom_sockaddr_heap_before_end); +ATF_TC_HEAD(recvfrom_sockaddr_heap_before_end, tc) +{ +} +ATF_TC_BODY(recvfrom_sockaddr_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct sockaddr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = sizeof(struct sockaddr) - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + char data[16]; + socklen_t socklen; + + __stack.__buf = malloc(__bufsz); + new_socket(sock); + socklen = __len; + + recvfrom(sock[0], data, sizeof(data), 0, __stack.__buf, &socklen); +#undef BUF + +} + +ATF_TC(recvfrom_sockaddr_heap_end); +ATF_TC_HEAD(recvfrom_sockaddr_heap_end, tc) +{ +} +ATF_TC_BODY(recvfrom_sockaddr_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct sockaddr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = sizeof(struct sockaddr); + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + char data[16]; + socklen_t socklen; + + __stack.__buf = malloc(__bufsz); + new_socket(sock); + socklen = __len; + + recvfrom(sock[0], data, sizeof(data), 0, __stack.__buf, &socklen); +#undef BUF + +} + +ATF_TC(recvfrom_sockaddr_heap_after_end); +ATF_TC_HEAD(recvfrom_sockaddr_heap_after_end, tc) +{ +} +ATF_TC_BODY(recvfrom_sockaddr_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct sockaddr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = sizeof(struct sockaddr) + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int sock[2] = { -1, -1 }; + char data[16]; + socklen_t socklen; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + new_socket(sock); + socklen = __len; + + recvfrom(sock[0], data, sizeof(data), 0, __stack.__buf, &socklen); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(recvmsg_msg_name_before_end); +ATF_TC_HEAD(recvmsg_msg_name_before_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_name_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct sockaddr __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = sizeof(struct sockaddr) - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct msghdr msg; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = BUF; + msg.msg_namelen = __len; + + recvmsg(sock[0], &msg, 0); +#undef BUF + +} + +ATF_TC(recvmsg_msg_name_end); +ATF_TC_HEAD(recvmsg_msg_name_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_name_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct sockaddr __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = sizeof(struct sockaddr); + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct msghdr msg; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = BUF; + msg.msg_namelen = __len; + + recvmsg(sock[0], &msg, 0); +#undef BUF + +} + +ATF_TC(recvmsg_msg_name_heap_before_end); +ATF_TC_HEAD(recvmsg_msg_name_heap_before_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_name_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct sockaddr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = sizeof(struct sockaddr) - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct msghdr msg; + + __stack.__buf = malloc(__bufsz); + memset(&msg, 0, sizeof(msg)); + msg.msg_name = BUF; + msg.msg_namelen = __len; + + recvmsg(sock[0], &msg, 0); +#undef BUF + +} + +ATF_TC(recvmsg_msg_name_heap_end); +ATF_TC_HEAD(recvmsg_msg_name_heap_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_name_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct sockaddr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = sizeof(struct sockaddr); + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct msghdr msg; + + __stack.__buf = malloc(__bufsz); + memset(&msg, 0, sizeof(msg)); + msg.msg_name = BUF; + msg.msg_namelen = __len; + + recvmsg(sock[0], &msg, 0); +#undef BUF + +} + +ATF_TC(recvmsg_msg_name_heap_after_end); +ATF_TC_HEAD(recvmsg_msg_name_heap_after_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_name_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct sockaddr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1); + const size_t __len = sizeof(struct sockaddr) + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int sock[2] = { -1, -1 }; + struct msghdr msg; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(&msg, 0, sizeof(msg)); + msg.msg_name = BUF; + msg.msg_namelen = __len; + + recvmsg(sock[0], &msg, 0); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(recvmsg_msg_iov_before_end); +ATF_TC_HEAD(recvmsg_msg_iov_before_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_iov_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct msghdr msg; + struct iovec iov[2]; + + memset(&msg, 0, sizeof(msg)); + memset(&iov[0], 0, sizeof(iov)); + + /* + * We position the buffer second just so that we can confirm that the + * fortification bits are traversing the iovec correctly. + */ + iov[1].iov_base = BUF; + iov[1].iov_len = __len; + + msg.msg_iov = &iov[0]; + msg.msg_iovlen = nitems(iov); + + recvmsg(sock[0], &msg, 0); +#undef BUF + +} + +ATF_TC(recvmsg_msg_iov_end); +ATF_TC_HEAD(recvmsg_msg_iov_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_iov_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct msghdr msg; + struct iovec iov[2]; + + memset(&msg, 0, sizeof(msg)); + memset(&iov[0], 0, sizeof(iov)); + + /* + * We position the buffer second just so that we can confirm that the + * fortification bits are traversing the iovec correctly. + */ + iov[1].iov_base = BUF; + iov[1].iov_len = __len; + + msg.msg_iov = &iov[0]; + msg.msg_iovlen = nitems(iov); + + recvmsg(sock[0], &msg, 0); +#undef BUF + +} + +ATF_TC(recvmsg_msg_iov_heap_before_end); +ATF_TC_HEAD(recvmsg_msg_iov_heap_before_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_iov_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct msghdr msg; + struct iovec iov[2]; + + __stack.__buf = malloc(__bufsz); + memset(&msg, 0, sizeof(msg)); + memset(&iov[0], 0, sizeof(iov)); + + /* + * We position the buffer second just so that we can confirm that the + * fortification bits are traversing the iovec correctly. + */ + iov[1].iov_base = BUF; + iov[1].iov_len = __len; + + msg.msg_iov = &iov[0]; + msg.msg_iovlen = nitems(iov); + + recvmsg(sock[0], &msg, 0); +#undef BUF + +} + +ATF_TC(recvmsg_msg_iov_heap_end); +ATF_TC_HEAD(recvmsg_msg_iov_heap_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_iov_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct msghdr msg; + struct iovec iov[2]; + + __stack.__buf = malloc(__bufsz); + memset(&msg, 0, sizeof(msg)); + memset(&iov[0], 0, sizeof(iov)); + + /* + * We position the buffer second just so that we can confirm that the + * fortification bits are traversing the iovec correctly. + */ + iov[1].iov_base = BUF; + iov[1].iov_len = __len; + + msg.msg_iov = &iov[0]; + msg.msg_iovlen = nitems(iov); + + recvmsg(sock[0], &msg, 0); +#undef BUF + +} + +ATF_TC(recvmsg_msg_iov_heap_after_end); +ATF_TC_HEAD(recvmsg_msg_iov_heap_after_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_iov_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int sock[2] = { -1, -1 }; + struct msghdr msg; + struct iovec iov[2]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(&msg, 0, sizeof(msg)); + memset(&iov[0], 0, sizeof(iov)); + + /* + * We position the buffer second just so that we can confirm that the + * fortification bits are traversing the iovec correctly. + */ + iov[1].iov_base = BUF; + iov[1].iov_len = __len; + + msg.msg_iov = &iov[0]; + msg.msg_iovlen = nitems(iov); + + recvmsg(sock[0], &msg, 0); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(recvmsg_msg_control_before_end); +ATF_TC_HEAD(recvmsg_msg_control_before_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_control_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[CMSG_SPACE(sizeof(int))]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = CMSG_SPACE(sizeof(int)) - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct msghdr msg; + + memset(&msg, 0, sizeof(msg)); + + msg.msg_control = BUF; + msg.msg_controllen = __len; + + recvmsg(sock[0], &msg, 0); +#undef BUF + +} + +ATF_TC(recvmsg_msg_control_end); +ATF_TC_HEAD(recvmsg_msg_control_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_control_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[CMSG_SPACE(sizeof(int))]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = CMSG_SPACE(sizeof(int)); + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct msghdr msg; + + memset(&msg, 0, sizeof(msg)); + + msg.msg_control = BUF; + msg.msg_controllen = __len; + + recvmsg(sock[0], &msg, 0); +#undef BUF + +} + +ATF_TC(recvmsg_msg_control_heap_before_end); +ATF_TC_HEAD(recvmsg_msg_control_heap_before_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_control_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (CMSG_SPACE(sizeof(int))); + const size_t __len = CMSG_SPACE(sizeof(int)) - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct msghdr msg; + + __stack.__buf = malloc(__bufsz); + memset(&msg, 0, sizeof(msg)); + + msg.msg_control = BUF; + msg.msg_controllen = __len; + + recvmsg(sock[0], &msg, 0); +#undef BUF + +} + +ATF_TC(recvmsg_msg_control_heap_end); +ATF_TC_HEAD(recvmsg_msg_control_heap_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_control_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (CMSG_SPACE(sizeof(int))); + const size_t __len = CMSG_SPACE(sizeof(int)); + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct msghdr msg; + + __stack.__buf = malloc(__bufsz); + memset(&msg, 0, sizeof(msg)); + + msg.msg_control = BUF; + msg.msg_controllen = __len; + + recvmsg(sock[0], &msg, 0); +#undef BUF + +} + +ATF_TC(recvmsg_msg_control_heap_after_end); +ATF_TC_HEAD(recvmsg_msg_control_heap_after_end, tc) +{ +} +ATF_TC_BODY(recvmsg_msg_control_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (CMSG_SPACE(sizeof(int))); + const size_t __len = CMSG_SPACE(sizeof(int)) + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int sock[2] = { -1, -1 }; + struct msghdr msg; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(&msg, 0, sizeof(msg)); + + msg.msg_control = BUF; + msg.msg_controllen = __len; + + recvmsg(sock[0], &msg, 0); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(recvmmsg_msgvec_before_end); +ATF_TC_HEAD(recvmmsg_msgvec_before_end, tc) +{ +} +ATF_TC_BODY(recvmmsg_msgvec_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct mmsghdr __buf[2]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 2 - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + + recvmmsg(sock[0], __stack.__buf, __len, 0, NULL); +#undef BUF + +} + +ATF_TC(recvmmsg_msgvec_end); +ATF_TC_HEAD(recvmmsg_msgvec_end, tc) +{ +} +ATF_TC_BODY(recvmmsg_msgvec_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct mmsghdr __buf[2]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 2; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + + recvmmsg(sock[0], __stack.__buf, __len, 0, NULL); +#undef BUF + +} + +ATF_TC(recvmmsg_msgvec_after_end); +ATF_TC_HEAD(recvmmsg_msgvec_after_end, tc) +{ +} +ATF_TC_BODY(recvmmsg_msgvec_after_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct mmsghdr __buf[2]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 2 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int sock[2] = { -1, -1 }; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + recvmmsg(sock[0], __stack.__buf, __len, 0, NULL); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(recvmmsg_msgvec_heap_before_end); +ATF_TC_HEAD(recvmmsg_msgvec_heap_before_end, tc) +{ +} +ATF_TC_BODY(recvmmsg_msgvec_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct mmsghdr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (2); + const size_t __len = 2 - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + + __stack.__buf = malloc(__bufsz); + + recvmmsg(sock[0], __stack.__buf, __len, 0, NULL); +#undef BUF + +} + +ATF_TC(recvmmsg_msgvec_heap_end); +ATF_TC_HEAD(recvmmsg_msgvec_heap_end, tc) +{ +} +ATF_TC_BODY(recvmmsg_msgvec_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct mmsghdr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (2); + const size_t __len = 2; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + + __stack.__buf = malloc(__bufsz); + + recvmmsg(sock[0], __stack.__buf, __len, 0, NULL); +#undef BUF + +} + +ATF_TC(recvmmsg_msgvec_heap_after_end); +ATF_TC_HEAD(recvmmsg_msgvec_heap_after_end, tc) +{ +} +ATF_TC_BODY(recvmmsg_msgvec_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct mmsghdr * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (2); + const size_t __len = 2 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int sock[2] = { -1, -1 }; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + recvmmsg(sock[0], __stack.__buf, __len, 0, NULL); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(recvmmsg_msghdr_before_end); +ATF_TC_HEAD(recvmmsg_msghdr_before_end, tc) +{ +} +ATF_TC_BODY(recvmmsg_msghdr_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct mmsghdr msgvec[2]; + + memset(&msgvec[0], 0, sizeof(msgvec)); + + /* + * Same as above, make sure fortification isn't ignoring n > 1 elements + * of the msgvec. + */ + msgvec[1].msg_hdr.msg_control = BUF; + msgvec[1].msg_hdr.msg_controllen = __len; + + recvmmsg(sock[0], &msgvec[0], nitems(msgvec), 0, NULL); +#undef BUF + +} + +ATF_TC(recvmmsg_msghdr_end); +ATF_TC_HEAD(recvmmsg_msghdr_end, tc) +{ +} +ATF_TC_BODY(recvmmsg_msghdr_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct mmsghdr msgvec[2]; + + memset(&msgvec[0], 0, sizeof(msgvec)); + + /* + * Same as above, make sure fortification isn't ignoring n > 1 elements + * of the msgvec. + */ + msgvec[1].msg_hdr.msg_control = BUF; + msgvec[1].msg_hdr.msg_controllen = __len; + + recvmmsg(sock[0], &msgvec[0], nitems(msgvec), 0, NULL); +#undef BUF + +} + +ATF_TC(recvmmsg_msghdr_heap_before_end); +ATF_TC_HEAD(recvmmsg_msghdr_heap_before_end, tc) +{ +} +ATF_TC_BODY(recvmmsg_msghdr_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct mmsghdr msgvec[2]; + + __stack.__buf = malloc(__bufsz); + memset(&msgvec[0], 0, sizeof(msgvec)); + + /* + * Same as above, make sure fortification isn't ignoring n > 1 elements + * of the msgvec. + */ + msgvec[1].msg_hdr.msg_control = BUF; + msgvec[1].msg_hdr.msg_controllen = __len; + + recvmmsg(sock[0], &msgvec[0], nitems(msgvec), 0, NULL); +#undef BUF + +} + +ATF_TC(recvmmsg_msghdr_heap_end); +ATF_TC_HEAD(recvmmsg_msghdr_heap_end, tc) +{ +} +ATF_TC_BODY(recvmmsg_msghdr_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + int sock[2] = { -1, -1 }; + struct mmsghdr msgvec[2]; + + __stack.__buf = malloc(__bufsz); + memset(&msgvec[0], 0, sizeof(msgvec)); + + /* + * Same as above, make sure fortification isn't ignoring n > 1 elements + * of the msgvec. + */ + msgvec[1].msg_hdr.msg_control = BUF; + msgvec[1].msg_hdr.msg_controllen = __len; + + recvmmsg(sock[0], &msgvec[0], nitems(msgvec), 0, NULL); +#undef BUF + +} + +ATF_TC(recvmmsg_msghdr_heap_after_end); +ATF_TC_HEAD(recvmmsg_msghdr_heap_after_end, tc) +{ +} +ATF_TC_BODY(recvmmsg_msghdr_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int sock[2] = { -1, -1 }; + struct mmsghdr msgvec[2]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(&msgvec[0], 0, sizeof(msgvec)); + + /* + * Same as above, make sure fortification isn't ignoring n > 1 elements + * of the msgvec. + */ + msgvec[1].msg_hdr.msg_control = BUF; + msgvec[1].msg_hdr.msg_controllen = __len; + + recvmmsg(sock[0], &msgvec[0], nitems(msgvec), 0, NULL); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, getpeername_before_end); + ATF_TP_ADD_TC(tp, getpeername_end); + ATF_TP_ADD_TC(tp, getpeername_heap_before_end); + ATF_TP_ADD_TC(tp, getpeername_heap_end); + ATF_TP_ADD_TC(tp, getpeername_heap_after_end); + ATF_TP_ADD_TC(tp, getsockname_before_end); + ATF_TP_ADD_TC(tp, getsockname_end); + ATF_TP_ADD_TC(tp, getsockname_heap_before_end); + ATF_TP_ADD_TC(tp, getsockname_heap_end); + ATF_TP_ADD_TC(tp, getsockname_heap_after_end); + ATF_TP_ADD_TC(tp, recv_before_end); + ATF_TP_ADD_TC(tp, recv_end); + ATF_TP_ADD_TC(tp, recv_heap_before_end); + ATF_TP_ADD_TC(tp, recv_heap_end); + ATF_TP_ADD_TC(tp, recv_heap_after_end); + ATF_TP_ADD_TC(tp, recvfrom_before_end); + ATF_TP_ADD_TC(tp, recvfrom_end); + ATF_TP_ADD_TC(tp, recvfrom_heap_before_end); + ATF_TP_ADD_TC(tp, recvfrom_heap_end); + ATF_TP_ADD_TC(tp, recvfrom_heap_after_end); + ATF_TP_ADD_TC(tp, recvfrom_sockaddr_before_end); + ATF_TP_ADD_TC(tp, recvfrom_sockaddr_end); + ATF_TP_ADD_TC(tp, recvfrom_sockaddr_heap_before_end); + ATF_TP_ADD_TC(tp, recvfrom_sockaddr_heap_end); + ATF_TP_ADD_TC(tp, recvfrom_sockaddr_heap_after_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_name_before_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_name_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_name_heap_before_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_name_heap_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_name_heap_after_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_iov_before_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_iov_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_iov_heap_before_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_iov_heap_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_iov_heap_after_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_control_before_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_control_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_control_heap_before_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_control_heap_end); + ATF_TP_ADD_TC(tp, recvmsg_msg_control_heap_after_end); + ATF_TP_ADD_TC(tp, recvmmsg_msgvec_before_end); + ATF_TP_ADD_TC(tp, recvmmsg_msgvec_end); + ATF_TP_ADD_TC(tp, recvmmsg_msgvec_after_end); + ATF_TP_ADD_TC(tp, recvmmsg_msgvec_heap_before_end); + ATF_TP_ADD_TC(tp, recvmmsg_msgvec_heap_end); + ATF_TP_ADD_TC(tp, recvmmsg_msgvec_heap_after_end); + ATF_TP_ADD_TC(tp, recvmmsg_msghdr_before_end); + ATF_TP_ADD_TC(tp, recvmmsg_msghdr_end); + ATF_TP_ADD_TC(tp, recvmmsg_msghdr_heap_before_end); + ATF_TP_ADD_TC(tp, recvmmsg_msghdr_heap_end); + ATF_TP_ADD_TC(tp, recvmmsg_msghdr_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/fortify_stdio_test.c b/lib/libc/tests/secure/fortify_stdio_test.c new file mode 100644 index 000000000000..17842393a740 --- /dev/null +++ b/lib/libc/tests/secure/fortify_stdio_test.c @@ -0,0 +1,1559 @@ +/* @generated by `generate-fortify-tests.lua "stdio"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +ATF_TC(ctermid_before_end); +ATF_TC_HEAD(ctermid_before_end, tc) +{ +} +ATF_TC_BODY(ctermid_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[L_ctermid + 1]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = L_ctermid + 1; + const size_t __idx __unused = __len - 1; + + ctermid(__stack.__buf); +#undef BUF + +} + +ATF_TC(ctermid_end); +ATF_TC_HEAD(ctermid_end, tc) +{ +} +ATF_TC_BODY(ctermid_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[L_ctermid]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = L_ctermid; + const size_t __idx __unused = __len - 1; + + ctermid(__stack.__buf); +#undef BUF + +} + +ATF_TC(ctermid_heap_before_end); +ATF_TC_HEAD(ctermid_heap_before_end, tc) +{ +} +ATF_TC_BODY(ctermid_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_ctermid + 1); + const size_t __len = L_ctermid + 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + ctermid(__stack.__buf); +#undef BUF + +} + +ATF_TC(ctermid_heap_end); +ATF_TC_HEAD(ctermid_heap_end, tc) +{ +} +ATF_TC_BODY(ctermid_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_ctermid); + const size_t __len = L_ctermid; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + ctermid(__stack.__buf); +#undef BUF + +} + +ATF_TC(ctermid_heap_after_end); +ATF_TC_HEAD(ctermid_heap_after_end, tc) +{ +} +ATF_TC_BODY(ctermid_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_ctermid - 1); + const size_t __len = L_ctermid - 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + ctermid(__stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(ctermid_r_before_end); +ATF_TC_HEAD(ctermid_r_before_end, tc) +{ +} +ATF_TC_BODY(ctermid_r_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[L_ctermid + 1]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = L_ctermid + 1; + const size_t __idx __unused = __len - 1; + + ctermid_r(__stack.__buf); +#undef BUF + +} + +ATF_TC(ctermid_r_end); +ATF_TC_HEAD(ctermid_r_end, tc) +{ +} +ATF_TC_BODY(ctermid_r_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[L_ctermid]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = L_ctermid; + const size_t __idx __unused = __len - 1; + + ctermid_r(__stack.__buf); +#undef BUF + +} + +ATF_TC(ctermid_r_heap_before_end); +ATF_TC_HEAD(ctermid_r_heap_before_end, tc) +{ +} +ATF_TC_BODY(ctermid_r_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_ctermid + 1); + const size_t __len = L_ctermid + 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + ctermid_r(__stack.__buf); +#undef BUF + +} + +ATF_TC(ctermid_r_heap_end); +ATF_TC_HEAD(ctermid_r_heap_end, tc) +{ +} +ATF_TC_BODY(ctermid_r_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_ctermid); + const size_t __len = L_ctermid; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + ctermid_r(__stack.__buf); +#undef BUF + +} + +ATF_TC(ctermid_r_heap_after_end); +ATF_TC_HEAD(ctermid_r_heap_after_end, tc) +{ +} +ATF_TC_BODY(ctermid_r_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_ctermid - 1); + const size_t __len = L_ctermid - 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + ctermid_r(__stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(fread_before_end); +ATF_TC_HEAD(fread_before_end, tc) +{ +} +ATF_TC_BODY(fread_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + replace_stdin(); + + fread(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC(fread_end); +ATF_TC_HEAD(fread_end, tc) +{ +} +ATF_TC_BODY(fread_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + replace_stdin(); + + fread(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC(fread_heap_before_end); +ATF_TC_HEAD(fread_heap_before_end, tc) +{ +} +ATF_TC_BODY(fread_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + fread(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC(fread_heap_end); +ATF_TC_HEAD(fread_heap_end, tc) +{ +} +ATF_TC_BODY(fread_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + fread(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC(fread_heap_after_end); +ATF_TC_HEAD(fread_heap_after_end, tc) +{ +} +ATF_TC_BODY(fread_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + fread(__stack.__buf, __len, 1, stdin); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(fread_unlocked_before_end); +ATF_TC_HEAD(fread_unlocked_before_end, tc) +{ +} +ATF_TC_BODY(fread_unlocked_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + replace_stdin(); + + fread_unlocked(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC(fread_unlocked_end); +ATF_TC_HEAD(fread_unlocked_end, tc) +{ +} +ATF_TC_BODY(fread_unlocked_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + replace_stdin(); + + fread_unlocked(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC(fread_unlocked_heap_before_end); +ATF_TC_HEAD(fread_unlocked_heap_before_end, tc) +{ +} +ATF_TC_BODY(fread_unlocked_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + fread_unlocked(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC(fread_unlocked_heap_end); +ATF_TC_HEAD(fread_unlocked_heap_end, tc) +{ +} +ATF_TC_BODY(fread_unlocked_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + fread_unlocked(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC(fread_unlocked_heap_after_end); +ATF_TC_HEAD(fread_unlocked_heap_after_end, tc) +{ +} +ATF_TC_BODY(fread_unlocked_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + fread_unlocked(__stack.__buf, __len, 1, stdin); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(gets_s_before_end); +ATF_TC_HEAD(gets_s_before_end, tc) +{ +} +ATF_TC_BODY(gets_s_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + replace_stdin(); + + gets_s(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(gets_s_end); +ATF_TC_HEAD(gets_s_end, tc) +{ +} +ATF_TC_BODY(gets_s_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + replace_stdin(); + + gets_s(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(gets_s_heap_before_end); +ATF_TC_HEAD(gets_s_heap_before_end, tc) +{ +} +ATF_TC_BODY(gets_s_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + gets_s(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(gets_s_heap_end); +ATF_TC_HEAD(gets_s_heap_end, tc) +{ +} +ATF_TC_BODY(gets_s_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + gets_s(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(gets_s_heap_after_end); +ATF_TC_HEAD(gets_s_heap_after_end, tc) +{ +} +ATF_TC_BODY(gets_s_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + gets_s(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(sprintf_before_end); +ATF_TC_HEAD(sprintf_before_end, tc) +{ +} +ATF_TC_BODY(sprintf_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char srcvar[__len + 10]; + + memset(srcvar, 'A', sizeof(srcvar) - 1); + srcvar[sizeof(srcvar) - 1] = '\0'; + + sprintf(__stack.__buf, "%.*s", (int)__len - 1, srcvar); +#undef BUF + +} + +ATF_TC(sprintf_end); +ATF_TC_HEAD(sprintf_end, tc) +{ +} +ATF_TC_BODY(sprintf_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char srcvar[__len + 10]; + + memset(srcvar, 'A', sizeof(srcvar) - 1); + srcvar[sizeof(srcvar) - 1] = '\0'; + + sprintf(__stack.__buf, "%.*s", (int)__len - 1, srcvar); +#undef BUF + +} + +ATF_TC(sprintf_heap_before_end); +ATF_TC_HEAD(sprintf_heap_before_end, tc) +{ +} +ATF_TC_BODY(sprintf_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char srcvar[__len + 10]; + + __stack.__buf = malloc(__bufsz); + memset(srcvar, 'A', sizeof(srcvar) - 1); + srcvar[sizeof(srcvar) - 1] = '\0'; + + sprintf(__stack.__buf, "%.*s", (int)__len - 1, srcvar); +#undef BUF + +} + +ATF_TC(sprintf_heap_end); +ATF_TC_HEAD(sprintf_heap_end, tc) +{ +} +ATF_TC_BODY(sprintf_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char srcvar[__len + 10]; + + __stack.__buf = malloc(__bufsz); + memset(srcvar, 'A', sizeof(srcvar) - 1); + srcvar[sizeof(srcvar) - 1] = '\0'; + + sprintf(__stack.__buf, "%.*s", (int)__len - 1, srcvar); +#undef BUF + +} + +ATF_TC(sprintf_heap_after_end); +ATF_TC_HEAD(sprintf_heap_after_end, tc) +{ +} +ATF_TC_BODY(sprintf_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char srcvar[__len + 10]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(srcvar, 'A', sizeof(srcvar) - 1); + srcvar[sizeof(srcvar) - 1] = '\0'; + + sprintf(__stack.__buf, "%.*s", (int)__len - 1, srcvar); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(snprintf_before_end); +ATF_TC_HEAD(snprintf_before_end, tc) +{ +} +ATF_TC_BODY(snprintf_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char srcvar[__len + 10]; + + memset(srcvar, 'A', sizeof(srcvar) - 1); + srcvar[sizeof(srcvar) - 1] = '\0'; + + snprintf(__stack.__buf, __len, "%.*s", (int)__len - 1, srcvar); +#undef BUF + +} + +ATF_TC(snprintf_end); +ATF_TC_HEAD(snprintf_end, tc) +{ +} +ATF_TC_BODY(snprintf_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char srcvar[__len + 10]; + + memset(srcvar, 'A', sizeof(srcvar) - 1); + srcvar[sizeof(srcvar) - 1] = '\0'; + + snprintf(__stack.__buf, __len, "%.*s", (int)__len - 1, srcvar); +#undef BUF + +} + +ATF_TC(snprintf_heap_before_end); +ATF_TC_HEAD(snprintf_heap_before_end, tc) +{ +} +ATF_TC_BODY(snprintf_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char srcvar[__len + 10]; + + __stack.__buf = malloc(__bufsz); + memset(srcvar, 'A', sizeof(srcvar) - 1); + srcvar[sizeof(srcvar) - 1] = '\0'; + + snprintf(__stack.__buf, __len, "%.*s", (int)__len - 1, srcvar); +#undef BUF + +} + +ATF_TC(snprintf_heap_end); +ATF_TC_HEAD(snprintf_heap_end, tc) +{ +} +ATF_TC_BODY(snprintf_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char srcvar[__len + 10]; + + __stack.__buf = malloc(__bufsz); + memset(srcvar, 'A', sizeof(srcvar) - 1); + srcvar[sizeof(srcvar) - 1] = '\0'; + + snprintf(__stack.__buf, __len, "%.*s", (int)__len - 1, srcvar); +#undef BUF + +} + +ATF_TC(snprintf_heap_after_end); +ATF_TC_HEAD(snprintf_heap_after_end, tc) +{ +} +ATF_TC_BODY(snprintf_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char srcvar[__len + 10]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(srcvar, 'A', sizeof(srcvar) - 1); + srcvar[sizeof(srcvar) - 1] = '\0'; + + snprintf(__stack.__buf, __len, "%.*s", (int)__len - 1, srcvar); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(tmpnam_before_end); +ATF_TC_HEAD(tmpnam_before_end, tc) +{ +} +ATF_TC_BODY(tmpnam_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[L_tmpnam + 1]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = L_tmpnam + 1; + const size_t __idx __unused = __len - 1; + + tmpnam(__stack.__buf); +#undef BUF + +} + +ATF_TC(tmpnam_end); +ATF_TC_HEAD(tmpnam_end, tc) +{ +} +ATF_TC_BODY(tmpnam_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[L_tmpnam]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = L_tmpnam; + const size_t __idx __unused = __len - 1; + + tmpnam(__stack.__buf); +#undef BUF + +} + +ATF_TC(tmpnam_heap_before_end); +ATF_TC_HEAD(tmpnam_heap_before_end, tc) +{ +} +ATF_TC_BODY(tmpnam_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_tmpnam + 1); + const size_t __len = L_tmpnam + 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + tmpnam(__stack.__buf); +#undef BUF + +} + +ATF_TC(tmpnam_heap_end); +ATF_TC_HEAD(tmpnam_heap_end, tc) +{ +} +ATF_TC_BODY(tmpnam_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_tmpnam); + const size_t __len = L_tmpnam; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + tmpnam(__stack.__buf); +#undef BUF + +} + +ATF_TC(tmpnam_heap_after_end); +ATF_TC_HEAD(tmpnam_heap_after_end, tc) +{ +} +ATF_TC_BODY(tmpnam_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_tmpnam - 1); + const size_t __len = L_tmpnam - 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + tmpnam(__stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(fgets_before_end); +ATF_TC_HEAD(fgets_before_end, tc) +{ +} +ATF_TC_BODY(fgets_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + FILE *fp; + + fp = new_fp(__len); + + fgets(__stack.__buf, __len, fp); +#undef BUF + +} + +ATF_TC(fgets_end); +ATF_TC_HEAD(fgets_end, tc) +{ +} +ATF_TC_BODY(fgets_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + FILE *fp; + + fp = new_fp(__len); + + fgets(__stack.__buf, __len, fp); +#undef BUF + +} + +ATF_TC(fgets_heap_before_end); +ATF_TC_HEAD(fgets_heap_before_end, tc) +{ +} +ATF_TC_BODY(fgets_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + FILE *fp; + + __stack.__buf = malloc(__bufsz); + fp = new_fp(__len); + + fgets(__stack.__buf, __len, fp); +#undef BUF + +} + +ATF_TC(fgets_heap_end); +ATF_TC_HEAD(fgets_heap_end, tc) +{ +} +ATF_TC_BODY(fgets_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + FILE *fp; + + __stack.__buf = malloc(__bufsz); + fp = new_fp(__len); + + fgets(__stack.__buf, __len, fp); +#undef BUF + +} + +ATF_TC(fgets_heap_after_end); +ATF_TC_HEAD(fgets_heap_after_end, tc) +{ +} +ATF_TC_BODY(fgets_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + FILE *fp; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + fp = new_fp(__len); + + fgets(__stack.__buf, __len, fp); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, ctermid_before_end); + ATF_TP_ADD_TC(tp, ctermid_end); + ATF_TP_ADD_TC(tp, ctermid_heap_before_end); + ATF_TP_ADD_TC(tp, ctermid_heap_end); + ATF_TP_ADD_TC(tp, ctermid_heap_after_end); + ATF_TP_ADD_TC(tp, ctermid_r_before_end); + ATF_TP_ADD_TC(tp, ctermid_r_end); + ATF_TP_ADD_TC(tp, ctermid_r_heap_before_end); + ATF_TP_ADD_TC(tp, ctermid_r_heap_end); + ATF_TP_ADD_TC(tp, ctermid_r_heap_after_end); + ATF_TP_ADD_TC(tp, fread_before_end); + ATF_TP_ADD_TC(tp, fread_end); + ATF_TP_ADD_TC(tp, fread_heap_before_end); + ATF_TP_ADD_TC(tp, fread_heap_end); + ATF_TP_ADD_TC(tp, fread_heap_after_end); + ATF_TP_ADD_TC(tp, fread_unlocked_before_end); + ATF_TP_ADD_TC(tp, fread_unlocked_end); + ATF_TP_ADD_TC(tp, fread_unlocked_heap_before_end); + ATF_TP_ADD_TC(tp, fread_unlocked_heap_end); + ATF_TP_ADD_TC(tp, fread_unlocked_heap_after_end); + ATF_TP_ADD_TC(tp, gets_s_before_end); + ATF_TP_ADD_TC(tp, gets_s_end); + ATF_TP_ADD_TC(tp, gets_s_heap_before_end); + ATF_TP_ADD_TC(tp, gets_s_heap_end); + ATF_TP_ADD_TC(tp, gets_s_heap_after_end); + ATF_TP_ADD_TC(tp, sprintf_before_end); + ATF_TP_ADD_TC(tp, sprintf_end); + ATF_TP_ADD_TC(tp, sprintf_heap_before_end); + ATF_TP_ADD_TC(tp, sprintf_heap_end); + ATF_TP_ADD_TC(tp, sprintf_heap_after_end); + ATF_TP_ADD_TC(tp, snprintf_before_end); + ATF_TP_ADD_TC(tp, snprintf_end); + ATF_TP_ADD_TC(tp, snprintf_heap_before_end); + ATF_TP_ADD_TC(tp, snprintf_heap_end); + ATF_TP_ADD_TC(tp, snprintf_heap_after_end); + ATF_TP_ADD_TC(tp, tmpnam_before_end); + ATF_TP_ADD_TC(tp, tmpnam_end); + ATF_TP_ADD_TC(tp, tmpnam_heap_before_end); + ATF_TP_ADD_TC(tp, tmpnam_heap_end); + ATF_TP_ADD_TC(tp, tmpnam_heap_after_end); + ATF_TP_ADD_TC(tp, fgets_before_end); + ATF_TP_ADD_TC(tp, fgets_end); + ATF_TP_ADD_TC(tp, fgets_heap_before_end); + ATF_TP_ADD_TC(tp, fgets_heap_end); + ATF_TP_ADD_TC(tp, fgets_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/fortify_stdlib_test.c b/lib/libc/tests/secure/fortify_stdlib_test.c new file mode 100644 index 000000000000..d0b1af78da86 --- /dev/null +++ b/lib/libc/tests/secure/fortify_stdlib_test.c @@ -0,0 +1,610 @@ +/* @generated by `generate-fortify-tests.lua "stdlib"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +ATF_TC(arc4random_buf_before_end); +ATF_TC_HEAD(arc4random_buf_before_end, tc) +{ +} +ATF_TC_BODY(arc4random_buf_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + arc4random_buf(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(arc4random_buf_end); +ATF_TC_HEAD(arc4random_buf_end, tc) +{ +} +ATF_TC_BODY(arc4random_buf_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + arc4random_buf(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(arc4random_buf_heap_before_end); +ATF_TC_HEAD(arc4random_buf_heap_before_end, tc) +{ +} +ATF_TC_BODY(arc4random_buf_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + arc4random_buf(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(arc4random_buf_heap_end); +ATF_TC_HEAD(arc4random_buf_heap_end, tc) +{ +} +ATF_TC_BODY(arc4random_buf_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + arc4random_buf(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(arc4random_buf_heap_after_end); +ATF_TC_HEAD(arc4random_buf_heap_after_end, tc) +{ +} +ATF_TC_BODY(arc4random_buf_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + arc4random_buf(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(getenv_r_before_end); +ATF_TC_HEAD(getenv_r_before_end, tc) +{ +} +ATF_TC_BODY(getenv_r_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + getenv_r("PATH", __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getenv_r_end); +ATF_TC_HEAD(getenv_r_end, tc) +{ +} +ATF_TC_BODY(getenv_r_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + getenv_r("PATH", __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getenv_r_heap_before_end); +ATF_TC_HEAD(getenv_r_heap_before_end, tc) +{ +} +ATF_TC_BODY(getenv_r_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getenv_r("PATH", __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getenv_r_heap_end); +ATF_TC_HEAD(getenv_r_heap_end, tc) +{ +} +ATF_TC_BODY(getenv_r_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getenv_r("PATH", __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getenv_r_heap_after_end); +ATF_TC_HEAD(getenv_r_heap_after_end, tc) +{ +} +ATF_TC_BODY(getenv_r_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getenv_r("PATH", __stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(realpath_before_end); +ATF_TC_HEAD(realpath_before_end, tc) +{ +} +ATF_TC_BODY(realpath_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[PATH_MAX + 1]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = PATH_MAX + 1; + const size_t __idx __unused = __len - 1; + + realpath(".", __stack.__buf); +#undef BUF + +} + +ATF_TC(realpath_end); +ATF_TC_HEAD(realpath_end, tc) +{ +} +ATF_TC_BODY(realpath_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[PATH_MAX]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = PATH_MAX; + const size_t __idx __unused = __len - 1; + + realpath(".", __stack.__buf); +#undef BUF + +} + +ATF_TC(realpath_heap_before_end); +ATF_TC_HEAD(realpath_heap_before_end, tc) +{ +} +ATF_TC_BODY(realpath_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (PATH_MAX + 1); + const size_t __len = PATH_MAX + 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + realpath(".", __stack.__buf); +#undef BUF + +} + +ATF_TC(realpath_heap_end); +ATF_TC_HEAD(realpath_heap_end, tc) +{ +} +ATF_TC_BODY(realpath_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (PATH_MAX); + const size_t __len = PATH_MAX; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + realpath(".", __stack.__buf); +#undef BUF + +} + +ATF_TC(realpath_heap_after_end); +ATF_TC_HEAD(realpath_heap_after_end, tc) +{ +} +ATF_TC_BODY(realpath_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (PATH_MAX - 1); + const size_t __len = PATH_MAX - 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + realpath(".", __stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, arc4random_buf_before_end); + ATF_TP_ADD_TC(tp, arc4random_buf_end); + ATF_TP_ADD_TC(tp, arc4random_buf_heap_before_end); + ATF_TP_ADD_TC(tp, arc4random_buf_heap_end); + ATF_TP_ADD_TC(tp, arc4random_buf_heap_after_end); + ATF_TP_ADD_TC(tp, getenv_r_before_end); + ATF_TP_ADD_TC(tp, getenv_r_end); + ATF_TP_ADD_TC(tp, getenv_r_heap_before_end); + ATF_TP_ADD_TC(tp, getenv_r_heap_end); + ATF_TP_ADD_TC(tp, getenv_r_heap_after_end); + ATF_TP_ADD_TC(tp, realpath_before_end); + ATF_TP_ADD_TC(tp, realpath_end); + ATF_TP_ADD_TC(tp, realpath_heap_before_end); + ATF_TP_ADD_TC(tp, realpath_heap_end); + ATF_TP_ADD_TC(tp, realpath_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/fortify_string_test.c b/lib/libc/tests/secure/fortify_string_test.c new file mode 100644 index 000000000000..cfea261ff66f --- /dev/null +++ b/lib/libc/tests/secure/fortify_string_test.c @@ -0,0 +1,2271 @@ +/* @generated by `generate-fortify-tests.lua "string"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +ATF_TC(memcpy_before_end); +ATF_TC_HEAD(memcpy_before_end, tc) +{ +} +ATF_TC_BODY(memcpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + memcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(memcpy_end); +ATF_TC_HEAD(memcpy_end, tc) +{ +} +ATF_TC_BODY(memcpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + memcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(memcpy_heap_before_end); +ATF_TC_HEAD(memcpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(memcpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + memcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(memcpy_heap_end); +ATF_TC_HEAD(memcpy_heap_end, tc) +{ +} +ATF_TC_BODY(memcpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + memcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(memcpy_heap_after_end); +ATF_TC_HEAD(memcpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(memcpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len + 10]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + memcpy(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(mempcpy_before_end); +ATF_TC_HEAD(mempcpy_before_end, tc) +{ +} +ATF_TC_BODY(mempcpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + mempcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(mempcpy_end); +ATF_TC_HEAD(mempcpy_end, tc) +{ +} +ATF_TC_BODY(mempcpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + mempcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(mempcpy_heap_before_end); +ATF_TC_HEAD(mempcpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(mempcpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + mempcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(mempcpy_heap_end); +ATF_TC_HEAD(mempcpy_heap_end, tc) +{ +} +ATF_TC_BODY(mempcpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + mempcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(mempcpy_heap_after_end); +ATF_TC_HEAD(mempcpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(mempcpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len + 10]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + mempcpy(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(memmove_before_end); +ATF_TC_HEAD(memmove_before_end, tc) +{ +} +ATF_TC_BODY(memmove_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + memmove(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(memmove_end); +ATF_TC_HEAD(memmove_end, tc) +{ +} +ATF_TC_BODY(memmove_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + memmove(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(memmove_heap_before_end); +ATF_TC_HEAD(memmove_heap_before_end, tc) +{ +} +ATF_TC_BODY(memmove_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + memmove(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(memmove_heap_end); +ATF_TC_HEAD(memmove_heap_end, tc) +{ +} +ATF_TC_BODY(memmove_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + memmove(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(memmove_heap_after_end); +ATF_TC_HEAD(memmove_heap_after_end, tc) +{ +} +ATF_TC_BODY(memmove_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len + 10]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + memmove(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(memset_before_end); +ATF_TC_HEAD(memset_before_end, tc) +{ +} +ATF_TC_BODY(memset_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + memset(__stack.__buf, 0, __len); +#undef BUF + +} + +ATF_TC(memset_end); +ATF_TC_HEAD(memset_end, tc) +{ +} +ATF_TC_BODY(memset_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + memset(__stack.__buf, 0, __len); +#undef BUF + +} + +ATF_TC(memset_heap_before_end); +ATF_TC_HEAD(memset_heap_before_end, tc) +{ +} +ATF_TC_BODY(memset_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + memset(__stack.__buf, 0, __len); +#undef BUF + +} + +ATF_TC(memset_heap_end); +ATF_TC_HEAD(memset_heap_end, tc) +{ +} +ATF_TC_BODY(memset_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + memset(__stack.__buf, 0, __len); +#undef BUF + +} + +ATF_TC(memset_heap_after_end); +ATF_TC_HEAD(memset_heap_after_end, tc) +{ +} +ATF_TC_BODY(memset_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + memset(__stack.__buf, 0, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(memset_explicit_before_end); +ATF_TC_HEAD(memset_explicit_before_end, tc) +{ +} +ATF_TC_BODY(memset_explicit_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + memset_explicit(__stack.__buf, 0, __len); +#undef BUF + +} + +ATF_TC(memset_explicit_end); +ATF_TC_HEAD(memset_explicit_end, tc) +{ +} +ATF_TC_BODY(memset_explicit_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + memset_explicit(__stack.__buf, 0, __len); +#undef BUF + +} + +ATF_TC(memset_explicit_heap_before_end); +ATF_TC_HEAD(memset_explicit_heap_before_end, tc) +{ +} +ATF_TC_BODY(memset_explicit_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + memset_explicit(__stack.__buf, 0, __len); +#undef BUF + +} + +ATF_TC(memset_explicit_heap_end); +ATF_TC_HEAD(memset_explicit_heap_end, tc) +{ +} +ATF_TC_BODY(memset_explicit_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + memset_explicit(__stack.__buf, 0, __len); +#undef BUF + +} + +ATF_TC(memset_explicit_heap_after_end); +ATF_TC_HEAD(memset_explicit_heap_after_end, tc) +{ +} +ATF_TC_BODY(memset_explicit_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + memset_explicit(__stack.__buf, 0, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(stpcpy_before_end); +ATF_TC_HEAD(stpcpy_before_end, tc) +{ +} +ATF_TC_BODY(stpcpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + stpcpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(stpcpy_end); +ATF_TC_HEAD(stpcpy_end, tc) +{ +} +ATF_TC_BODY(stpcpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + stpcpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(stpcpy_heap_before_end); +ATF_TC_HEAD(stpcpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(stpcpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + stpcpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(stpcpy_heap_end); +ATF_TC_HEAD(stpcpy_heap_end, tc) +{ +} +ATF_TC_BODY(stpcpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + stpcpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(stpcpy_heap_after_end); +ATF_TC_HEAD(stpcpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(stpcpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + stpcpy(__stack.__buf, src); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(stpncpy_before_end); +ATF_TC_HEAD(stpncpy_before_end, tc) +{ +} +ATF_TC_BODY(stpncpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + stpncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(stpncpy_end); +ATF_TC_HEAD(stpncpy_end, tc) +{ +} +ATF_TC_BODY(stpncpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + stpncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(stpncpy_heap_before_end); +ATF_TC_HEAD(stpncpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(stpncpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + stpncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(stpncpy_heap_end); +ATF_TC_HEAD(stpncpy_heap_end, tc) +{ +} +ATF_TC_BODY(stpncpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + stpncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(stpncpy_heap_after_end); +ATF_TC_HEAD(stpncpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(stpncpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + stpncpy(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(strcat_before_end); +ATF_TC_HEAD(strcat_before_end, tc) +{ +} +ATF_TC_BODY(strcat_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strcat(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(strcat_end); +ATF_TC_HEAD(strcat_end, tc) +{ +} +ATF_TC_BODY(strcat_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strcat(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(strcat_heap_before_end); +ATF_TC_HEAD(strcat_heap_before_end, tc) +{ +} +ATF_TC_BODY(strcat_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strcat(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(strcat_heap_end); +ATF_TC_HEAD(strcat_heap_end, tc) +{ +} +ATF_TC_BODY(strcat_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strcat(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(strcat_heap_after_end); +ATF_TC_HEAD(strcat_heap_after_end, tc) +{ +} +ATF_TC_BODY(strcat_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strcat(__stack.__buf, src); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(strlcat_before_end); +ATF_TC_HEAD(strlcat_before_end, tc) +{ +} +ATF_TC_BODY(strlcat_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strlcat_end); +ATF_TC_HEAD(strlcat_end, tc) +{ +} +ATF_TC_BODY(strlcat_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strlcat_heap_before_end); +ATF_TC_HEAD(strlcat_heap_before_end, tc) +{ +} +ATF_TC_BODY(strlcat_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strlcat_heap_end); +ATF_TC_HEAD(strlcat_heap_end, tc) +{ +} +ATF_TC_BODY(strlcat_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strlcat_heap_after_end); +ATF_TC_HEAD(strlcat_heap_after_end, tc) +{ +} +ATF_TC_BODY(strlcat_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcat(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(strncat_before_end); +ATF_TC_HEAD(strncat_before_end, tc) +{ +} +ATF_TC_BODY(strncat_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strncat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strncat_end); +ATF_TC_HEAD(strncat_end, tc) +{ +} +ATF_TC_BODY(strncat_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strncat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strncat_heap_before_end); +ATF_TC_HEAD(strncat_heap_before_end, tc) +{ +} +ATF_TC_BODY(strncat_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strncat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strncat_heap_end); +ATF_TC_HEAD(strncat_heap_end, tc) +{ +} +ATF_TC_BODY(strncat_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strncat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strncat_heap_after_end); +ATF_TC_HEAD(strncat_heap_after_end, tc) +{ +} +ATF_TC_BODY(strncat_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strncat(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(strcpy_before_end); +ATF_TC_HEAD(strcpy_before_end, tc) +{ +} +ATF_TC_BODY(strcpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strcpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(strcpy_end); +ATF_TC_HEAD(strcpy_end, tc) +{ +} +ATF_TC_BODY(strcpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strcpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(strcpy_heap_before_end); +ATF_TC_HEAD(strcpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(strcpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strcpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(strcpy_heap_end); +ATF_TC_HEAD(strcpy_heap_end, tc) +{ +} +ATF_TC_BODY(strcpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strcpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(strcpy_heap_after_end); +ATF_TC_HEAD(strcpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(strcpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strcpy(__stack.__buf, src); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(strlcpy_before_end); +ATF_TC_HEAD(strlcpy_before_end, tc) +{ +} +ATF_TC_BODY(strlcpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strlcpy_end); +ATF_TC_HEAD(strlcpy_end, tc) +{ +} +ATF_TC_BODY(strlcpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strlcpy_heap_before_end); +ATF_TC_HEAD(strlcpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(strlcpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strlcpy_heap_end); +ATF_TC_HEAD(strlcpy_heap_end, tc) +{ +} +ATF_TC_BODY(strlcpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strlcpy_heap_after_end); +ATF_TC_HEAD(strlcpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(strlcpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcpy(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(strncpy_before_end); +ATF_TC_HEAD(strncpy_before_end, tc) +{ +} +ATF_TC_BODY(strncpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strncpy_end); +ATF_TC_HEAD(strncpy_end, tc) +{ +} +ATF_TC_BODY(strncpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strncpy_heap_before_end); +ATF_TC_HEAD(strncpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(strncpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strncpy_heap_end); +ATF_TC_HEAD(strncpy_heap_end, tc) +{ +} +ATF_TC_BODY(strncpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(strncpy_heap_after_end); +ATF_TC_HEAD(strncpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(strncpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strncpy(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, memcpy_before_end); + ATF_TP_ADD_TC(tp, memcpy_end); + ATF_TP_ADD_TC(tp, memcpy_heap_before_end); + ATF_TP_ADD_TC(tp, memcpy_heap_end); + ATF_TP_ADD_TC(tp, memcpy_heap_after_end); + ATF_TP_ADD_TC(tp, mempcpy_before_end); + ATF_TP_ADD_TC(tp, mempcpy_end); + ATF_TP_ADD_TC(tp, mempcpy_heap_before_end); + ATF_TP_ADD_TC(tp, mempcpy_heap_end); + ATF_TP_ADD_TC(tp, mempcpy_heap_after_end); + ATF_TP_ADD_TC(tp, memmove_before_end); + ATF_TP_ADD_TC(tp, memmove_end); + ATF_TP_ADD_TC(tp, memmove_heap_before_end); + ATF_TP_ADD_TC(tp, memmove_heap_end); + ATF_TP_ADD_TC(tp, memmove_heap_after_end); + ATF_TP_ADD_TC(tp, memset_before_end); + ATF_TP_ADD_TC(tp, memset_end); + ATF_TP_ADD_TC(tp, memset_heap_before_end); + ATF_TP_ADD_TC(tp, memset_heap_end); + ATF_TP_ADD_TC(tp, memset_heap_after_end); + ATF_TP_ADD_TC(tp, memset_explicit_before_end); + ATF_TP_ADD_TC(tp, memset_explicit_end); + ATF_TP_ADD_TC(tp, memset_explicit_heap_before_end); + ATF_TP_ADD_TC(tp, memset_explicit_heap_end); + ATF_TP_ADD_TC(tp, memset_explicit_heap_after_end); + ATF_TP_ADD_TC(tp, stpcpy_before_end); + ATF_TP_ADD_TC(tp, stpcpy_end); + ATF_TP_ADD_TC(tp, stpcpy_heap_before_end); + ATF_TP_ADD_TC(tp, stpcpy_heap_end); + ATF_TP_ADD_TC(tp, stpcpy_heap_after_end); + ATF_TP_ADD_TC(tp, stpncpy_before_end); + ATF_TP_ADD_TC(tp, stpncpy_end); + ATF_TP_ADD_TC(tp, stpncpy_heap_before_end); + ATF_TP_ADD_TC(tp, stpncpy_heap_end); + ATF_TP_ADD_TC(tp, stpncpy_heap_after_end); + ATF_TP_ADD_TC(tp, strcat_before_end); + ATF_TP_ADD_TC(tp, strcat_end); + ATF_TP_ADD_TC(tp, strcat_heap_before_end); + ATF_TP_ADD_TC(tp, strcat_heap_end); + ATF_TP_ADD_TC(tp, strcat_heap_after_end); + ATF_TP_ADD_TC(tp, strlcat_before_end); + ATF_TP_ADD_TC(tp, strlcat_end); + ATF_TP_ADD_TC(tp, strlcat_heap_before_end); + ATF_TP_ADD_TC(tp, strlcat_heap_end); + ATF_TP_ADD_TC(tp, strlcat_heap_after_end); + ATF_TP_ADD_TC(tp, strncat_before_end); + ATF_TP_ADD_TC(tp, strncat_end); + ATF_TP_ADD_TC(tp, strncat_heap_before_end); + ATF_TP_ADD_TC(tp, strncat_heap_end); + ATF_TP_ADD_TC(tp, strncat_heap_after_end); + ATF_TP_ADD_TC(tp, strcpy_before_end); + ATF_TP_ADD_TC(tp, strcpy_end); + ATF_TP_ADD_TC(tp, strcpy_heap_before_end); + ATF_TP_ADD_TC(tp, strcpy_heap_end); + ATF_TP_ADD_TC(tp, strcpy_heap_after_end); + ATF_TP_ADD_TC(tp, strlcpy_before_end); + ATF_TP_ADD_TC(tp, strlcpy_end); + ATF_TP_ADD_TC(tp, strlcpy_heap_before_end); + ATF_TP_ADD_TC(tp, strlcpy_heap_end); + ATF_TP_ADD_TC(tp, strlcpy_heap_after_end); + ATF_TP_ADD_TC(tp, strncpy_before_end); + ATF_TP_ADD_TC(tp, strncpy_end); + ATF_TP_ADD_TC(tp, strncpy_heap_before_end); + ATF_TP_ADD_TC(tp, strncpy_heap_end); + ATF_TP_ADD_TC(tp, strncpy_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/fortify_strings_test.c b/lib/libc/tests/secure/fortify_strings_test.c new file mode 100644 index 000000000000..9f7d37a2480e --- /dev/null +++ b/lib/libc/tests/secure/fortify_strings_test.c @@ -0,0 +1,615 @@ +/* @generated by `generate-fortify-tests.lua "strings"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +ATF_TC(bcopy_before_end); +ATF_TC_HEAD(bcopy_before_end, tc) +{ +} +ATF_TC_BODY(bcopy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + bcopy(src, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(bcopy_end); +ATF_TC_HEAD(bcopy_end, tc) +{ +} +ATF_TC_BODY(bcopy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + bcopy(src, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(bcopy_heap_before_end); +ATF_TC_HEAD(bcopy_heap_before_end, tc) +{ +} +ATF_TC_BODY(bcopy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + bcopy(src, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(bcopy_heap_end); +ATF_TC_HEAD(bcopy_heap_end, tc) +{ +} +ATF_TC_BODY(bcopy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + bcopy(src, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(bcopy_heap_after_end); +ATF_TC_HEAD(bcopy_heap_after_end, tc) +{ +} +ATF_TC_BODY(bcopy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len + 10]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + bcopy(src, __stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(bzero_before_end); +ATF_TC_HEAD(bzero_before_end, tc) +{ +} +ATF_TC_BODY(bzero_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + bzero(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(bzero_end); +ATF_TC_HEAD(bzero_end, tc) +{ +} +ATF_TC_BODY(bzero_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + bzero(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(bzero_heap_before_end); +ATF_TC_HEAD(bzero_heap_before_end, tc) +{ +} +ATF_TC_BODY(bzero_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + bzero(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(bzero_heap_end); +ATF_TC_HEAD(bzero_heap_end, tc) +{ +} +ATF_TC_BODY(bzero_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + bzero(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(bzero_heap_after_end); +ATF_TC_HEAD(bzero_heap_after_end, tc) +{ +} +ATF_TC_BODY(bzero_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + bzero(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(explicit_bzero_before_end); +ATF_TC_HEAD(explicit_bzero_before_end, tc) +{ +} +ATF_TC_BODY(explicit_bzero_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + explicit_bzero(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(explicit_bzero_end); +ATF_TC_HEAD(explicit_bzero_end, tc) +{ +} +ATF_TC_BODY(explicit_bzero_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + explicit_bzero(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(explicit_bzero_heap_before_end); +ATF_TC_HEAD(explicit_bzero_heap_before_end, tc) +{ +} +ATF_TC_BODY(explicit_bzero_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + explicit_bzero(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(explicit_bzero_heap_end); +ATF_TC_HEAD(explicit_bzero_heap_end, tc) +{ +} +ATF_TC_BODY(explicit_bzero_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + explicit_bzero(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(explicit_bzero_heap_after_end); +ATF_TC_HEAD(explicit_bzero_heap_after_end, tc) +{ +} +ATF_TC_BODY(explicit_bzero_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + explicit_bzero(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, bcopy_before_end); + ATF_TP_ADD_TC(tp, bcopy_end); + ATF_TP_ADD_TC(tp, bcopy_heap_before_end); + ATF_TP_ADD_TC(tp, bcopy_heap_end); + ATF_TP_ADD_TC(tp, bcopy_heap_after_end); + ATF_TP_ADD_TC(tp, bzero_before_end); + ATF_TP_ADD_TC(tp, bzero_end); + ATF_TP_ADD_TC(tp, bzero_heap_before_end); + ATF_TP_ADD_TC(tp, bzero_heap_end); + ATF_TP_ADD_TC(tp, bzero_heap_after_end); + ATF_TP_ADD_TC(tp, explicit_bzero_before_end); + ATF_TP_ADD_TC(tp, explicit_bzero_end); + ATF_TP_ADD_TC(tp, explicit_bzero_heap_before_end); + ATF_TP_ADD_TC(tp, explicit_bzero_heap_end); + ATF_TP_ADD_TC(tp, explicit_bzero_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/fortify_uio_test.c b/lib/libc/tests/secure/fortify_uio_test.c new file mode 100644 index 000000000000..46b46ed2f7df --- /dev/null +++ b/lib/libc/tests/secure/fortify_uio_test.c @@ -0,0 +1,917 @@ +/* @generated by `generate-fortify-tests.lua "uio"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +ATF_TC(readv_before_end); +ATF_TC_HEAD(readv_before_end, tc) +{ +} +ATF_TC_BODY(readv_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct iovec __buf[2]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 2 - 1; + const size_t __idx __unused = __len - 1; + + readv(STDIN_FILENO, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(readv_end); +ATF_TC_HEAD(readv_end, tc) +{ +} +ATF_TC_BODY(readv_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct iovec __buf[2]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 2; + const size_t __idx __unused = __len - 1; + + readv(STDIN_FILENO, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(readv_after_end); +ATF_TC_HEAD(readv_after_end, tc) +{ +} +ATF_TC_BODY(readv_after_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct iovec __buf[2]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 2 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + readv(STDIN_FILENO, __stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(readv_heap_before_end); +ATF_TC_HEAD(readv_heap_before_end, tc) +{ +} +ATF_TC_BODY(readv_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct iovec * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (2); + const size_t __len = 2 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + readv(STDIN_FILENO, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(readv_heap_end); +ATF_TC_HEAD(readv_heap_end, tc) +{ +} +ATF_TC_BODY(readv_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct iovec * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (2); + const size_t __len = 2; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + readv(STDIN_FILENO, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(readv_heap_after_end); +ATF_TC_HEAD(readv_heap_after_end, tc) +{ +} +ATF_TC_BODY(readv_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct iovec * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (2); + const size_t __len = 2 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + readv(STDIN_FILENO, __stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(readv_iov_before_end); +ATF_TC_HEAD(readv_iov_before_end, tc) +{ +} +ATF_TC_BODY(readv_iov_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + struct iovec iov[1]; + + iov[0].iov_base = __stack.__buf; + iov[0].iov_len = __len; + + replace_stdin(); + + readv(STDIN_FILENO, iov, nitems(iov)); +#undef BUF + +} + +ATF_TC(readv_iov_end); +ATF_TC_HEAD(readv_iov_end, tc) +{ +} +ATF_TC_BODY(readv_iov_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + struct iovec iov[1]; + + iov[0].iov_base = __stack.__buf; + iov[0].iov_len = __len; + + replace_stdin(); + + readv(STDIN_FILENO, iov, nitems(iov)); +#undef BUF + +} + +ATF_TC(readv_iov_heap_before_end); +ATF_TC_HEAD(readv_iov_heap_before_end, tc) +{ +} +ATF_TC_BODY(readv_iov_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + struct iovec iov[1]; + + __stack.__buf = malloc(__bufsz); + iov[0].iov_base = __stack.__buf; + iov[0].iov_len = __len; + + replace_stdin(); + + readv(STDIN_FILENO, iov, nitems(iov)); +#undef BUF + +} + +ATF_TC(readv_iov_heap_end); +ATF_TC_HEAD(readv_iov_heap_end, tc) +{ +} +ATF_TC_BODY(readv_iov_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + struct iovec iov[1]; + + __stack.__buf = malloc(__bufsz); + iov[0].iov_base = __stack.__buf; + iov[0].iov_len = __len; + + replace_stdin(); + + readv(STDIN_FILENO, iov, nitems(iov)); +#undef BUF + +} + +ATF_TC(readv_iov_heap_after_end); +ATF_TC_HEAD(readv_iov_heap_after_end, tc) +{ +} +ATF_TC_BODY(readv_iov_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + struct iovec iov[1]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + iov[0].iov_base = __stack.__buf; + iov[0].iov_len = __len; + + replace_stdin(); + + readv(STDIN_FILENO, iov, nitems(iov)); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(preadv_before_end); +ATF_TC_HEAD(preadv_before_end, tc) +{ +} +ATF_TC_BODY(preadv_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct iovec __buf[2]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 2 - 1; + const size_t __idx __unused = __len - 1; + + preadv(STDIN_FILENO, __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(preadv_end); +ATF_TC_HEAD(preadv_end, tc) +{ +} +ATF_TC_BODY(preadv_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct iovec __buf[2]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 2; + const size_t __idx __unused = __len - 1; + + preadv(STDIN_FILENO, __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(preadv_after_end); +ATF_TC_HEAD(preadv_after_end, tc) +{ +} +ATF_TC_BODY(preadv_after_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + struct iovec __buf[2]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 2 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + preadv(STDIN_FILENO, __stack.__buf, __len, 0); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(preadv_heap_before_end); +ATF_TC_HEAD(preadv_heap_before_end, tc) +{ +} +ATF_TC_BODY(preadv_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct iovec * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (2); + const size_t __len = 2 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + preadv(STDIN_FILENO, __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(preadv_heap_end); +ATF_TC_HEAD(preadv_heap_end, tc) +{ +} +ATF_TC_BODY(preadv_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct iovec * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (2); + const size_t __len = 2; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + preadv(STDIN_FILENO, __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(preadv_heap_after_end); +ATF_TC_HEAD(preadv_heap_after_end, tc) +{ +} +ATF_TC_BODY(preadv_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + struct iovec * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (2); + const size_t __len = 2 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + preadv(STDIN_FILENO, __stack.__buf, __len, 0); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(preadv_iov_before_end); +ATF_TC_HEAD(preadv_iov_before_end, tc) +{ +} +ATF_TC_BODY(preadv_iov_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + struct iovec iov[1]; + + iov[0].iov_base = __stack.__buf; + iov[0].iov_len = __len; + + replace_stdin(); + + preadv(STDIN_FILENO, iov, nitems(iov), 0); +#undef BUF + +} + +ATF_TC(preadv_iov_end); +ATF_TC_HEAD(preadv_iov_end, tc) +{ +} +ATF_TC_BODY(preadv_iov_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + struct iovec iov[1]; + + iov[0].iov_base = __stack.__buf; + iov[0].iov_len = __len; + + replace_stdin(); + + preadv(STDIN_FILENO, iov, nitems(iov), 0); +#undef BUF + +} + +ATF_TC(preadv_iov_heap_before_end); +ATF_TC_HEAD(preadv_iov_heap_before_end, tc) +{ +} +ATF_TC_BODY(preadv_iov_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + struct iovec iov[1]; + + __stack.__buf = malloc(__bufsz); + iov[0].iov_base = __stack.__buf; + iov[0].iov_len = __len; + + replace_stdin(); + + preadv(STDIN_FILENO, iov, nitems(iov), 0); +#undef BUF + +} + +ATF_TC(preadv_iov_heap_end); +ATF_TC_HEAD(preadv_iov_heap_end, tc) +{ +} +ATF_TC_BODY(preadv_iov_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + struct iovec iov[1]; + + __stack.__buf = malloc(__bufsz); + iov[0].iov_base = __stack.__buf; + iov[0].iov_len = __len; + + replace_stdin(); + + preadv(STDIN_FILENO, iov, nitems(iov), 0); +#undef BUF + +} + +ATF_TC(preadv_iov_heap_after_end); +ATF_TC_HEAD(preadv_iov_heap_after_end, tc) +{ +} +ATF_TC_BODY(preadv_iov_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + struct iovec iov[1]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + iov[0].iov_base = __stack.__buf; + iov[0].iov_len = __len; + + replace_stdin(); + + preadv(STDIN_FILENO, iov, nitems(iov), 0); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, readv_before_end); + ATF_TP_ADD_TC(tp, readv_end); + ATF_TP_ADD_TC(tp, readv_after_end); + ATF_TP_ADD_TC(tp, readv_heap_before_end); + ATF_TP_ADD_TC(tp, readv_heap_end); + ATF_TP_ADD_TC(tp, readv_heap_after_end); + ATF_TP_ADD_TC(tp, readv_iov_before_end); + ATF_TP_ADD_TC(tp, readv_iov_end); + ATF_TP_ADD_TC(tp, readv_iov_heap_before_end); + ATF_TP_ADD_TC(tp, readv_iov_heap_end); + ATF_TP_ADD_TC(tp, readv_iov_heap_after_end); + ATF_TP_ADD_TC(tp, preadv_before_end); + ATF_TP_ADD_TC(tp, preadv_end); + ATF_TP_ADD_TC(tp, preadv_after_end); + ATF_TP_ADD_TC(tp, preadv_heap_before_end); + ATF_TP_ADD_TC(tp, preadv_heap_end); + ATF_TP_ADD_TC(tp, preadv_heap_after_end); + ATF_TP_ADD_TC(tp, preadv_iov_before_end); + ATF_TP_ADD_TC(tp, preadv_iov_end); + ATF_TP_ADD_TC(tp, preadv_iov_heap_before_end); + ATF_TP_ADD_TC(tp, preadv_iov_heap_end); + ATF_TP_ADD_TC(tp, preadv_iov_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/fortify_unistd_test.c b/lib/libc/tests/secure/fortify_unistd_test.c new file mode 100644 index 000000000000..b12ef2bbb8ea --- /dev/null +++ b/lib/libc/tests/secure/fortify_unistd_test.c @@ -0,0 +1,2199 @@ +/* @generated by `generate-fortify-tests.lua "unistd"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +#define JAIL_HOSTNAME "host.example.com" +#define JAIL_DOMAINNAME "example.com" +static void +dhost_jail(void) +{ + struct iovec iov[4]; + int jid; + + iov[0].iov_base = __DECONST(char *, "host.hostname"); + iov[0].iov_len = sizeof("host.hostname"); + iov[1].iov_base = __DECONST(char *, JAIL_HOSTNAME); + iov[1].iov_len = sizeof(JAIL_HOSTNAME); + iov[2].iov_base = __DECONST(char *, "host.domainname"); + iov[2].iov_len = sizeof("host.domainname"); + iov[3].iov_base = __DECONST(char *, JAIL_DOMAINNAME); + iov[3].iov_len = sizeof(JAIL_DOMAINNAME); + + jid = jail_set(iov, nitems(iov), JAIL_CREATE | JAIL_ATTACH); + ATF_REQUIRE_MSG(jid > 0, "Jail creation failed: %s", strerror(errno)); +} + +ATF_TC(getcwd_before_end); +ATF_TC_HEAD(getcwd_before_end, tc) +{ +} +ATF_TC_BODY(getcwd_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[8]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 8 - 1; + const size_t __idx __unused = __len - 1; + + getcwd(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getcwd_end); +ATF_TC_HEAD(getcwd_end, tc) +{ +} +ATF_TC_BODY(getcwd_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[8]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 8; + const size_t __idx __unused = __len - 1; + + getcwd(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getcwd_heap_before_end); +ATF_TC_HEAD(getcwd_heap_before_end, tc) +{ +} +ATF_TC_BODY(getcwd_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (8); + const size_t __len = 8 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getcwd(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getcwd_heap_end); +ATF_TC_HEAD(getcwd_heap_end, tc) +{ +} +ATF_TC_BODY(getcwd_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (8); + const size_t __len = 8; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getcwd(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getcwd_heap_after_end); +ATF_TC_HEAD(getcwd_heap_after_end, tc) +{ +} +ATF_TC_BODY(getcwd_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (8); + const size_t __len = 8 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getcwd(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(getgrouplist_before_end); +ATF_TC_HEAD(getgrouplist_before_end, tc) +{ +} +ATF_TC_BODY(getgrouplist_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + gid_t __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + int intlen = (int)__len; + + getgrouplist("root", 0, __stack.__buf, &intlen); +#undef BUF + +} + +ATF_TC(getgrouplist_end); +ATF_TC_HEAD(getgrouplist_end, tc) +{ +} +ATF_TC_BODY(getgrouplist_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + gid_t __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + int intlen = (int)__len; + + getgrouplist("root", 0, __stack.__buf, &intlen); +#undef BUF + +} + +ATF_TC(getgrouplist_heap_before_end); +ATF_TC_HEAD(getgrouplist_heap_before_end, tc) +{ +} +ATF_TC_BODY(getgrouplist_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + gid_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + int intlen = (int)__len; + + __stack.__buf = malloc(__bufsz); + + getgrouplist("root", 0, __stack.__buf, &intlen); +#undef BUF + +} + +ATF_TC(getgrouplist_heap_end); +ATF_TC_HEAD(getgrouplist_heap_end, tc) +{ +} +ATF_TC_BODY(getgrouplist_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + gid_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + int intlen = (int)__len; + + __stack.__buf = malloc(__bufsz); + + getgrouplist("root", 0, __stack.__buf, &intlen); +#undef BUF + +} + +ATF_TC(getgrouplist_heap_after_end); +ATF_TC_HEAD(getgrouplist_heap_after_end, tc) +{ +} +ATF_TC_BODY(getgrouplist_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + gid_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int intlen = (int)__len; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getgrouplist("root", 0, __stack.__buf, &intlen); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(getgroups_before_end); +ATF_TC_HEAD(getgroups_before_end, tc) +{ +} +ATF_TC_BODY(getgroups_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + gid_t __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + + getgroups(__len, __stack.__buf); +#undef BUF + +} + +ATF_TC(getgroups_end); +ATF_TC_HEAD(getgroups_end, tc) +{ +} +ATF_TC_BODY(getgroups_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + gid_t __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + + getgroups(__len, __stack.__buf); +#undef BUF + +} + +ATF_TC(getgroups_heap_before_end); +ATF_TC_HEAD(getgroups_heap_before_end, tc) +{ +} +ATF_TC_BODY(getgroups_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + gid_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getgroups(__len, __stack.__buf); +#undef BUF + +} + +ATF_TC(getgroups_heap_end); +ATF_TC_HEAD(getgroups_heap_end, tc) +{ +} +ATF_TC_BODY(getgroups_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + gid_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getgroups(__len, __stack.__buf); +#undef BUF + +} + +ATF_TC(getgroups_heap_after_end); +ATF_TC_HEAD(getgroups_heap_after_end, tc) +{ +} +ATF_TC_BODY(getgroups_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + gid_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getgroups(__len, __stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(getloginclass_before_end); +ATF_TC_HEAD(getloginclass_before_end, tc) +{ +} +ATF_TC_BODY(getloginclass_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + getloginclass(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getloginclass_end); +ATF_TC_HEAD(getloginclass_end, tc) +{ +} +ATF_TC_BODY(getloginclass_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + getloginclass(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getloginclass_heap_before_end); +ATF_TC_HEAD(getloginclass_heap_before_end, tc) +{ +} +ATF_TC_BODY(getloginclass_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getloginclass(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getloginclass_heap_end); +ATF_TC_HEAD(getloginclass_heap_end, tc) +{ +} +ATF_TC_BODY(getloginclass_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getloginclass(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getloginclass_heap_after_end); +ATF_TC_HEAD(getloginclass_heap_after_end, tc) +{ +} +ATF_TC_BODY(getloginclass_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getloginclass(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(pread_before_end); +ATF_TC_HEAD(pread_before_end, tc) +{ +} +ATF_TC_BODY(pread_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[41]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 41 - 1; + const size_t __idx __unused = __len - 1; + int fd; + + fd = new_tmpfile(); /* Cannot fail */ + + pread(fd, __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(pread_end); +ATF_TC_HEAD(pread_end, tc) +{ +} +ATF_TC_BODY(pread_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[41]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 41; + const size_t __idx __unused = __len - 1; + int fd; + + fd = new_tmpfile(); /* Cannot fail */ + + pread(fd, __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(pread_heap_before_end); +ATF_TC_HEAD(pread_heap_before_end, tc) +{ +} +ATF_TC_BODY(pread_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); + const size_t __len = 41 - 1; + const size_t __idx __unused = __len - 1; + int fd; + + __stack.__buf = malloc(__bufsz); + fd = new_tmpfile(); /* Cannot fail */ + + pread(fd, __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(pread_heap_end); +ATF_TC_HEAD(pread_heap_end, tc) +{ +} +ATF_TC_BODY(pread_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); + const size_t __len = 41; + const size_t __idx __unused = __len - 1; + int fd; + + __stack.__buf = malloc(__bufsz); + fd = new_tmpfile(); /* Cannot fail */ + + pread(fd, __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(pread_heap_after_end); +ATF_TC_HEAD(pread_heap_after_end, tc) +{ +} +ATF_TC_BODY(pread_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); + const size_t __len = 41 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int fd; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + fd = new_tmpfile(); /* Cannot fail */ + + pread(fd, __stack.__buf, __len, 0); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(read_before_end); +ATF_TC_HEAD(read_before_end, tc) +{ +} +ATF_TC_BODY(read_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[41]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 41 - 1; + const size_t __idx __unused = __len - 1; + int fd; + + fd = new_tmpfile(); /* Cannot fail */ + + read(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(read_end); +ATF_TC_HEAD(read_end, tc) +{ +} +ATF_TC_BODY(read_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[41]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 41; + const size_t __idx __unused = __len - 1; + int fd; + + fd = new_tmpfile(); /* Cannot fail */ + + read(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(read_heap_before_end); +ATF_TC_HEAD(read_heap_before_end, tc) +{ +} +ATF_TC_BODY(read_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); + const size_t __len = 41 - 1; + const size_t __idx __unused = __len - 1; + int fd; + + __stack.__buf = malloc(__bufsz); + fd = new_tmpfile(); /* Cannot fail */ + + read(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(read_heap_end); +ATF_TC_HEAD(read_heap_end, tc) +{ +} +ATF_TC_BODY(read_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); + const size_t __len = 41; + const size_t __idx __unused = __len - 1; + int fd; + + __stack.__buf = malloc(__bufsz); + fd = new_tmpfile(); /* Cannot fail */ + + read(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(read_heap_after_end); +ATF_TC_HEAD(read_heap_after_end, tc) +{ +} +ATF_TC_BODY(read_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); + const size_t __len = 41 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int fd; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + fd = new_tmpfile(); /* Cannot fail */ + + read(fd, __stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(readlink_before_end); +ATF_TC_HEAD(readlink_before_end, tc) +{ +} +ATF_TC_BODY(readlink_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + const char *path; + + path = new_symlink(__len); /* Cannot fail */ + + readlink(path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(readlink_end); +ATF_TC_HEAD(readlink_end, tc) +{ +} +ATF_TC_BODY(readlink_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + const char *path; + + path = new_symlink(__len); /* Cannot fail */ + + readlink(path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(readlink_heap_before_end); +ATF_TC_HEAD(readlink_heap_before_end, tc) +{ +} +ATF_TC_BODY(readlink_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + const char *path; + + __stack.__buf = malloc(__bufsz); + path = new_symlink(__len); /* Cannot fail */ + + readlink(path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(readlink_heap_end); +ATF_TC_HEAD(readlink_heap_end, tc) +{ +} +ATF_TC_BODY(readlink_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + const char *path; + + __stack.__buf = malloc(__bufsz); + path = new_symlink(__len); /* Cannot fail */ + + readlink(path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(readlink_heap_after_end); +ATF_TC_HEAD(readlink_heap_after_end, tc) +{ +} +ATF_TC_BODY(readlink_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + const char *path; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + path = new_symlink(__len); /* Cannot fail */ + + readlink(path, __stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(readlinkat_before_end); +ATF_TC_HEAD(readlinkat_before_end, tc) +{ +} +ATF_TC_BODY(readlinkat_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + const char *path; + + path = new_symlink(__len); /* Cannot fail */ + + readlinkat(AT_FDCWD, path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(readlinkat_end); +ATF_TC_HEAD(readlinkat_end, tc) +{ +} +ATF_TC_BODY(readlinkat_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + const char *path; + + path = new_symlink(__len); /* Cannot fail */ + + readlinkat(AT_FDCWD, path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(readlinkat_heap_before_end); +ATF_TC_HEAD(readlinkat_heap_before_end, tc) +{ +} +ATF_TC_BODY(readlinkat_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + const char *path; + + __stack.__buf = malloc(__bufsz); + path = new_symlink(__len); /* Cannot fail */ + + readlinkat(AT_FDCWD, path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(readlinkat_heap_end); +ATF_TC_HEAD(readlinkat_heap_end, tc) +{ +} +ATF_TC_BODY(readlinkat_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + const char *path; + + __stack.__buf = malloc(__bufsz); + path = new_symlink(__len); /* Cannot fail */ + + readlinkat(AT_FDCWD, path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(readlinkat_heap_after_end); +ATF_TC_HEAD(readlinkat_heap_after_end, tc) +{ +} +ATF_TC_BODY(readlinkat_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + const char *path; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + path = new_symlink(__len); /* Cannot fail */ + + readlinkat(AT_FDCWD, path, __stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(getdomainname_before_end); +ATF_TC_HEAD(getdomainname_before_end, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(getdomainname_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[12]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 12 - 1; + const size_t __idx __unused = __len - 1; + + dhost_jail(); + getdomainname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getdomainname_end); +ATF_TC_HEAD(getdomainname_end, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(getdomainname_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[12]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 12; + const size_t __idx __unused = __len - 1; + + dhost_jail(); + getdomainname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getdomainname_heap_before_end); +ATF_TC_HEAD(getdomainname_heap_before_end, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(getdomainname_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (12); + const size_t __len = 12 - 1; + const size_t __idx __unused = __len - 1; + + dhost_jail(); + __stack.__buf = malloc(__bufsz); + + getdomainname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getdomainname_heap_end); +ATF_TC_HEAD(getdomainname_heap_end, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(getdomainname_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (12); + const size_t __len = 12; + const size_t __idx __unused = __len - 1; + + dhost_jail(); + __stack.__buf = malloc(__bufsz); + + getdomainname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getdomainname_heap_after_end); +ATF_TC_HEAD(getdomainname_heap_after_end, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(getdomainname_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (12); + const size_t __len = 12 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + dhost_jail(); + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getdomainname(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(getentropy_before_end); +ATF_TC_HEAD(getentropy_before_end, tc) +{ +} +ATF_TC_BODY(getentropy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + getentropy(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getentropy_end); +ATF_TC_HEAD(getentropy_end, tc) +{ +} +ATF_TC_BODY(getentropy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + getentropy(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getentropy_heap_before_end); +ATF_TC_HEAD(getentropy_heap_before_end, tc) +{ +} +ATF_TC_BODY(getentropy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getentropy(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getentropy_heap_end); +ATF_TC_HEAD(getentropy_heap_end, tc) +{ +} +ATF_TC_BODY(getentropy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getentropy(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getentropy_heap_after_end); +ATF_TC_HEAD(getentropy_heap_after_end, tc) +{ +} +ATF_TC_BODY(getentropy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getentropy(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(gethostname_before_end); +ATF_TC_HEAD(gethostname_before_end, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(gethostname_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[17]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 17 - 1; + const size_t __idx __unused = __len - 1; + + dhost_jail(); + gethostname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(gethostname_end); +ATF_TC_HEAD(gethostname_end, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(gethostname_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[17]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 17; + const size_t __idx __unused = __len - 1; + + dhost_jail(); + gethostname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(gethostname_heap_before_end); +ATF_TC_HEAD(gethostname_heap_before_end, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(gethostname_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (17); + const size_t __len = 17 - 1; + const size_t __idx __unused = __len - 1; + + dhost_jail(); + __stack.__buf = malloc(__bufsz); + + gethostname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(gethostname_heap_end); +ATF_TC_HEAD(gethostname_heap_end, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(gethostname_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (17); + const size_t __len = 17; + const size_t __idx __unused = __len - 1; + + dhost_jail(); + __stack.__buf = malloc(__bufsz); + + gethostname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(gethostname_heap_after_end); +ATF_TC_HEAD(gethostname_heap_after_end, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(gethostname_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (17); + const size_t __len = 17 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + dhost_jail(); + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + gethostname(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(getlogin_r_before_end); +ATF_TC_HEAD(getlogin_r_before_end, tc) +{ +} +ATF_TC_BODY(getlogin_r_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[MAXLOGNAME + 1]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = MAXLOGNAME + 1 - 1; + const size_t __idx __unused = __len - 1; + + getlogin_r(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getlogin_r_end); +ATF_TC_HEAD(getlogin_r_end, tc) +{ +} +ATF_TC_BODY(getlogin_r_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[MAXLOGNAME + 1]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = MAXLOGNAME + 1; + const size_t __idx __unused = __len - 1; + + getlogin_r(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getlogin_r_heap_before_end); +ATF_TC_HEAD(getlogin_r_heap_before_end, tc) +{ +} +ATF_TC_BODY(getlogin_r_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (MAXLOGNAME + 1); + const size_t __len = MAXLOGNAME + 1 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getlogin_r(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getlogin_r_heap_end); +ATF_TC_HEAD(getlogin_r_heap_end, tc) +{ +} +ATF_TC_BODY(getlogin_r_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (MAXLOGNAME + 1); + const size_t __len = MAXLOGNAME + 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getlogin_r(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC(getlogin_r_heap_after_end); +ATF_TC_HEAD(getlogin_r_heap_after_end, tc) +{ +} +ATF_TC_BODY(getlogin_r_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (MAXLOGNAME + 1); + const size_t __len = MAXLOGNAME + 1 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getlogin_r(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(ttyname_r_before_end); +ATF_TC_HEAD(ttyname_r_before_end, tc) +{ +} +ATF_TC_BODY(ttyname_r_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + int fd; + + fd = STDIN_FILENO; + if (!isatty(fd)) + atf_tc_skip("stdin is not an fd"); + + ttyname_r(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(ttyname_r_end); +ATF_TC_HEAD(ttyname_r_end, tc) +{ +} +ATF_TC_BODY(ttyname_r_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + int fd; + + fd = STDIN_FILENO; + if (!isatty(fd)) + atf_tc_skip("stdin is not an fd"); + + ttyname_r(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(ttyname_r_heap_before_end); +ATF_TC_HEAD(ttyname_r_heap_before_end, tc) +{ +} +ATF_TC_BODY(ttyname_r_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + int fd; + + fd = STDIN_FILENO; + if (!isatty(fd)) + atf_tc_skip("stdin is not an fd"); + + __stack.__buf = malloc(__bufsz); + + ttyname_r(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(ttyname_r_heap_end); +ATF_TC_HEAD(ttyname_r_heap_end, tc) +{ +} +ATF_TC_BODY(ttyname_r_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + int fd; + + fd = STDIN_FILENO; + if (!isatty(fd)) + atf_tc_skip("stdin is not an fd"); + + __stack.__buf = malloc(__bufsz); + + ttyname_r(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC(ttyname_r_heap_after_end); +ATF_TC_HEAD(ttyname_r_heap_after_end, tc) +{ +} +ATF_TC_BODY(ttyname_r_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int fd; + + fd = STDIN_FILENO; + if (!isatty(fd)) + atf_tc_skip("stdin is not an fd"); + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + ttyname_r(fd, __stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, getcwd_before_end); + ATF_TP_ADD_TC(tp, getcwd_end); + ATF_TP_ADD_TC(tp, getcwd_heap_before_end); + ATF_TP_ADD_TC(tp, getcwd_heap_end); + ATF_TP_ADD_TC(tp, getcwd_heap_after_end); + ATF_TP_ADD_TC(tp, getgrouplist_before_end); + ATF_TP_ADD_TC(tp, getgrouplist_end); + ATF_TP_ADD_TC(tp, getgrouplist_heap_before_end); + ATF_TP_ADD_TC(tp, getgrouplist_heap_end); + ATF_TP_ADD_TC(tp, getgrouplist_heap_after_end); + ATF_TP_ADD_TC(tp, getgroups_before_end); + ATF_TP_ADD_TC(tp, getgroups_end); + ATF_TP_ADD_TC(tp, getgroups_heap_before_end); + ATF_TP_ADD_TC(tp, getgroups_heap_end); + ATF_TP_ADD_TC(tp, getgroups_heap_after_end); + ATF_TP_ADD_TC(tp, getloginclass_before_end); + ATF_TP_ADD_TC(tp, getloginclass_end); + ATF_TP_ADD_TC(tp, getloginclass_heap_before_end); + ATF_TP_ADD_TC(tp, getloginclass_heap_end); + ATF_TP_ADD_TC(tp, getloginclass_heap_after_end); + ATF_TP_ADD_TC(tp, pread_before_end); + ATF_TP_ADD_TC(tp, pread_end); + ATF_TP_ADD_TC(tp, pread_heap_before_end); + ATF_TP_ADD_TC(tp, pread_heap_end); + ATF_TP_ADD_TC(tp, pread_heap_after_end); + ATF_TP_ADD_TC(tp, read_before_end); + ATF_TP_ADD_TC(tp, read_end); + ATF_TP_ADD_TC(tp, read_heap_before_end); + ATF_TP_ADD_TC(tp, read_heap_end); + ATF_TP_ADD_TC(tp, read_heap_after_end); + ATF_TP_ADD_TC(tp, readlink_before_end); + ATF_TP_ADD_TC(tp, readlink_end); + ATF_TP_ADD_TC(tp, readlink_heap_before_end); + ATF_TP_ADD_TC(tp, readlink_heap_end); + ATF_TP_ADD_TC(tp, readlink_heap_after_end); + ATF_TP_ADD_TC(tp, readlinkat_before_end); + ATF_TP_ADD_TC(tp, readlinkat_end); + ATF_TP_ADD_TC(tp, readlinkat_heap_before_end); + ATF_TP_ADD_TC(tp, readlinkat_heap_end); + ATF_TP_ADD_TC(tp, readlinkat_heap_after_end); + ATF_TP_ADD_TC(tp, getdomainname_before_end); + ATF_TP_ADD_TC(tp, getdomainname_end); + ATF_TP_ADD_TC(tp, getdomainname_heap_before_end); + ATF_TP_ADD_TC(tp, getdomainname_heap_end); + ATF_TP_ADD_TC(tp, getdomainname_heap_after_end); + ATF_TP_ADD_TC(tp, getentropy_before_end); + ATF_TP_ADD_TC(tp, getentropy_end); + ATF_TP_ADD_TC(tp, getentropy_heap_before_end); + ATF_TP_ADD_TC(tp, getentropy_heap_end); + ATF_TP_ADD_TC(tp, getentropy_heap_after_end); + ATF_TP_ADD_TC(tp, gethostname_before_end); + ATF_TP_ADD_TC(tp, gethostname_end); + ATF_TP_ADD_TC(tp, gethostname_heap_before_end); + ATF_TP_ADD_TC(tp, gethostname_heap_end); + ATF_TP_ADD_TC(tp, gethostname_heap_after_end); + ATF_TP_ADD_TC(tp, getlogin_r_before_end); + ATF_TP_ADD_TC(tp, getlogin_r_end); + ATF_TP_ADD_TC(tp, getlogin_r_heap_before_end); + ATF_TP_ADD_TC(tp, getlogin_r_heap_end); + ATF_TP_ADD_TC(tp, getlogin_r_heap_after_end); + ATF_TP_ADD_TC(tp, ttyname_r_before_end); + ATF_TP_ADD_TC(tp, ttyname_r_end); + ATF_TP_ADD_TC(tp, ttyname_r_heap_before_end); + ATF_TP_ADD_TC(tp, ttyname_r_heap_end); + ATF_TP_ADD_TC(tp, ttyname_r_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/fortify_wchar_test.c b/lib/libc/tests/secure/fortify_wchar_test.c new file mode 100644 index 000000000000..43c7997bc6a3 --- /dev/null +++ b/lib/libc/tests/secure/fortify_wchar_test.c @@ -0,0 +1,2124 @@ +/* @generated by `generate-fortify-tests.lua "wchar"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +ATF_TC(wmemcpy_before_end); +ATF_TC_HEAD(wmemcpy_before_end, tc) +{ +} +ATF_TC_BODY(wmemcpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len + 10]; + + wmemcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wmemcpy_end); +ATF_TC_HEAD(wmemcpy_end, tc) +{ +} +ATF_TC_BODY(wmemcpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len + 10]; + + wmemcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wmemcpy_heap_before_end); +ATF_TC_HEAD(wmemcpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(wmemcpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + wmemcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wmemcpy_heap_end); +ATF_TC_HEAD(wmemcpy_heap_end, tc) +{ +} +ATF_TC_BODY(wmemcpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + wmemcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wmemcpy_heap_after_end); +ATF_TC_HEAD(wmemcpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(wmemcpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + wchar_t src[__len + 10]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + wmemcpy(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(wmempcpy_before_end); +ATF_TC_HEAD(wmempcpy_before_end, tc) +{ +} +ATF_TC_BODY(wmempcpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len + 10]; + + wmempcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wmempcpy_end); +ATF_TC_HEAD(wmempcpy_end, tc) +{ +} +ATF_TC_BODY(wmempcpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len + 10]; + + wmempcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wmempcpy_heap_before_end); +ATF_TC_HEAD(wmempcpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(wmempcpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + wmempcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wmempcpy_heap_end); +ATF_TC_HEAD(wmempcpy_heap_end, tc) +{ +} +ATF_TC_BODY(wmempcpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + wmempcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wmempcpy_heap_after_end); +ATF_TC_HEAD(wmempcpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(wmempcpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + wchar_t src[__len + 10]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + wmempcpy(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(wmemmove_before_end); +ATF_TC_HEAD(wmemmove_before_end, tc) +{ +} +ATF_TC_BODY(wmemmove_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len + 10]; + + wmemmove(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wmemmove_end); +ATF_TC_HEAD(wmemmove_end, tc) +{ +} +ATF_TC_BODY(wmemmove_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len + 10]; + + wmemmove(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wmemmove_heap_before_end); +ATF_TC_HEAD(wmemmove_heap_before_end, tc) +{ +} +ATF_TC_BODY(wmemmove_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + wmemmove(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wmemmove_heap_end); +ATF_TC_HEAD(wmemmove_heap_end, tc) +{ +} +ATF_TC_BODY(wmemmove_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + wmemmove(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wmemmove_heap_after_end); +ATF_TC_HEAD(wmemmove_heap_after_end, tc) +{ +} +ATF_TC_BODY(wmemmove_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + wchar_t src[__len + 10]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + wmemmove(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(wmemset_before_end); +ATF_TC_HEAD(wmemset_before_end, tc) +{ +} +ATF_TC_BODY(wmemset_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + wmemset(__stack.__buf, L'0', __len); +#undef BUF + +} + +ATF_TC(wmemset_end); +ATF_TC_HEAD(wmemset_end, tc) +{ +} +ATF_TC_BODY(wmemset_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + wmemset(__stack.__buf, L'0', __len); +#undef BUF + +} + +ATF_TC(wmemset_heap_before_end); +ATF_TC_HEAD(wmemset_heap_before_end, tc) +{ +} +ATF_TC_BODY(wmemset_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + wmemset(__stack.__buf, L'0', __len); +#undef BUF + +} + +ATF_TC(wmemset_heap_end); +ATF_TC_HEAD(wmemset_heap_end, tc) +{ +} +ATF_TC_BODY(wmemset_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + wmemset(__stack.__buf, L'0', __len); +#undef BUF + +} + +ATF_TC(wmemset_heap_after_end); +ATF_TC_HEAD(wmemset_heap_after_end, tc) +{ +} +ATF_TC_BODY(wmemset_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + wmemset(__stack.__buf, L'0', __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(wcpcpy_before_end); +ATF_TC_HEAD(wcpcpy_before_end, tc) +{ +} +ATF_TC_BODY(wcpcpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcpcpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(wcpcpy_end); +ATF_TC_HEAD(wcpcpy_end, tc) +{ +} +ATF_TC_BODY(wcpcpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcpcpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(wcpcpy_heap_before_end); +ATF_TC_HEAD(wcpcpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(wcpcpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcpcpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(wcpcpy_heap_end); +ATF_TC_HEAD(wcpcpy_heap_end, tc) +{ +} +ATF_TC_BODY(wcpcpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcpcpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(wcpcpy_heap_after_end); +ATF_TC_HEAD(wcpcpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(wcpcpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + wchar_t src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcpcpy(__stack.__buf, src); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(wcpncpy_before_end); +ATF_TC_HEAD(wcpncpy_before_end, tc) +{ +} +ATF_TC_BODY(wcpncpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcpncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcpncpy_end); +ATF_TC_HEAD(wcpncpy_end, tc) +{ +} +ATF_TC_BODY(wcpncpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcpncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcpncpy_heap_before_end); +ATF_TC_HEAD(wcpncpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(wcpncpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcpncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcpncpy_heap_end); +ATF_TC_HEAD(wcpncpy_heap_end, tc) +{ +} +ATF_TC_BODY(wcpncpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcpncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcpncpy_heap_after_end); +ATF_TC_HEAD(wcpncpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(wcpncpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + wchar_t src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcpncpy(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(wcscat_before_end); +ATF_TC_HEAD(wcscat_before_end, tc) +{ +} +ATF_TC_BODY(wcscat_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcscat(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(wcscat_end); +ATF_TC_HEAD(wcscat_end, tc) +{ +} +ATF_TC_BODY(wcscat_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcscat(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(wcscat_heap_before_end); +ATF_TC_HEAD(wcscat_heap_before_end, tc) +{ +} +ATF_TC_BODY(wcscat_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcscat(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(wcscat_heap_end); +ATF_TC_HEAD(wcscat_heap_end, tc) +{ +} +ATF_TC_BODY(wcscat_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcscat(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(wcscat_heap_after_end); +ATF_TC_HEAD(wcscat_heap_after_end, tc) +{ +} +ATF_TC_BODY(wcscat_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + wchar_t src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcscat(__stack.__buf, src); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(wcslcat_before_end); +ATF_TC_HEAD(wcslcat_before_end, tc) +{ +} +ATF_TC_BODY(wcslcat_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcslcat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcslcat_end); +ATF_TC_HEAD(wcslcat_end, tc) +{ +} +ATF_TC_BODY(wcslcat_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcslcat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcslcat_heap_before_end); +ATF_TC_HEAD(wcslcat_heap_before_end, tc) +{ +} +ATF_TC_BODY(wcslcat_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcslcat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcslcat_heap_end); +ATF_TC_HEAD(wcslcat_heap_end, tc) +{ +} +ATF_TC_BODY(wcslcat_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcslcat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcslcat_heap_after_end); +ATF_TC_HEAD(wcslcat_heap_after_end, tc) +{ +} +ATF_TC_BODY(wcslcat_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + wchar_t src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcslcat(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(wcsncat_before_end); +ATF_TC_HEAD(wcsncat_before_end, tc) +{ +} +ATF_TC_BODY(wcsncat_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcsncat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcsncat_end); +ATF_TC_HEAD(wcsncat_end, tc) +{ +} +ATF_TC_BODY(wcsncat_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcsncat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcsncat_heap_before_end); +ATF_TC_HEAD(wcsncat_heap_before_end, tc) +{ +} +ATF_TC_BODY(wcsncat_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcsncat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcsncat_heap_end); +ATF_TC_HEAD(wcsncat_heap_end, tc) +{ +} +ATF_TC_BODY(wcsncat_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcsncat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcsncat_heap_after_end); +ATF_TC_HEAD(wcsncat_heap_after_end, tc) +{ +} +ATF_TC_BODY(wcsncat_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + wchar_t src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcsncat(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(wcscpy_before_end); +ATF_TC_HEAD(wcscpy_before_end, tc) +{ +} +ATF_TC_BODY(wcscpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcscpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(wcscpy_end); +ATF_TC_HEAD(wcscpy_end, tc) +{ +} +ATF_TC_BODY(wcscpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcscpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(wcscpy_heap_before_end); +ATF_TC_HEAD(wcscpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(wcscpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcscpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(wcscpy_heap_end); +ATF_TC_HEAD(wcscpy_heap_end, tc) +{ +} +ATF_TC_BODY(wcscpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcscpy(__stack.__buf, src); +#undef BUF + +} + +ATF_TC(wcscpy_heap_after_end); +ATF_TC_HEAD(wcscpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(wcscpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + wchar_t src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcscpy(__stack.__buf, src); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(wcslcpy_before_end); +ATF_TC_HEAD(wcslcpy_before_end, tc) +{ +} +ATF_TC_BODY(wcslcpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcslcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcslcpy_end); +ATF_TC_HEAD(wcslcpy_end, tc) +{ +} +ATF_TC_BODY(wcslcpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcslcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcslcpy_heap_before_end); +ATF_TC_HEAD(wcslcpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(wcslcpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcslcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcslcpy_heap_end); +ATF_TC_HEAD(wcslcpy_heap_end, tc) +{ +} +ATF_TC_BODY(wcslcpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcslcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcslcpy_heap_after_end); +ATF_TC_HEAD(wcslcpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(wcslcpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + wchar_t src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcslcpy(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC(wcsncpy_before_end); +ATF_TC_HEAD(wcsncpy_before_end, tc) +{ +} +ATF_TC_BODY(wcsncpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcsncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcsncpy_end); +ATF_TC_HEAD(wcsncpy_end, tc) +{ +} +ATF_TC_BODY(wcsncpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + wchar_t __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcsncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcsncpy_heap_before_end); +ATF_TC_HEAD(wcsncpy_heap_before_end, tc) +{ +} +ATF_TC_BODY(wcsncpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcsncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcsncpy_heap_end); +ATF_TC_HEAD(wcsncpy_heap_end, tc) +{ +} +ATF_TC_BODY(wcsncpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + wchar_t src[__len]; + + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcsncpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC(wcsncpy_heap_after_end); +ATF_TC_HEAD(wcsncpy_heap_after_end, tc) +{ +} +ATF_TC_BODY(wcsncpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + wchar_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + wchar_t src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + wcsncpy(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, wmemcpy_before_end); + ATF_TP_ADD_TC(tp, wmemcpy_end); + ATF_TP_ADD_TC(tp, wmemcpy_heap_before_end); + ATF_TP_ADD_TC(tp, wmemcpy_heap_end); + ATF_TP_ADD_TC(tp, wmemcpy_heap_after_end); + ATF_TP_ADD_TC(tp, wmempcpy_before_end); + ATF_TP_ADD_TC(tp, wmempcpy_end); + ATF_TP_ADD_TC(tp, wmempcpy_heap_before_end); + ATF_TP_ADD_TC(tp, wmempcpy_heap_end); + ATF_TP_ADD_TC(tp, wmempcpy_heap_after_end); + ATF_TP_ADD_TC(tp, wmemmove_before_end); + ATF_TP_ADD_TC(tp, wmemmove_end); + ATF_TP_ADD_TC(tp, wmemmove_heap_before_end); + ATF_TP_ADD_TC(tp, wmemmove_heap_end); + ATF_TP_ADD_TC(tp, wmemmove_heap_after_end); + ATF_TP_ADD_TC(tp, wmemset_before_end); + ATF_TP_ADD_TC(tp, wmemset_end); + ATF_TP_ADD_TC(tp, wmemset_heap_before_end); + ATF_TP_ADD_TC(tp, wmemset_heap_end); + ATF_TP_ADD_TC(tp, wmemset_heap_after_end); + ATF_TP_ADD_TC(tp, wcpcpy_before_end); + ATF_TP_ADD_TC(tp, wcpcpy_end); + ATF_TP_ADD_TC(tp, wcpcpy_heap_before_end); + ATF_TP_ADD_TC(tp, wcpcpy_heap_end); + ATF_TP_ADD_TC(tp, wcpcpy_heap_after_end); + ATF_TP_ADD_TC(tp, wcpncpy_before_end); + ATF_TP_ADD_TC(tp, wcpncpy_end); + ATF_TP_ADD_TC(tp, wcpncpy_heap_before_end); + ATF_TP_ADD_TC(tp, wcpncpy_heap_end); + ATF_TP_ADD_TC(tp, wcpncpy_heap_after_end); + ATF_TP_ADD_TC(tp, wcscat_before_end); + ATF_TP_ADD_TC(tp, wcscat_end); + ATF_TP_ADD_TC(tp, wcscat_heap_before_end); + ATF_TP_ADD_TC(tp, wcscat_heap_end); + ATF_TP_ADD_TC(tp, wcscat_heap_after_end); + ATF_TP_ADD_TC(tp, wcslcat_before_end); + ATF_TP_ADD_TC(tp, wcslcat_end); + ATF_TP_ADD_TC(tp, wcslcat_heap_before_end); + ATF_TP_ADD_TC(tp, wcslcat_heap_end); + ATF_TP_ADD_TC(tp, wcslcat_heap_after_end); + ATF_TP_ADD_TC(tp, wcsncat_before_end); + ATF_TP_ADD_TC(tp, wcsncat_end); + ATF_TP_ADD_TC(tp, wcsncat_heap_before_end); + ATF_TP_ADD_TC(tp, wcsncat_heap_end); + ATF_TP_ADD_TC(tp, wcsncat_heap_after_end); + ATF_TP_ADD_TC(tp, wcscpy_before_end); + ATF_TP_ADD_TC(tp, wcscpy_end); + ATF_TP_ADD_TC(tp, wcscpy_heap_before_end); + ATF_TP_ADD_TC(tp, wcscpy_heap_end); + ATF_TP_ADD_TC(tp, wcscpy_heap_after_end); + ATF_TP_ADD_TC(tp, wcslcpy_before_end); + ATF_TP_ADD_TC(tp, wcslcpy_end); + ATF_TP_ADD_TC(tp, wcslcpy_heap_before_end); + ATF_TP_ADD_TC(tp, wcslcpy_heap_end); + ATF_TP_ADD_TC(tp, wcslcpy_heap_after_end); + ATF_TP_ADD_TC(tp, wcsncpy_before_end); + ATF_TP_ADD_TC(tp, wcsncpy_end); + ATF_TP_ADD_TC(tp, wcsncpy_heap_before_end); + ATF_TP_ADD_TC(tp, wcsncpy_heap_end); + ATF_TP_ADD_TC(tp, wcsncpy_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/generate-fortify-tests.lua b/lib/libc/tests/secure/generate-fortify-tests.lua new file mode 100755 index 000000000000..c9cd9353a869 --- /dev/null +++ b/lib/libc/tests/secure/generate-fortify-tests.lua @@ -0,0 +1,1581 @@ +#!/usr/libexec/flua +-- +-- SPDX-License-Identifier: BSD-2-Clause +-- +-- Copyright (c) 2024, Klara, Inc. +-- +-- 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. +-- + +-- THEORY OF OPERATION +-- +-- generate-fortify-tests.lua is intended to test fortified functions as found +-- mostly in the various headers in /usr/include/ssp. Each fortified function +-- gets three basic tests: +-- +-- 1. Write just before the end of the buffer, +-- 2. Write right at the end of the buffer, +-- 3. Write just after the end of the buffer. +-- +-- Each test is actually generated twice: once with a buffer on the stack, and +-- again with a buffer on the heap, to confirm that __builtin_object_size(3) can +-- deduce the buffer size in both scenarios. The tests work by setting up the +-- stack with our buffer (and some padding on either side to avoid tripping any +-- other stack or memory protection), doing any initialization as described by +-- the test definition, then calling the fortified function with the buffer as +-- outlined by the test definition. +-- +-- For the 'before' and 'at' the end tests, we're ensuring that valid writes +-- that are on the verge of being invalid aren't accidentally being detected as +-- invalid. +-- +-- The 'after' test is the one that actually tests the functional benefit of +-- _FORTIFY_SOURCE by violating a boundary that should trigger an abort. As +-- such, this test differs more from the other two in that it has to fork() off +-- the fortified function call so that we can monitor for a SIGABRT and +-- pass/fail the test at function end appropriately. + +-- Some tests, like the FD_*() macros, may define these differently. For +-- instance, for fd sets we're varying the index we pass and not using arbitrary +-- buffers. Other tests that don't use the length in any way may physically +-- vary the buffer size for each test case when we'd typically vary the length +-- we're requesting a write for. + +local includes = { + "sys/param.h", + "sys/jail.h", + "sys/random.h", + "sys/resource.h", + "sys/select.h", + "sys/socket.h", + "sys/time.h", + "sys/uio.h", + "sys/wait.h", + "dirent.h", + "errno.h", + "fcntl.h", + "limits.h", + "poll.h", + "signal.h", + "stdio.h", + "stdlib.h", + "string.h", + "strings.h", + "sysexits.h", + "unistd.h", + "wchar.h", + "atf-c.h", +} + +local tests_added = {} + +-- Configuration for tests that want the host/domainname +local hostname = "host.example.com" +local domainname = "example.com" + +-- Some of these will need to be excluded because clang sees the wrong size when +-- an array is embedded inside a struct, we'll get something that looks more +-- like __builtin_object_size(ptr, 0) than it does the correct +-- __builtin_object_size(ptr, 1) (i.e., includes the padding after). This is +-- almost certainly a bug in llvm. +local function excludes_stack_overflow(disposition, is_heap) + return (not is_heap) and disposition > 0 +end + +local poll_init = [[ + for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { + __stack.__buf[i].fd = -1; + } +]] + +local printf_stackvars = "\tchar srcvar[__len + 10];\n" +local printf_init = [[ + memset(srcvar, 'A', sizeof(srcvar) - 1); + srcvar[sizeof(srcvar) - 1] = '\0'; +]] + +local readv_stackvars = "\tstruct iovec iov[1];\n" +local readv_init = [[ + iov[0].iov_base = __stack.__buf; + iov[0].iov_len = __len; + + replace_stdin(); +]] + +local socket_stackvars = "\tint sock[2] = { -1, -1 };\n" +local recvfrom_sockaddr_stackvars = socket_stackvars .. [[ + char data[16]; + socklen_t socklen; +]] +local recvmsg_stackvars = socket_stackvars .. "\tstruct msghdr msg;\n" +local socket_init = [[ + new_socket(sock); +]] +local socket_socklen_init = socket_init .. [[ + socklen = __len; +]] + +local stdio_init = [[ + replace_stdin(); +]] + +local string_stackvars = "\tchar src[__len];\n" +local string_init = [[ + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; +]] + +local wstring_stackvars = "\twchar_t src[__len];\n" +local wstring_init = [[ + wmemset(__stack.__buf, 0, __len); + wmemset(src, 'A', __len - 1); + src[__len - 1] = '\0'; +]] + +-- Each test entry describes how to test a given function. We need to know how +-- to construct the buffer, we need to know the argument set we're dealing with, +-- and we need to know what we're passing to each argument. We could be passing +-- fixed values, or we could be passing the __buf under test. +-- +-- definition: +-- func: name of the function under test to call +-- bufsize: size of buffer to generate, defaults to 42 +-- buftype: type of buffer to generate, defaults to unsigned char[] +-- arguments: __buf, __len, or the name of a variable placed on the stack +-- exclude: a function(disposition, is_heap) that returns true if this combo +-- should be excluded. +-- stackvars: extra variables to be placed on the stack, should be a string +-- optionally formatted with tabs and newlines +-- init: extra code to inject just before the function call for initialization +-- of the buffer or any of the above-added stackvars; also a string +-- uses_len: bool-ish, necessary if arguments doesn't include either __idx or +-- or __len so that the test generator doesn't try to vary the size of the +-- buffer instead of just manipulating __idx/__len to try and induce an +-- overflow. +-- +-- Most tests will just use the default bufsize/buftype, but under some +-- circumstances it's useful to use a different type (e.g., for alignment +-- requirements). +local all_tests = { + random = { + -- <sys/random.h> + { + func = "getrandom", + arguments = { + "__buf", + "__len", + "0", + }, + exclude = excludes_stack_overflow, + }, + }, + select = { + -- <sys/select.h> + { + func = "FD_SET", + bufsize = "FD_SETSIZE", + buftype = "fd_set", + arguments = { + "__idx", + "__buf", + }, + }, + { + func = "FD_CLR", + bufsize = "FD_SETSIZE", + buftype = "fd_set", + arguments = { + "__idx", + "__buf", + }, + }, + { + func = "FD_ISSET", + bufsize = "FD_SETSIZE", + buftype = "fd_set", + arguments = { + "__idx", + "__buf", + }, + }, + }, + socket = { + -- <sys/socket.h> + { + func = "getpeername", + buftype = "struct sockaddr", + bufsize = "sizeof(struct sockaddr)", + arguments = { + "sock[0]", + "__buf", + "&socklen", + }, + exclude = excludes_stack_overflow, + stackvars = socket_stackvars .. "\tsocklen_t socklen;", + init = socket_socklen_init, + uses_len = true, + }, + { + func = "getsockname", + buftype = "struct sockaddr", + bufsize = "sizeof(struct sockaddr)", + arguments = { + "sock[0]", + "__buf", + "&socklen", + }, + exclude = excludes_stack_overflow, + stackvars = socket_stackvars .. "\tsocklen_t socklen;", + init = socket_socklen_init, + uses_len = true, + }, + { + func = "recv", + arguments = { + "sock[0]", + "__buf", + "__len", + "0", + }, + exclude = excludes_stack_overflow, + stackvars = socket_stackvars, + init = socket_init, + }, + { + func = "recvfrom", + arguments = { + "sock[0]", + "__buf", + "__len", + "0", + "NULL", + "NULL", + }, + exclude = excludes_stack_overflow, + stackvars = socket_stackvars, + init = socket_init, + }, + { + func = "recvfrom", + variant = "sockaddr", + buftype = "struct sockaddr", + bufsize = "sizeof(struct sockaddr)", + arguments = { + "sock[0]", + "data", + "sizeof(data)", + "0", + "__buf", + "&socklen", + }, + exclude = excludes_stack_overflow, + stackvars = recvfrom_sockaddr_stackvars, + init = socket_socklen_init, + uses_len = true, + }, + { + func = "recvmsg", + variant = "msg_name", + buftype = "struct sockaddr", + bufsize = "sizeof(struct sockaddr)", + arguments = { + "sock[0]", + "&msg", + "0", + }, + exclude = excludes_stack_overflow, + stackvars = recvmsg_stackvars, + init = [[ + memset(&msg, 0, sizeof(msg)); + msg.msg_name = BUF; + msg.msg_namelen = __len; +]], + uses_len = true, + }, + { + func = "recvmsg", + variant = "msg_iov", + arguments = { + "sock[0]", + "&msg", + "0", + }, + exclude = excludes_stack_overflow, + stackvars = recvmsg_stackvars .. "\tstruct iovec iov[2];\n", + init = [[ + memset(&msg, 0, sizeof(msg)); + memset(&iov[0], 0, sizeof(iov)); + + /* + * We position the buffer second just so that we can confirm that the + * fortification bits are traversing the iovec correctly. + */ + iov[1].iov_base = BUF; + iov[1].iov_len = __len; + + msg.msg_iov = &iov[0]; + msg.msg_iovlen = nitems(iov); +]], + uses_len = true, + }, + { + func = "recvmsg", + variant = "msg_control", + bufsize = "CMSG_SPACE(sizeof(int))", + arguments = { + "sock[0]", + "&msg", + "0", + }, + exclude = excludes_stack_overflow, + stackvars = recvmsg_stackvars, + init = [[ + memset(&msg, 0, sizeof(msg)); + + msg.msg_control = BUF; + msg.msg_controllen = __len; +]], + uses_len = true, + }, + { + func = "recvmmsg", + variant = "msgvec", + buftype = "struct mmsghdr[]", + bufsize = "2", + arguments = { + "sock[0]", + "__buf", + "__len", + "0", + "NULL", + }, + stackvars = socket_stackvars, + }, + { + -- We'll assume that recvmsg is covering msghdr + -- validation thoroughly enough, we'll just try tossing + -- an error in the second element of a msgvec to try and + -- make sure that each one is being validated. + func = "recvmmsg", + variant = "msghdr", + arguments = { + "sock[0]", + "&msgvec[0]", + "nitems(msgvec)", + "0", + "NULL", + }, + exclude = excludes_stack_overflow, + stackvars = socket_stackvars .. "\tstruct mmsghdr msgvec[2];\n", + init = [[ + memset(&msgvec[0], 0, sizeof(msgvec)); + + /* + * Same as above, make sure fortification isn't ignoring n > 1 elements + * of the msgvec. + */ + msgvec[1].msg_hdr.msg_control = BUF; + msgvec[1].msg_hdr.msg_controllen = __len; +]], + uses_len = true, + }, + }, + uio = { + -- <sys/uio.h> + { + func = "readv", + buftype = "struct iovec[]", + bufsize = 2, + arguments = { + "STDIN_FILENO", + "__buf", + "__len", + }, + }, + { + func = "readv", + variant = "iov", + arguments = { + "STDIN_FILENO", + "iov", + "nitems(iov)", + }, + exclude = excludes_stack_overflow, + stackvars = readv_stackvars, + init = readv_init, + uses_len = true, + }, + { + func = "preadv", + buftype = "struct iovec[]", + bufsize = 2, + arguments = { + "STDIN_FILENO", + "__buf", + "__len", + "0", + }, + }, + { + func = "preadv", + variant = "iov", + arguments = { + "STDIN_FILENO", + "iov", + "nitems(iov)", + "0", + }, + exclude = excludes_stack_overflow, + stackvars = readv_stackvars, + init = readv_init, + uses_len = true, + }, + }, + poll = { + -- <poll.h> + { + func = "poll", + bufsize = "4", + buftype = "struct pollfd[]", + arguments = { + "__buf", + "__len", + "0", + }, + init = poll_init, + }, + { + func = "ppoll", + bufsize = "4", + buftype = "struct pollfd[]", + arguments = { + "__buf", + "__len", + "&tv", + "NULL", + }, + stackvars = "\tstruct timespec tv = { 0 };\n", + init = poll_init, + }, + }, + signal = { + -- <signal.h> + { + func = "sig2str", + bufsize = "SIG2STR_MAX", + arguments = { + "1", + "__buf", + }, + exclude = excludes_stack_overflow, + }, + }, + stdio = { + -- <stdio.h> + { + func = "ctermid", + bufsize = "L_ctermid", + arguments = { + "__buf", + }, + exclude = excludes_stack_overflow, + }, + { + func = "ctermid_r", + bufsize = "L_ctermid", + arguments = { + "__buf", + }, + exclude = excludes_stack_overflow, + }, + { + func = "fread", + arguments = { + "__buf", + "__len", + "1", + "stdin", + }, + exclude = excludes_stack_overflow, + init = stdio_init, + }, + { + func = "fread_unlocked", + arguments = { + "__buf", + "__len", + "1", + "stdin", + }, + exclude = excludes_stack_overflow, + init = stdio_init, + }, + { + func = "gets_s", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + init = stdio_init, + }, + { + func = "sprintf", + arguments = { + "__buf", + "\"%.*s\"", + "(int)__len - 1", -- - 1 for NUL terminator + "srcvar", + }, + exclude = excludes_stack_overflow, + stackvars = printf_stackvars, + init = printf_init, + }, + { + func = "snprintf", + arguments = { + "__buf", + "__len", + "\"%.*s\"", + "(int)__len - 1", -- - 1 for NUL terminator + "srcvar", + }, + exclude = excludes_stack_overflow, + stackvars = printf_stackvars, + init = printf_init, + }, + { + func = "tmpnam", + bufsize = "L_tmpnam", + arguments = { + "__buf", + }, + exclude = excludes_stack_overflow, + }, + { + func = "fgets", + arguments = { + "__buf", + "__len", + "fp", + }, + exclude = excludes_stack_overflow, + stackvars = "\tFILE *fp;\n", + init = [[ + fp = new_fp(__len); +]], + }, + }, + stdlib = { + -- <stdlib.h> + { + func = "arc4random_buf", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "getenv_r", + arguments = { + "\"PATH\"", + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "realpath", + bufsize = "PATH_MAX", + arguments = { + "\".\"", + "__buf", + }, + exclude = excludes_stack_overflow, + }, + }, + string = { + -- <string.h> + { + func = "memcpy", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\tchar src[__len + 10];\n", + }, + { + func = "mempcpy", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\tchar src[__len + 10];\n", + }, + { + func = "memmove", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\tchar src[__len + 10];\n", + }, + { + func = "memset", + arguments = { + "__buf", + "0", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "memset_explicit", + arguments = { + "__buf", + "0", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "stpcpy", + arguments = { + "__buf", + "src", + }, + exclude = excludes_stack_overflow, + stackvars = string_stackvars, + init = string_init, + uses_len = true, + }, + { + func = "stpncpy", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = string_stackvars, + init = string_init, + }, + { + func = "strcat", + arguments = { + "__buf", + "src", + }, + exclude = excludes_stack_overflow, + stackvars = string_stackvars, + init = string_init, + uses_len = true, + }, + { + func = "strlcat", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = string_stackvars, + init = string_init, + }, + { + func = "strncat", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = string_stackvars, + init = string_init, + }, + { + func = "strcpy", + arguments = { + "__buf", + "src", + }, + exclude = excludes_stack_overflow, + stackvars = string_stackvars, + init = string_init, + uses_len = true, + }, + { + func = "strlcpy", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = string_stackvars, + init = string_init, + }, + { + func = "strncpy", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = string_stackvars, + init = string_init, + }, + }, + strings = { + -- <strings.h> + { + func = "bcopy", + arguments = { + "src", + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\tchar src[__len + 10];\n", + }, + { + func = "bzero", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "explicit_bzero", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + }, + }, + unistd = { + -- <unistd.h> + { + func = "getcwd", + bufsize = "8", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "getgrouplist", + bufsize = "4", + buftype = "gid_t[]", + arguments = { + "\"root\"", + "0", + "__buf", + "&intlen", + }, + exclude = excludes_stack_overflow, + stackvars = "\tint intlen = (int)__len;\n", + uses_len = true, + }, + { + func = "getgroups", + bufsize = "4", + buftype = "gid_t[]", + arguments = { + "__len", + "__buf", + }, + exclude = excludes_stack_overflow, + }, + { + func = "getloginclass", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "pread", + bufsize = "41", + arguments = { + "fd", + "__buf", + "__len", + "0", + }, + exclude = excludes_stack_overflow, + stackvars = "\tint fd;\n", + init = [[ + fd = new_tmpfile(); /* Cannot fail */ +]], + }, + { + func = "read", + bufsize = "41", + arguments = { + "fd", + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\tint fd;\n", + init = [[ + fd = new_tmpfile(); /* Cannot fail */ +]], + }, + { + func = "readlink", + arguments = { + "path", + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\tconst char *path;\n", + init = [[ + path = new_symlink(__len); /* Cannot fail */ +]], + }, + { + func = "readlinkat", + arguments = { + "AT_FDCWD", + "path", + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\tconst char *path;\n", + init = [[ + path = new_symlink(__len); /* Cannot fail */ +]], + }, + { + func = "getdomainname", + bufsize = #domainname + 1, + arguments = { + "__buf", + "__len", + }, + need_root = true, + exclude = excludes_stack_overflow, + early_init = " dhost_jail();", + }, + { + func = "getentropy", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "gethostname", + bufsize = #hostname + 1, + arguments = { + "__buf", + "__len", + }, + need_root = true, + exclude = excludes_stack_overflow, + early_init = " dhost_jail();", + }, + { + func = "getlogin_r", + bufsize = "MAXLOGNAME + 1", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "ttyname_r", + arguments = { + "fd", + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\tint fd;\n", + early_init = [[ + fd = STDIN_FILENO; + if (!isatty(fd)) + atf_tc_skip("stdin is not an fd"); +]] + }, + }, + wchar = { + -- <wchar.h> + { + func = "wmemcpy", + buftype = "wchar_t[]", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\twchar_t src[__len + 10];\n", + }, + { + func = "wmempcpy", + buftype = "wchar_t[]", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\twchar_t src[__len + 10];\n", + }, + { + func = "wmemmove", + buftype = "wchar_t[]", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\twchar_t src[__len + 10];\n", + }, + { + func = "wmemset", + buftype = "wchar_t[]", + arguments = { + "__buf", + "L'0'", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "wcpcpy", + buftype = "wchar_t[]", + arguments = { + "__buf", + "src", + }, + exclude = excludes_stack_overflow, + stackvars = wstring_stackvars, + init = wstring_init, + uses_len = true, + }, + { + func = "wcpncpy", + buftype = "wchar_t[]", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = wstring_stackvars, + init = wstring_init, + }, + { + func = "wcscat", + buftype = "wchar_t[]", + arguments = { + "__buf", + "src", + }, + exclude = excludes_stack_overflow, + stackvars = wstring_stackvars, + init = wstring_init, + uses_len = true, + }, + { + func = "wcslcat", + buftype = "wchar_t[]", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = wstring_stackvars, + init = wstring_init, + }, + { + func = "wcsncat", + buftype = "wchar_t[]", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = wstring_stackvars, + init = wstring_init, + }, + { + func = "wcscpy", + buftype = "wchar_t[]", + arguments = { + "__buf", + "src", + }, + exclude = excludes_stack_overflow, + stackvars = wstring_stackvars, + init = wstring_init, + uses_len = true, + }, + { + func = "wcslcpy", + buftype = "wchar_t[]", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = wstring_stackvars, + init = wstring_init, + }, + { + func = "wcsncpy", + buftype = "wchar_t[]", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = wstring_stackvars, + init = wstring_init, + }, + }, +} + +local function write_test_boilerplate(fh, name, body, def) + fh:write("ATF_TC(" .. name .. ");\n") + fh:write("ATF_TC_HEAD(" .. name .. ", tc)\n") + fh:write("{\n") + if def.need_root then + fh:write(" atf_tc_set_md_var(tc, \"require.user\", \"root\");\n") + end + fh:write("}\n") + + fh:write("ATF_TC_BODY(" .. name .. ", tc)\n") + fh:write("{\n" .. body .. "\n}\n\n") + return name +end + +local function generate_test_name(func, variant, disposition, heap) + local basename = func + if variant then + basename = basename .. "_" .. variant + end + if heap then + basename = basename .. "_heap" + end + if disposition < 0 then + return basename .. "_before_end" + elseif disposition == 0 then + return basename .. "_end" + else + return basename .. "_after_end" + end +end + +local function array_type(buftype) + if not buftype:match("%[%]") then + return nil + end + + return buftype:gsub("%[%]", "") +end + +local function configurable(def, idx) + local cfgitem = def[idx] + + if not cfgitem then + return nil + end + + if type(cfgitem) == "function" then + return cfgitem() + end + + return cfgitem +end + +local function generate_stackframe(buftype, bufsize, disposition, heap, def) + local function len_offset(inverted) + -- Tests that don't use __len in their arguments may use an + -- inverted sense because we can't just specify a length that + -- would induce an access just after the end. Instead, we have + -- to manipulate the buffer size to be too short so that the + -- function under test would write one too many. + if disposition < 0 then + return ((inverted and " + ") or " - ") .. "1" + elseif disposition == 0 then + return "" + else + return ((inverted and " - ") or " + ") .. "1" + end + end + + local function test_uses_len() + if def.uses_len then + return true + end + + for _, arg in ipairs(def.arguments) do + if arg:match("__len") or arg:match("__idx") then + return true + end + end + + return false + end + + + -- This is perhaps a little convoluted, but we toss the buffer into a + -- struct on the stack to guarantee that we have at least one valid + -- byte on either side of the buffer -- a measure to make sure that + -- we're tripping _FORTIFY_SOURCE specifically in the buffer + 1 case, + -- rather than some other stack or memory protection. + local vars = "\tstruct {\n" + vars = vars .. "\t\tuint8_t padding_l;\n" + + local uses_len = test_uses_len() + local bufsize_offset = len_offset(not uses_len) + local buftype_elem = array_type(buftype) + local size_expr = bufsize + + if not uses_len then + -- If the length isn't in use, we have to vary the buffer size + -- since the fortified function likely has some internal size + -- constraint that it's supposed to be checking. + size_expr = size_expr .. bufsize_offset + end + + if not heap and buftype_elem then + -- Array type: size goes after identifier + vars = vars .. "\t\t" .. buftype_elem .. + " __buf[" .. size_expr .. "];\n" + else + local basic_type = buftype_elem or buftype + + -- Heap tests obviously just put a pointer on the stack that + -- points to our new allocation, but we leave it in the padded + -- struct just to simplify our generator. + if heap then + basic_type = basic_type .. " *" + end + vars = vars .. "\t\t" .. basic_type .. " __buf;\n" + end + + -- padding_r is our just-past-the-end padding that we use to make sure + -- that there's a valid portion after the buffer that isn't being + -- included in our function calls. If we didn't have it, then we'd have + -- a hard time feeling confident that an abort on the just-after tests + -- isn't maybe from some other memory or stack protection. + vars = vars .. "\t\tuint8_t padding_r;\n" + vars = vars .. "\t} __stack;\n" + + -- Not all tests will use __bufsz, but some do for, e.g., clearing + -- memory.. + vars = vars .. "\tconst size_t __bufsz __unused = " + if heap then + local scalar = 1 + if buftype_elem then + scalar = size_expr + end + + vars = vars .. "sizeof(*__stack.__buf) * (" .. scalar .. ");\n" + else + vars = vars .. "sizeof(__stack.__buf);\n" + end + + vars = vars .. "\tconst size_t __len = " .. bufsize .. + bufsize_offset .. ";\n" + vars = vars .. "\tconst size_t __idx __unused = __len - 1;\n" + + -- For overflow testing, we need to fork() because we're expecting the + -- test to ultimately abort()/_exit(). Then we can collect the exit + -- status and report appropriately. + if disposition > 0 then + vars = vars .. "\tpid_t __child;\n" + vars = vars .. "\tint __status;\n" + end + + -- Any other stackvars defined by the test get placed after everything + -- else. + vars = vars .. (configurable(def, "stackvars") or "") + + return vars +end + +local function write_test(fh, func, disposition, heap, def) + local testname = generate_test_name(func, def.variant, disposition, heap) + local buftype = def.buftype or "unsigned char[]" + local bufsize = def.bufsize or 42 + local body = "" + + if def.exclude and def.exclude(disposition, heap) then + return + end + + local function need_addr() + return not (buftype:match("%[%]") or buftype:match("%*")) + end + + if heap then + body = body .. "#define BUF __stack.__buf\n" + else + body = body .. "#define BUF &__stack.__buf\n" + end + + -- Setup the buffer + body = body .. generate_stackframe(buftype, bufsize, disposition, heap, def) .. + "\n" + + -- Any early initialization goes before we would fork for the just-after + -- tests, because they may want to skip the test based on some criteria + -- and we can't propagate that up very easily once we're forked. + local early_init = configurable(def, "early_init") + body = body .. (early_init or "") + if early_init then + body = body .. "\n" + end + + -- Fork off, iff we're testing some access past the end of the buffer. + if disposition > 0 then + body = body .. [[ + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); +]] + end + + local bufvar = "__stack.__buf" + if heap then + -- Buffer needs to be initialized because it's a heap allocation. + body = body .. "\t" .. bufvar .. " = malloc(__bufsz);\n" + end + + -- Non-early init happens just after the fork in the child, not the + -- monitor. This is used to setup any other buffers we may need, for + -- instance. + local extra_init = configurable(def, "init") + body = body .. (extra_init or "") + + if heap or extra_init then + body = body .. "\n" + end + + -- Setup the function call with arguments as described in the test + -- definition. + body = body .. "\t" .. func .. "(" + + for idx, arg in ipairs(def.arguments) do + if idx > 1 then + body = body .. ", " + end + + if arg == "__buf" then + if not heap and need_addr() then + body = body .. "&" + end + + body = body .. bufvar + else + local argname = arg + + if def.value_of then + argname = argname or def.value_of(arg) + end + + body = body .. argname + end + end + + body = body .. ");\n" + + -- Monitor stuff follows, for OOB access. + if disposition <= 0 then + goto skip + end + + body = body .. [[ + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +]] + +::skip:: + body = body .. "#undef BUF\n" + return write_test_boilerplate(fh, testname, body, def) +end + +-- main() +local tests +local tcat = assert(arg[1], "usage: generate-fortify-tests.lua <category>") +for k, defs in pairs(all_tests) do + if k == tcat then + tests = defs + break + end +end + +assert(tests, "category " .. tcat .. " not found") + +local fh = io.stdout +fh:write("/* @" .. "generated" .. " by `generate-fortify-tests.lua \"" .. + tcat .. "\"` */\n\n") +fh:write("#define _FORTIFY_SOURCE 2\n") +fh:write("#define TMPFILE_SIZE (1024 * 32)\n") + +fh:write("\n") +for _, inc in ipairs(includes) do + fh:write("#include <" .. inc .. ">\n") +end + +fh:write([[ + +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + +/* + * Create a new symlink to use for readlink(2) style tests, we'll just use a + * random target name to have something interesting to look at. + */ +static const char * __unused +new_symlink(size_t __len) +{ + static const char linkname[] = "link"; + char target[MAXNAMLEN]; + int error; + + ATF_REQUIRE(__len <= sizeof(target)); + + arc4random_buf(target, sizeof(target)); + + error = unlink(linkname); + ATF_REQUIRE(error == 0 || errno == ENOENT); + + error = symlink(target, linkname); + ATF_REQUIRE(error == 0); + + return (linkname); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ + unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; + static char sockbuf[256]; + ssize_t rv; + size_t total = 0; + struct msghdr hdr = { 0 }; + struct cmsghdr *cmsg; + int error, fd; + + error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + ATF_REQUIRE(error == 0); + + while (total != sizeof(sockbuf)) { + rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + + ATF_REQUIRE_MSG(rv > 0, + "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", + rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); + ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), + "%zd exceeds total %zu", rv, sizeof(sockbuf)); + total += rv; + } + + hdr.msg_control = ctrl; + hdr.msg_controllen = sizeof(ctrl); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + fd = STDIN_FILENO; + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + error = sendmsg(sock[1], &hdr, 0); + ATF_REQUIRE(error != -1); +} + +/* + * Constructs a tmpfile that we can use for testing read(2) and friends. + */ +static int __unused +new_tmpfile(void) +{ + char buf[1024]; + ssize_t rv; + size_t written; + int fd; + + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +]]) + +if tcat == "unistd" then + fh:write("#define JAIL_HOSTNAME \"" .. hostname .. "\"\n") + fh:write("#define JAIL_DOMAINNAME \"" .. domainname .. "\"\n") + fh:write([[ +static void +dhost_jail(void) +{ + struct iovec iov[4]; + int jid; + + iov[0].iov_base = __DECONST(char *, "host.hostname"); + iov[0].iov_len = sizeof("host.hostname"); + iov[1].iov_base = __DECONST(char *, JAIL_HOSTNAME); + iov[1].iov_len = sizeof(JAIL_HOSTNAME); + iov[2].iov_base = __DECONST(char *, "host.domainname"); + iov[2].iov_len = sizeof("host.domainname"); + iov[3].iov_base = __DECONST(char *, JAIL_DOMAINNAME); + iov[3].iov_len = sizeof(JAIL_DOMAINNAME); + + jid = jail_set(iov, nitems(iov), JAIL_CREATE | JAIL_ATTACH); + ATF_REQUIRE_MSG(jid > 0, "Jail creation failed: %s", strerror(errno)); +} + +]]) +end + +for _, def in pairs(tests) do + local func = def.func + local function write_tests(heap) + -- Dispositions here are relative to the buffer size prescribed + -- by the test definition. + local dispositions = def.dispositions or { -1, 0, 1 } + + for _, disposition in ipairs(dispositions) do + tests_added[#tests_added + 1] = write_test(fh, func, disposition, heap, def) + end + end + + write_tests(false) + write_tests(true) +end + +fh:write("ATF_TP_ADD_TCS(tp)\n") +fh:write("{\n") +for idx = 1, #tests_added do + fh:write("\tATF_TP_ADD_TC(tp, " .. tests_added[idx] .. ");\n") +end +fh:write("\treturn (atf_no_error());\n") +fh:write("}\n") diff --git a/lib/libc/tests/setjmp/Makefile b/lib/libc/tests/setjmp/Makefile index 39b0a96295f4..8ea8550dfba0 100644 --- a/lib/libc/tests/setjmp/Makefile +++ b/lib/libc/tests/setjmp/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - NETBSD_ATF_TESTS_C= setjmp_test NETBSD_ATF_TESTS_C+= threadjmp_test diff --git a/lib/libc/tests/setjmp/Makefile.depend b/lib/libc/tests/setjmp/Makefile.depend index 10e58b789640..e89a5c52c82a 100644 --- a/lib/libc/tests/setjmp/Makefile.depend +++ b/lib/libc/tests/setjmp/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/ssp/Makefile b/lib/libc/tests/ssp/Makefile index 936ada01a760..644d5a6d64a2 100644 --- a/lib/libc/tests/ssp/Makefile +++ b/lib/libc/tests/ssp/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> MK_WERROR= no @@ -11,6 +9,7 @@ CFLAGS.h_raw+= -fstack-protector-all -Wstack-protector # override the sanitizer runtime libraries to be the ones installed on the # target system. CFLAGS.h_raw+= -fsanitize=bounds +LIBADD+=sys .elif ${COMPILER_TYPE} == "gcc" CFLAGS.h_raw+= --param ssp-buffer-size=1 LDADD+= -lssp @@ -30,7 +29,8 @@ PROGS+= h_memset # now on amd64 when it trips the stack bounds specified in t_ssp.sh . This # probably needs to be fixed as it's currently hardcoded. .if ${COMPILER_TYPE} == "clang" && !defined(_SKIP_BUILD) && \ - (!defined(_RECURSING_PROGS) || ${PROG} == "h_raw") + (!defined(_RECURSING_PROGS) || ${PROG} == "h_raw") && \ + defined(MK_CLANG) && ${MK_CLANG} == "yes" .include "${SRCTOP}/lib/libclang_rt/compiler-rt-vars.mk" _libclang_rt_ubsan= ${SYSROOT}${SANITIZER_LIBDIR}/libclang_rt.ubsan_standalone-${CRTARCH}.a .if exists(${_libclang_rt_ubsan}) diff --git a/lib/libc/tests/ssp/Makefile.depend b/lib/libc/tests/ssp/Makefile.depend index cf65fef9f923..a3475b45b52e 100644 --- a/lib/libc/tests/ssp/Makefile.depend +++ b/lib/libc/tests/ssp/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/stdio/Makefile b/lib/libc/tests/stdio/Makefile index 792375ba17b8..6dca927c4fb7 100644 --- a/lib/libc/tests/stdio/Makefile +++ b/lib/libc/tests/stdio/Makefile @@ -1,9 +1,8 @@ -# $FreeBSD$ - .include <bsd.own.mk> ATF_TESTS_C+= eintr_test ATF_TESTS_C+= fdopen_test +ATF_TESTS_C+= flushlbuf_test ATF_TESTS_C+= fmemopen2_test ATF_TESTS_C+= fopen2_test ATF_TESTS_C+= freopen_test @@ -17,6 +16,10 @@ ATF_TESTS_C+= print_positional_test ATF_TESTS_C+= printbasic_test ATF_TESTS_C+= printfloat_test ATF_TESTS_C+= scanfloat_test +ATF_TESTS_C+= snprintf_test +ATF_TESTS_C+= sscanf_test +ATF_TESTS_C+= swprintf_test +ATF_TESTS_C+= swscanf_test SRCS.fopen2_test= fopen_test.c @@ -35,9 +38,15 @@ LIBADD.eintr_test+= md LIBADD.printfloat_test+= m LIBADD.scanfloat_test+= m +# Older toolchains won't understand C23 %b, %wN, %wfN +PROG_OVERRIDE_VARS+= NO_WFORMAT +NO_WFORMAT.snprintf_test= +NO_WFORMAT.sscanf_test= +NO_WFORMAT.swprintf_test= +NO_WFORMAT.swscanf_test= + .if ${COMPILER_TYPE} == "gcc" # 90: use of assignment suppression and length modifier together in scanf format -PROG_OVERRIDE_VARS+= NO_WFORMAT NO_WFORMAT.scanfloat_test= .endif diff --git a/lib/libc/tests/stdio/Makefile.depend b/lib/libc/tests/stdio/Makefile.depend index 45823695c1bb..e5ddbc552be2 100644 --- a/lib/libc/tests/stdio/Makefile.depend +++ b/lib/libc/tests/stdio/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/stdio/fdopen_test.c b/lib/libc/tests/stdio/fdopen_test.c index 060635af498b..5abaed7375b6 100644 --- a/lib/libc/tests/stdio/fdopen_test.c +++ b/lib/libc/tests/stdio/fdopen_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <fcntl.h> #include <paths.h> diff --git a/lib/libc/tests/stdio/flushlbuf_test.c b/lib/libc/tests/stdio/flushlbuf_test.c new file mode 100644 index 000000000000..3f8a6378f933 --- /dev/null +++ b/lib/libc/tests/stdio/flushlbuf_test.c @@ -0,0 +1,155 @@ +/*- + * Copyright (c) 2023 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <errno.h> +#include <stdio.h> + +#include <atf-c.h> + +#define BUFSIZE 16 + +static const char seq[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +struct stream { + char buf[BUFSIZE]; + unsigned int len; + unsigned int pos; +}; + +static int +writefn(void *cookie, const char *buf, int len) +{ + struct stream *s = cookie; + int written = 0; + + if (len <= 0) + return (0); + while (len > 0 && s->pos < s->len) { + s->buf[s->pos++] = *buf++; + written++; + len--; + } + if (written > 0) + return (written); + errno = EAGAIN; + return (-1); +} + +ATF_TC_WITHOUT_HEAD(flushlbuf_partial); +ATF_TC_BODY(flushlbuf_partial, tc) +{ + static struct stream s; + static char buf[BUFSIZE + 1]; + FILE *f; + unsigned int i = 0; + int ret = 0; + + /* + * Create the stream and its buffer, print just enough characters + * to the stream to fill the buffer without triggering a flush, + * then check the state. + */ + s.len = BUFSIZE / 2; // write will fail after this amount + ATF_REQUIRE((f = fwopen(&s, writefn)) != NULL); + ATF_REQUIRE(setvbuf(f, buf, _IOLBF, BUFSIZE) == 0); + while (i < BUFSIZE) + if ((ret = fprintf(f, "%c", seq[i++])) < 0) + break; + ATF_CHECK_EQ(BUFSIZE, i); + ATF_CHECK_EQ(seq[i - 1], buf[BUFSIZE - 1]); + ATF_CHECK_EQ(1, ret); + ATF_CHECK_EQ(0, s.pos); + + /* + * At this point, the buffer is full but writefn() has not yet + * been called. The next fprintf() call will trigger a preemptive + * fflush(), and writefn() will consume s.len characters before + * returning EAGAIN, causing fprintf() to fail without having + * written anything (which is why we don't increment i here). + */ + ret = fprintf(f, "%c", seq[i]); + ATF_CHECK_ERRNO(EAGAIN, ret < 0); + ATF_CHECK_EQ(s.len, s.pos); + + /* + * We have consumed s.len characters from the buffer, so continue + * printing until it is full again and check that no overflow has + * occurred yet. + */ + while (i < BUFSIZE + s.len) + fprintf(f, "%c", seq[i++]); + ATF_CHECK_EQ(BUFSIZE + s.len, i); + ATF_CHECK_EQ(seq[i - 1], buf[BUFSIZE - 1]); + ATF_CHECK_EQ(0, buf[BUFSIZE]); + + /* + * The straw that breaks the camel's back: libc fails to recognize + * that the buffer is full and continues to write beyond its end. + */ + fprintf(f, "%c", seq[i++]); + ATF_CHECK_EQ(0, buf[BUFSIZE]); +} + +ATF_TC_WITHOUT_HEAD(flushlbuf_full); +ATF_TC_BODY(flushlbuf_full, tc) +{ + static struct stream s; + static char buf[BUFSIZE]; + FILE *f; + unsigned int i = 0; + int ret = 0; + + /* + * Create the stream and its buffer, print just enough characters + * to the stream to fill the buffer without triggering a flush, + * then check the state. + */ + s.len = 0; // any attempt to write will fail + ATF_REQUIRE((f = fwopen(&s, writefn)) != NULL); + ATF_REQUIRE(setvbuf(f, buf, _IOLBF, BUFSIZE) == 0); + while (i < BUFSIZE) + if ((ret = fprintf(f, "%c", seq[i++])) < 0) + break; + ATF_CHECK_EQ(BUFSIZE, i); + ATF_CHECK_EQ(seq[i - 1], buf[BUFSIZE - 1]); + ATF_CHECK_EQ(1, ret); + ATF_CHECK_EQ(0, s.pos); + + /* + * At this point, the buffer is full but writefn() has not yet + * been called. The next fprintf() call will trigger a preemptive + * fflush(), and writefn() will immediately return EAGAIN, causing + * fprintf() to fail without having written anything (which is why + * we don't increment i here). + */ + ret = fprintf(f, "%c", seq[i]); + ATF_CHECK_ERRNO(EAGAIN, ret < 0); + ATF_CHECK_EQ(s.len, s.pos); + + /* + * Now make our stream writeable. + */ + s.len = sizeof(s.buf); + + /* + * Flush the stream again. The data we failed to write previously + * should still be in the buffer and will now be written to the + * stream. + */ + ATF_CHECK_EQ(0, fflush(f)); + ATF_CHECK_EQ(seq[0], s.buf[0]); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, flushlbuf_partial); + ATF_TP_ADD_TC(tp, flushlbuf_full); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdio/fmemopen2_test.c b/lib/libc/tests/stdio/fmemopen2_test.c index a2ca3257fe4e..a558ff3515e9 100644 --- a/lib/libc/tests/stdio/fmemopen2_test.c +++ b/lib/libc/tests/stdio/fmemopen2_test.c @@ -28,9 +28,6 @@ SUCH DAMAGE. * a FILE * retrieved using fmemopen() */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <stdio.h> #include <string.h> @@ -135,9 +132,11 @@ ATF_TC_BODY(test_autoalloc, tc) /* Open a FILE * using a wrong mode */ fp = fmemopen(NULL, 512, "r"); ATF_REQUIRE(fp == NULL); + ATF_REQUIRE(errno == EINVAL); fp = fmemopen(NULL, 512, "w"); ATF_REQUIRE(fp == NULL); + ATF_REQUIRE(errno == EINVAL); } ATF_TC_WITHOUT_HEAD(test_data_length); @@ -274,6 +273,36 @@ ATF_TC_BODY(test_size_0, tc) ATF_REQUIRE(errno == EINVAL); } +/* + * PR281953 - ensure we cannot write in read-only only mode, and cannot read in + * write-only mode. + */ +ATF_TC_WITHOUT_HEAD(test_rdonly_wronly); +ATF_TC_BODY(test_rdonly_wronly, tc) +{ + FILE *fp; + char buf[16]; + char buf_orig[16] = "input data"; + char buf_write[16] = "write"; + size_t sz; + + memcpy(buf, buf_orig, sizeof(buf)); + fp = fmemopen(buf, sizeof(buf), "r"); + ATF_REQUIRE(fp != NULL); + sz = fwrite(buf_write, 1, strlen(buf_write), fp); + ATF_REQUIRE(sz == 0); + ATF_REQUIRE(errno == EBADF); + ATF_REQUIRE(memcmp(buf, buf_orig, sizeof(buf)) == 0); + fclose(fp); + + fp = fmemopen(buf_orig, sizeof(buf), "w"); + ATF_REQUIRE(fp != NULL); + sz = fread(buf, sizeof(buf), 1, fp); + ATF_REQUIRE(sz == 0); + ATF_REQUIRE(errno == EBADF); + fclose(fp); +} + ATF_TP_ADD_TCS(tp) { @@ -283,6 +312,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, test_binary); ATF_TP_ADD_TC(tp, test_append_binary_pos); ATF_TP_ADD_TC(tp, test_size_0); + ATF_TP_ADD_TC(tp, test_rdonly_wronly); return (atf_no_error()); } diff --git a/lib/libc/tests/stdio/fopen_test.c b/lib/libc/tests/stdio/fopen_test.c index 962e7fdb1a34..4dda5cbf0e5e 100644 --- a/lib/libc/tests/stdio/fopen_test.c +++ b/lib/libc/tests/stdio/fopen_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <fcntl.h> #include <paths.h> #include <stdio.h> diff --git a/lib/libc/tests/stdio/freopen_test.c b/lib/libc/tests/stdio/freopen_test.c index 8ca4719e8603..55fe3c580dd3 100644 --- a/lib/libc/tests/stdio/freopen_test.c +++ b/lib/libc/tests/stdio/freopen_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <paths.h> #include <stdbool.h> diff --git a/lib/libc/tests/stdio/getdelim_test.c b/lib/libc/tests/stdio/getdelim_test.c index 7b20b02a36f1..01a0ab0949fe 100644 --- a/lib/libc/tests/stdio/getdelim_test.c +++ b/lib/libc/tests/stdio/getdelim_test.c @@ -25,9 +25,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> diff --git a/lib/libc/tests/stdio/gets_s_test.c b/lib/libc/tests/stdio/gets_s_test.c index 7d02990f82d4..4e1a59006b60 100644 --- a/lib/libc/tests/stdio/gets_s_test.c +++ b/lib/libc/tests/stdio/gets_s_test.c @@ -23,9 +23,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <assert.h> #include <stdint.h> #include <stdio.h> diff --git a/lib/libc/tests/stdio/mkostemp_test.c b/lib/libc/tests/stdio/mkostemp_test.c index 0dd475b4ec61..b31335fed43f 100644 --- a/lib/libc/tests/stdio/mkostemp_test.c +++ b/lib/libc/tests/stdio/mkostemp_test.c @@ -28,9 +28,6 @@ * Test program for mkostemp(). */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/stat.h> #include <errno.h> diff --git a/lib/libc/tests/stdio/open_memstream2_test.c b/lib/libc/tests/stdio/open_memstream2_test.c index 21ea64c7c669..c9c6528832d8 100644 --- a/lib/libc/tests/stdio/open_memstream2_test.c +++ b/lib/libc/tests/stdio/open_memstream2_test.c @@ -25,9 +25,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <err.h> #include <errno.h> #include <limits.h> diff --git a/lib/libc/tests/stdio/open_wmemstream_test.c b/lib/libc/tests/stdio/open_wmemstream_test.c index 324bcf3d3482..7ab882a4740a 100644 --- a/lib/libc/tests/stdio/open_wmemstream_test.c +++ b/lib/libc/tests/stdio/open_wmemstream_test.c @@ -25,9 +25,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <err.h> #include <errno.h> #include <limits.h> diff --git a/lib/libc/tests/stdio/perror_test.c b/lib/libc/tests/stdio/perror_test.c index 989f1ff6ea59..f3cb646d094e 100644 --- a/lib/libc/tests/stdio/perror_test.c +++ b/lib/libc/tests/stdio/perror_test.c @@ -29,9 +29,6 @@ * ISO/IEC 9899:1999. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <err.h> #include <errno.h> #include <limits.h> diff --git a/lib/libc/tests/stdio/print_positional_test.c b/lib/libc/tests/stdio/print_positional_test.c index 9c9ec314d62d..f896a30882f4 100644 --- a/lib/libc/tests/stdio/print_positional_test.c +++ b/lib/libc/tests/stdio/print_positional_test.c @@ -29,9 +29,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <stdio.h> #include <stdlib.h> diff --git a/lib/libc/tests/stdio/printbasic_test.c b/lib/libc/tests/stdio/printbasic_test.c index 322e7477da25..411dff518795 100644 --- a/lib/libc/tests/stdio/printbasic_test.c +++ b/lib/libc/tests/stdio/printbasic_test.c @@ -28,9 +28,6 @@ * Tests for basic and miscellaneous printf() formats. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <err.h> #include <limits.h> #include <locale.h> diff --git a/lib/libc/tests/stdio/printfloat_test.c b/lib/libc/tests/stdio/printfloat_test.c index 736ba1b493ef..031859124163 100644 --- a/lib/libc/tests/stdio/printfloat_test.c +++ b/lib/libc/tests/stdio/printfloat_test.c @@ -28,9 +28,6 @@ * Test for printf() floating point formats. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <err.h> #include <fenv.h> #include <float.h> diff --git a/lib/libc/tests/stdio/scanfloat_test.c b/lib/libc/tests/stdio/scanfloat_test.c index 7e27e69542e7..635d93d560b3 100644 --- a/lib/libc/tests/stdio/scanfloat_test.c +++ b/lib/libc/tests/stdio/scanfloat_test.c @@ -28,9 +28,6 @@ * Test for scanf() floating point formats. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <fenv.h> #include <float.h> #include <locale.h> @@ -62,88 +59,88 @@ ATF_TC_BODY(normalized_numbers, tc) buf[0] = '\0'; ATF_REQUIRE(setlocale(LC_NUMERIC, "")); - sscanf("3.141592", "%e", &f); + ATF_REQUIRE_EQ(1, sscanf("3.141592", "%e", &f)); ATF_REQUIRE(eq(FLT, f, 3.141592)); - sscanf("3.141592653589793", "%lf", &d); + ATF_REQUIRE_EQ(1, sscanf("3.141592653589793", "%lf", &d)); ATF_REQUIRE(eq(DBL, d, 3.141592653589793)); - sscanf("1.234568e+06", "%E", &f); + ATF_REQUIRE_EQ(1, sscanf("1.234568e+06", "%E", &f)); ATF_REQUIRE(eq(FLT, f, 1.234568e+06)); - sscanf("-1.234568e6", "%lF", &d); + ATF_REQUIRE_EQ(1, sscanf("-1.234568e6", "%lF", &d)); ATF_REQUIRE(eq(DBL, d, -1.234568e6)); - sscanf("+1.234568e-52", "%LG", &ld); + ATF_REQUIRE_EQ(1, sscanf("+1.234568e-52", "%LG", &ld)); ATF_REQUIRE(eq(LDBL, ld, 1.234568e-52L)); - sscanf("0.1", "%la", &d); + ATF_REQUIRE_EQ(1, sscanf("0.1", "%la", &d)); ATF_REQUIRE(eq(DBL, d, 0.1)); - sscanf("00.2", "%lA", &d); + ATF_REQUIRE_EQ(1, sscanf("00.2", "%lA", &d)); ATF_REQUIRE(eq(DBL, d, 0.2)); - sscanf("123456", "%5le%s", &d, buf); + ATF_REQUIRE_EQ(2, sscanf("123456", "%5le%s", &d, buf)); ATF_REQUIRE(eq(DBL, d, 12345.)); ATF_REQUIRE(strcmp(buf, "6") == 0); - sscanf("1.0Q", "%*5le%s", buf); + ATF_REQUIRE_EQ(1, sscanf("1.0Q", "%*5le%s", buf)); ATF_REQUIRE(strcmp(buf, "Q") == 0); - sscanf("-1.23e", "%e%s", &f, buf); + ATF_REQUIRE_EQ(2, sscanf("-1.23e", "%e%s", &f, buf)); ATF_REQUIRE(eq(FLT, f, -1.23)); ATF_REQUIRE(strcmp(buf, "e") == 0); - sscanf("1.25e+", "%le%s", &d, buf); + ATF_REQUIRE_EQ(2, sscanf("1.25e+", "%le%s", &d, buf)); ATF_REQUIRE(eq(DBL, d, 1.25)); ATF_REQUIRE(strcmp(buf, "e+") == 0); - sscanf("1.23E4E5", "%le%s", &d, buf); + ATF_REQUIRE_EQ(2, sscanf("1.23E4E5", "%le%s", &d, buf)); ATF_REQUIRE(eq(DBL, d, 1.23e4)); ATF_REQUIRE(strcmp(buf, "E5") == 0); - sscanf("12e6", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("12e6", "%le", &d)); ATF_REQUIRE(eq(DBL, d, 12e6)); - sscanf("1.a", "%le%s", &d, buf); + ATF_REQUIRE_EQ(2, sscanf("1.a", "%le%s", &d, buf)); ATF_REQUIRE(eq(DBL, d, 1.0)); ATF_REQUIRE(strcmp(buf, "a") == 0); - sscanf(".0p4", "%le%s", &d, buf); + ATF_REQUIRE_EQ(2, sscanf(".0p4", "%le%s", &d, buf)); ATF_REQUIRE(eq(DBL, d, 0.0)); ATF_REQUIRE(strcmp(buf, "p4") == 0); d = 0.25; - ATF_REQUIRE(sscanf(".", "%le", &d) == 0); + ATF_REQUIRE_EQ(0, sscanf(".", "%le", &d)); ATF_REQUIRE(d == 0.25); - sscanf("0x08", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("0x08", "%le", &d)); ATF_REQUIRE(d == 0x8p0); - sscanf("0x90a.bcdefP+09a", "%le%s", &d, buf); + ATF_REQUIRE_EQ(2, sscanf("0x90a.bcdefP+09a", "%le%s", &d, buf)); ATF_REQUIRE(d == 0x90a.bcdefp+09); ATF_REQUIRE(strcmp(buf, "a") == 0); #if (LDBL_MANT_DIG > DBL_MANT_DIG) && !defined(__i386__) - sscanf("3.14159265358979323846", "%Lg", &ld); + ATF_REQUIRE_EQ(1, sscanf("3.14159265358979323846", "%Lg", &ld)); ATF_REQUIRE(eq(LDBL, ld, 3.14159265358979323846L)); - sscanf(" 0X.0123456789abcdefffp-3g", "%Le%s", &ld, buf); + ATF_REQUIRE_EQ(2, sscanf(" 0X.0123456789abcdefffp-3g", "%Le%s", &ld, buf)); ATF_REQUIRE(ld == 0x0.0123456789abcdefffp-3L); ATF_REQUIRE(strcmp(buf, "g") == 0); #endif - sscanf("0xg", "%le%s", &d, buf); + ATF_REQUIRE_EQ(2, sscanf("0xg", "%le%s", &d, buf)); ATF_REQUIRE(d == 0.0); ATF_REQUIRE(strcmp(buf, "xg") == 0); ATF_REQUIRE(setlocale(LC_NUMERIC, "ru_RU.ISO8859-5")); /* decimalpoint==, */ - sscanf("1.23", "%le%s", &d, buf); + ATF_REQUIRE_EQ(2, sscanf("1.23", "%le%s", &d, buf)); ATF_REQUIRE(d == 1.0); ATF_REQUIRE(strcmp(buf, ".23") == 0); - sscanf("1,23", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("1,23", "%le", &d)); ATF_REQUIRE(d == 1.23); ATF_REQUIRE(setlocale(LC_NUMERIC, "")); @@ -159,40 +156,40 @@ ATF_TC_BODY(infinities_and_nans, tc) ATF_REQUIRE(setlocale(LC_NUMERIC, "C")); - sscanf("-Inf", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("-Inf", "%le", &d)); ATF_REQUIRE(d < 0.0 && isinf(d)); - sscanf("iNfInItY and beyond", "%le%s", &d, buf); + ATF_REQUIRE_EQ(2, sscanf("iNfInItY and beyond", "%le%s", &d, buf)); ATF_REQUIRE(d > 0.0 && isinf(d)); ATF_REQUIRE(strcmp(buf, " and beyond")); - sscanf("NaN", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("NaN", "%le", &d)); ATF_REQUIRE(isnan(d)); - sscanf("NAN(123Y", "%le%s", &d, buf); + ATF_REQUIRE_EQ(2, sscanf("NAN(123Y", "%le%s", &d, buf)); ATF_REQUIRE(isnan(d)); ATF_REQUIRE(strcmp(buf, "(123Y") == 0); - sscanf("nan(f00f)plugh", "%le%s", &d, buf); + ATF_REQUIRE_EQ(2, sscanf("nan(f00f)plugh", "%le%s", &d, buf)); ATF_REQUIRE(isnan(d)); ATF_REQUIRE(strcmp(buf, "plugh") == 0); - sscanf("-nan", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("-nan", "%le", &d)); ATF_REQUIRE(isnan(d)); /* Only quiet NaNs should be returned. */ - sscanf("NaN", "%e", &f); - sscanf("nan", "%le", &d); - sscanf("nan", "%Le", &ld); - feclearexcept(FE_ALL_EXCEPT); + ATF_REQUIRE_EQ(1, sscanf("NaN", "%e", &f)); + ATF_REQUIRE_EQ(1, sscanf("nan", "%le", &d)); + ATF_REQUIRE_EQ(1, sscanf("nan", "%Le", &ld)); + ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); ATF_REQUIRE(f != f); ATF_REQUIRE(d != d); ATF_REQUIRE(ld != ld); ATF_REQUIRE(fetestexcept(FE_INVALID) == 0); - sscanf("nan(1234)", "%e", &f); - sscanf("nan(1234)", "%le", &d); - sscanf("nan(1234)", "%Le", &ld); - feclearexcept(FE_ALL_EXCEPT); + ATF_REQUIRE_EQ(1, sscanf("nan(1234)", "%e", &f)); + ATF_REQUIRE_EQ(1, sscanf("nan(1234)", "%le", &d)); + ATF_REQUIRE_EQ(1, sscanf("nan(1234)", "%Le", &ld)); + ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); ATF_REQUIRE(f != f); ATF_REQUIRE(d != d); ATF_REQUIRE(ld != ld); @@ -208,74 +205,74 @@ ATF_TC_BODY(rounding_tests, tc) ATF_REQUIRE(setlocale(LC_NUMERIC, "C")); - fesetround(FE_DOWNWARD); + ATF_REQUIRE_EQ(0, fesetround(FE_DOWNWARD)); - sscanf("1.999999999999999999999999999999999", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("1.999999999999999999999999999999999", "%le", &d)); ATF_REQUIRE(d < 2.0); - sscanf("0x1.ffffffffffffffp0", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("0x1.ffffffffffffffp0", "%le", &d)); ATF_REQUIRE(d < 2.0); - sscanf("1.999999999999999999999999999999999", "%Le", &ld); + ATF_REQUIRE_EQ(1, sscanf("1.999999999999999999999999999999999", "%Le", &ld)); ATF_REQUIRE(ld < 2.0); - sscanf("1.0571892669084007", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("1.0571892669084007", "%le", &d)); ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0); - sscanf("-1.0571892669084007", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("-1.0571892669084007", "%le", &d)); ATF_REQUIRE(d == -0x1.0ea3f4af0dc5ap0); - sscanf("1.0571892669084010", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("1.0571892669084010", "%le", &d)); ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0); - sscanf("0x1.23p-5000", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("0x1.23p-5000", "%le", &d)); ATF_REQUIRE(d == 0.0); - sscanf("0x1.2345678p-1050", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("0x1.2345678p-1050", "%le", &d)); ATF_REQUIRE(d == 0x1.234567p-1050); - fesetround(FE_UPWARD); + ATF_REQUIRE_EQ(0, fesetround(FE_UPWARD)); - sscanf("1.0571892669084007", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("1.0571892669084007", "%le", &d)); ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0); - sscanf("-1.0571892669084007", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("-1.0571892669084007", "%le", &d)); ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0); - sscanf("1.0571892669084010", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("1.0571892669084010", "%le", &d)); ATF_REQUIRE(d == 0x1.0ea3f4af0dc5bp0); - sscanf("0x1.23p-5000", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("0x1.23p-5000", "%le", &d)); ATF_REQUIRE(d == 0x1p-1074); - sscanf("0x1.2345678p-1050", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("0x1.2345678p-1050", "%le", &d)); ATF_REQUIRE(d == 0x1.234568p-1050); - fesetround(FE_TOWARDZERO); + ATF_REQUIRE_EQ(0, fesetround(FE_TOWARDZERO)); - sscanf("1.0571892669084007", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("1.0571892669084007", "%le", &d)); ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0); - sscanf("-1.0571892669084007", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("-1.0571892669084007", "%le", &d)); ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0); - sscanf("1.0571892669084010", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("1.0571892669084010", "%le", &d)); ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0); - sscanf("0x1.23p-5000", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("0x1.23p-5000", "%le", &d)); ATF_REQUIRE(d == 0.0); - sscanf("0x1.2345678p-1050", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("0x1.2345678p-1050", "%le", &d)); ATF_REQUIRE(d == 0x1.234567p-1050); - fesetround(FE_TONEAREST); + ATF_REQUIRE_EQ(0, fesetround(FE_TONEAREST)); /* 1.0571892669084007 is slightly closer to 0x1.0ea3f4af0dc59p0 */ - sscanf("1.0571892669084007", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("1.0571892669084007", "%le", &d)); ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0); - sscanf("-1.0571892669084007", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("-1.0571892669084007", "%le", &d)); ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0); - sscanf("1.0571892669084010", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("1.0571892669084010", "%le", &d)); ATF_REQUIRE(d == 0x1.0ea3f4af0dc5bp0); /* strtod() should round small numbers to 0. */ - sscanf("0x1.23p-5000", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("0x1.23p-5000", "%le", &d)); ATF_REQUIRE(d == 0.0); /* Extra digits in a denormal shouldn't break anything. */ - sscanf("0x1.2345678p-1050", "%le", &d); + ATF_REQUIRE_EQ(1, sscanf("0x1.2345678p-1050", "%le", &d)); ATF_REQUIRE(d == 0x1.234568p-1050); } @@ -290,16 +287,16 @@ ATF_TC_BODY(strtod, tc) ATF_REQUIRE(strcmp("xy", endp) == 0); /* This used to cause an infinite loop and round the wrong way. */ - fesetround(FE_DOWNWARD); + ATF_REQUIRE_EQ(0, fesetround(FE_DOWNWARD)); ATF_REQUIRE(strtof("3.5e38", &endp) == FLT_MAX); ATF_REQUIRE(strtod("2e308", &endp) == DBL_MAX); - fesetround(FE_UPWARD); + ATF_REQUIRE_EQ(0, fesetround(FE_UPWARD)); ATF_REQUIRE(strtof("3.5e38", &endp) == INFINITY); ATF_REQUIRE(strtod("2e308", &endp) == INFINITY); - fesetround(FE_TOWARDZERO); + ATF_REQUIRE_EQ(0, fesetround(FE_TOWARDZERO)); ATF_REQUIRE(strtof("3.5e38", &endp) == FLT_MAX); ATF_REQUIRE(strtod("2e308", &endp) == DBL_MAX); - fesetround(FE_TONEAREST); + ATF_REQUIRE_EQ(0, fesetround(FE_TONEAREST)); ATF_REQUIRE(strtof("3.5e38", &endp) == INFINITY); ATF_REQUIRE(strtod("2e308", &endp) == INFINITY); } diff --git a/lib/libc/tests/stdio/snprintf_test.c b/lib/libc/tests/stdio/snprintf_test.c new file mode 100644 index 000000000000..29b908b65120 --- /dev/null +++ b/lib/libc/tests/stdio/snprintf_test.c @@ -0,0 +1,205 @@ +/*- + * Copyright (c) 2023 Dag-Erling Smørgrav + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <assert.h> +#include <limits.h> +#include <locale.h> +#include <stdint.h> +#include <stdio.h> + +#include <atf-c.h> + +#ifndef nitems +#define nitems(a) (sizeof(a) / sizeof(a[0])) +#endif + +#define SNPRINTF_TEST(output, format, ...) \ + do { \ + char buf[256]; \ + assert(strlen(output) < nitems(buf)); \ + int ret = snprintf(buf, nitems(buf), format, \ + __VA_ARGS__); \ + ATF_CHECK_EQ(strlen(output), ret); \ + if (ret > 0) { \ + ATF_CHECK_EQ(0, strcmp(output, buf)); \ + } \ + } while (0) + +ATF_TC_WITHOUT_HEAD(snprintf_b); +ATF_TC_BODY(snprintf_b, tc) +{ + SNPRINTF_TEST("0", "%b", 0); + SNPRINTF_TEST(" 0", "%12b", 0); + SNPRINTF_TEST("000000000000", "%012b", 0); + SNPRINTF_TEST("1", "%b", 1); + SNPRINTF_TEST(" 1", "%12b", 1); + SNPRINTF_TEST("000000000001", "%012b", 1); + SNPRINTF_TEST("1111111111111111111111111111111", "%b", INT_MAX); + SNPRINTF_TEST("0", "%#b", 0); + SNPRINTF_TEST(" 0", "%#12b", 0); + SNPRINTF_TEST("000000000000", "%#012b", 0); + SNPRINTF_TEST("0b1", "%#b", 1); + SNPRINTF_TEST(" 0b1", "%#12b", 1); + SNPRINTF_TEST("0b0000000001", "%#012b", 1); + SNPRINTF_TEST("0b1111111111111111111111111111111", "%#b", INT_MAX); +} + +ATF_TC_WITHOUT_HEAD(snprintf_B); +ATF_TC_BODY(snprintf_B, tc) +{ + SNPRINTF_TEST("0", "%B", 0); + SNPRINTF_TEST(" 0", "%12B", 0); + SNPRINTF_TEST("000000000000", "%012B", 0); + SNPRINTF_TEST("1", "%B", 1); + SNPRINTF_TEST(" 1", "%12B", 1); + SNPRINTF_TEST("000000000001", "%012B", 1); + SNPRINTF_TEST("1111111111111111111111111111111", "%B", INT_MAX); + SNPRINTF_TEST("0", "%#B", 0); + SNPRINTF_TEST(" 0", "%#12B", 0); + SNPRINTF_TEST("000000000000", "%#012B", 0); + SNPRINTF_TEST("0B1", "%#B", 1); + SNPRINTF_TEST(" 0B1", "%#12B", 1); + SNPRINTF_TEST("0B0000000001", "%#012B", 1); + SNPRINTF_TEST("0B1111111111111111111111111111111", "%#B", INT_MAX); +} + +ATF_TC_WITHOUT_HEAD(snprintf_d); +ATF_TC_BODY(snprintf_d, tc) +{ + SNPRINTF_TEST("0", "%d", 0); + SNPRINTF_TEST(" 0", "%12d", 0); + SNPRINTF_TEST("000000000000", "%012d", 0); + SNPRINTF_TEST("1", "%d", 1); + SNPRINTF_TEST(" 1", "%12d", 1); + SNPRINTF_TEST("000000000001", "%012d", 1); + SNPRINTF_TEST("2147483647", "%d", INT_MAX); + SNPRINTF_TEST(" 2147483647", "%12d", INT_MAX); + SNPRINTF_TEST("002147483647", "%012d", INT_MAX); + SNPRINTF_TEST("2,147,483,647", "%'d", INT_MAX); +} + +ATF_TC_WITHOUT_HEAD(snprintf_x); +ATF_TC_BODY(snprintf_x, tc) +{ + SNPRINTF_TEST("0", "%x", 0); + SNPRINTF_TEST(" 0", "%12x", 0); + SNPRINTF_TEST("000000000000", "%012x", 0); + SNPRINTF_TEST("1", "%x", 1); + SNPRINTF_TEST(" 1", "%12x", 1); + SNPRINTF_TEST("000000000001", "%012x", 1); + SNPRINTF_TEST("7fffffff", "%x", INT_MAX); + SNPRINTF_TEST(" 7fffffff", "%12x", INT_MAX); + SNPRINTF_TEST("00007fffffff", "%012x", INT_MAX); + SNPRINTF_TEST("0", "%#x", 0); + SNPRINTF_TEST(" 0", "%#12x", 0); + SNPRINTF_TEST("000000000000", "%#012x", 0); + SNPRINTF_TEST("0x1", "%#x", 1); + SNPRINTF_TEST(" 0x1", "%#12x", 1); + SNPRINTF_TEST("0x0000000001", "%#012x", 1); + SNPRINTF_TEST("0x7fffffff", "%#x", INT_MAX); + SNPRINTF_TEST(" 0x7fffffff", "%#12x", INT_MAX); + SNPRINTF_TEST("0x007fffffff", "%#012x", INT_MAX); +} + +ATF_TC_WITHOUT_HEAD(snprintf_X); +ATF_TC_BODY(snprintf_X, tc) +{ + SNPRINTF_TEST("0", "%X", 0); + SNPRINTF_TEST(" 0", "%12X", 0); + SNPRINTF_TEST("000000000000", "%012X", 0); + SNPRINTF_TEST("1", "%X", 1); + SNPRINTF_TEST(" 1", "%12X", 1); + SNPRINTF_TEST("000000000001", "%012X", 1); + SNPRINTF_TEST("7FFFFFFF", "%X", INT_MAX); + SNPRINTF_TEST(" 7FFFFFFF", "%12X", INT_MAX); + SNPRINTF_TEST("00007FFFFFFF", "%012X", INT_MAX); + SNPRINTF_TEST("0", "%#X", 0); + SNPRINTF_TEST(" 0", "%#12X", 0); + SNPRINTF_TEST("000000000000", "%#012X", 0); + SNPRINTF_TEST("0X1", "%#X", 1); + SNPRINTF_TEST(" 0X1", "%#12X", 1); + SNPRINTF_TEST("0X0000000001", "%#012X", 1); + SNPRINTF_TEST("0X7FFFFFFF", "%#X", INT_MAX); + SNPRINTF_TEST(" 0X7FFFFFFF", "%#12X", INT_MAX); + SNPRINTF_TEST("0X007FFFFFFF", "%#012X", INT_MAX); +} + +ATF_TC_WITHOUT_HEAD(snprintf_wN); +ATF_TC_BODY(snprintf_wN, tc) +{ + SNPRINTF_TEST("0", "%w8d", (int8_t)0); + SNPRINTF_TEST("-128", "%w8d", (int8_t)SCHAR_MIN); + SNPRINTF_TEST("127", "%w8d", (int8_t)SCHAR_MAX); + SNPRINTF_TEST("0", "%w8u", (uint8_t)0); + SNPRINTF_TEST("255", "%w8u", (uint8_t)UCHAR_MAX); + + SNPRINTF_TEST("0", "%w16d", (int16_t)0); + SNPRINTF_TEST("-32768", "%w16d", (int16_t)SHRT_MIN); + SNPRINTF_TEST("32767", "%w16d", (int16_t)SHRT_MAX); + SNPRINTF_TEST("0", "%w16u", (uint16_t)0); + SNPRINTF_TEST("65535", "%w16u", (uint16_t)USHRT_MAX); + + SNPRINTF_TEST("0", "%w32d", (int32_t)0); + SNPRINTF_TEST("-2147483648", "%w32d", (int32_t)INT_MIN); + SNPRINTF_TEST("2147483647", "%w32d", (int32_t)INT_MAX); + SNPRINTF_TEST("0", "%w32u", (uint32_t)0); + SNPRINTF_TEST("4294967295", "%w32u", (uint32_t)UINT_MAX); + + SNPRINTF_TEST("0", "%w64d", (int64_t)0); + SNPRINTF_TEST("-9223372036854775808", "%w64d", (int64_t)LLONG_MIN); + SNPRINTF_TEST("9223372036854775807", "%w64d", (int64_t)LLONG_MAX); + SNPRINTF_TEST("0", "%w64u", (uint64_t)0); + SNPRINTF_TEST("18446744073709551615", "%w64u", (uint64_t)ULLONG_MAX); + + SNPRINTF_TEST("wd", "%wd", 0); + SNPRINTF_TEST("w1d", "%w1d", 0); + SNPRINTF_TEST("w128d", "%w128d", 0); +} + +ATF_TC_WITHOUT_HEAD(snprintf_wfN); +ATF_TC_BODY(snprintf_wfN, tc) +{ + SNPRINTF_TEST("0", "%wf8d", (int_fast8_t)0); + SNPRINTF_TEST("-2147483648", "%wf8d", (int_fast8_t)INT_MIN); + SNPRINTF_TEST("2147483647", "%wf8d", (int_fast8_t)INT_MAX); + SNPRINTF_TEST("0", "%wf8u", (uint8_t)0); + SNPRINTF_TEST("4294967295", "%wf8u", (uint_fast8_t)UINT_MAX); + + SNPRINTF_TEST("0", "%wf16d", (int_fast16_t)0); + SNPRINTF_TEST("-2147483648", "%wf16d", (int_fast16_t)INT_MIN); + SNPRINTF_TEST("2147483647", "%wf16d", (int_fast16_t)INT_MAX); + SNPRINTF_TEST("0", "%wf16u", (uint16_t)0); + SNPRINTF_TEST("4294967295", "%wf16u", (uint_fast16_t)UINT_MAX); + + SNPRINTF_TEST("0", "%wf32d", (int_fast32_t)0); + SNPRINTF_TEST("-2147483648", "%wf32d", (int_fast32_t)INT_MIN); + SNPRINTF_TEST("2147483647", "%wf32d", (int_fast32_t)INT_MAX); + SNPRINTF_TEST("0", "%wf32u", (uint32_t)0); + SNPRINTF_TEST("4294967295", "%wf32u", (uint_fast32_t)UINT_MAX); + + SNPRINTF_TEST("0", "%wf64d", (int_fast64_t)0); + SNPRINTF_TEST("-9223372036854775808", "%wf64d", (int_fast64_t)LLONG_MIN); + SNPRINTF_TEST("9223372036854775807", "%wf64d", (int_fast64_t)LLONG_MAX); + SNPRINTF_TEST("0", "%wf64u", (uint64_t)0); + SNPRINTF_TEST("18446744073709551615", "%wf64u", (uint_fast64_t)ULLONG_MAX); + + SNPRINTF_TEST("wfd", "%wfd", 0); + SNPRINTF_TEST("wf1d", "%wf1d", 0); + SNPRINTF_TEST("wf128d", "%wf128d", 0); +} + +ATF_TP_ADD_TCS(tp) +{ + setlocale(LC_NUMERIC, "en_US.UTF-8"); + ATF_TP_ADD_TC(tp, snprintf_b); + ATF_TP_ADD_TC(tp, snprintf_B); + ATF_TP_ADD_TC(tp, snprintf_d); + ATF_TP_ADD_TC(tp, snprintf_x); + ATF_TP_ADD_TC(tp, snprintf_X); + ATF_TP_ADD_TC(tp, snprintf_wN); + ATF_TP_ADD_TC(tp, snprintf_wfN); + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdio/sscanf_test.c b/lib/libc/tests/stdio/sscanf_test.c new file mode 100644 index 000000000000..e43292820eeb --- /dev/null +++ b/lib/libc/tests/stdio/sscanf_test.c @@ -0,0 +1,356 @@ +/*- + * Copyright (c) 2023 Dag-Erling Smørgrav + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <limits.h> +#include <locale.h> +#include <stdint.h> +#include <stdio.h> + +#include <atf-c.h> + +static const struct sscanf_test_case { + char input[8]; + struct { + int ret, val, len; + } b, o, d, x, i; +} sscanf_test_cases[] = { +// input binary octal decimal hexadecimal automatic + // all digits + { "0", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, }, + { "1", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, }, + { "2", { 0, 0, 0 }, { 1, 2, 1 }, { 1, 2, 1 }, { 1, 2, 1 }, { 1, 2, 1 }, }, + { "3", { 0, 0, 0 }, { 1, 3, 1 }, { 1, 3, 1 }, { 1, 3, 1 }, { 1, 3, 1 }, }, + { "4", { 0, 0, 0 }, { 1, 4, 1 }, { 1, 4, 1 }, { 1, 4, 1 }, { 1, 4, 1 }, }, + { "5", { 0, 0, 0 }, { 1, 5, 1 }, { 1, 5, 1 }, { 1, 5, 1 }, { 1, 5, 1 }, }, + { "6", { 0, 0, 0 }, { 1, 6, 1 }, { 1, 6, 1 }, { 1, 6, 1 }, { 1, 6, 1 }, }, + { "7", { 0, 0, 0 }, { 1, 7, 1 }, { 1, 7, 1 }, { 1, 7, 1 }, { 1, 7, 1 }, }, + { "8", { 0, 0, 0 }, { 0, 0, 0 }, { 1, 8, 1 }, { 1, 8, 1 }, { 1, 8, 1 }, }, + { "9", { 0, 0, 0 }, { 0, 0, 0 }, { 1, 9, 1 }, { 1, 9, 1 }, { 1, 9, 1 }, }, + { "A", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 10, 1 }, { 0, 0, 0 }, }, + { "B", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 11, 1 }, { 0, 0, 0 }, }, + { "C", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 12, 1 }, { 0, 0, 0 }, }, + { "D", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 13, 1 }, { 0, 0, 0 }, }, + { "E", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 14, 1 }, { 0, 0, 0 }, }, + { "F", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 15, 1 }, { 0, 0, 0 }, }, + { "X", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, }, + { "a", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 10, 1 }, { 0, 0, 0 }, }, + { "b", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 11, 1 }, { 0, 0, 0 }, }, + { "c", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 12, 1 }, { 0, 0, 0 }, }, + { "d", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 13, 1 }, { 0, 0, 0 }, }, + { "e", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 14, 1 }, { 0, 0, 0 }, }, + { "f", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 15, 1 }, { 0, 0, 0 }, }, + { "x", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, }, + // all digits with leading zero + { "00", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, }, + { "01", { 1, 1, 2 }, { 1, 1, 2 }, { 1, 1, 2 }, { 1, 1, 2 }, { 1, 1, 2 }, }, + { "02", { 1, 0, 1 }, { 1, 2, 2 }, { 1, 2, 2 }, { 1, 2, 2 }, { 1, 2, 2 }, }, + { "03", { 1, 0, 1 }, { 1, 3, 2 }, { 1, 3, 2 }, { 1, 3, 2 }, { 1, 3, 2 }, }, + { "04", { 1, 0, 1 }, { 1, 4, 2 }, { 1, 4, 2 }, { 1, 4, 2 }, { 1, 4, 2 }, }, + { "05", { 1, 0, 1 }, { 1, 5, 2 }, { 1, 5, 2 }, { 1, 5, 2 }, { 1, 5, 2 }, }, + { "06", { 1, 0, 1 }, { 1, 6, 2 }, { 1, 6, 2 }, { 1, 6, 2 }, { 1, 6, 2 }, }, + { "07", { 1, 0, 1 }, { 1, 7, 2 }, { 1, 7, 2 }, { 1, 7, 2 }, { 1, 7, 2 }, }, + { "08", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 8, 2 }, { 1, 8, 2 }, { 1, 0, 1 }, }, + { "09", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 9, 2 }, { 1, 9, 2 }, { 1, 0, 1 }, }, + { "0A", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 10, 2 }, { 1, 0, 1 }, }, + { "0B", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 11, 2 }, { 1, 0, 1 }, }, + { "0C", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 12, 2 }, { 1, 0, 1 }, }, + { "0D", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 13, 2 }, { 1, 0, 1 }, }, + { "0E", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 14, 2 }, { 1, 0, 1 }, }, + { "0F", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 15, 2 }, { 1, 0, 1 }, }, + { "0X", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, }, + { "0a", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 10, 2 }, { 1, 0, 1 }, }, + { "0b", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 11, 2 }, { 1, 0, 1 }, }, + { "0c", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 12, 2 }, { 1, 0, 1 }, }, + { "0d", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 13, 2 }, { 1, 0, 1 }, }, + { "0e", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 14, 2 }, { 1, 0, 1 }, }, + { "0f", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 15, 2 }, { 1, 0, 1 }, }, + { "0x", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, }, + // all digits with two leading zeroes + { "000", { 1, 0, 3 }, { 1, 0, 3 }, { 1, 0, 3 }, { 1, 0, 3 }, { 1, 0, 3 }, }, + { "001", { 1, 1, 3 }, { 1, 1, 3 }, { 1, 1, 3 }, { 1, 1, 3 }, { 1, 1, 3 }, }, + { "002", { 1, 0, 2 }, { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 }, }, + { "003", { 1, 0, 2 }, { 1, 3, 3 }, { 1, 3, 3 }, { 1, 3, 3 }, { 1, 3, 3 }, }, + { "004", { 1, 0, 2 }, { 1, 4, 3 }, { 1, 4, 3 }, { 1, 4, 3 }, { 1, 4, 3 }, }, + { "005", { 1, 0, 2 }, { 1, 5, 3 }, { 1, 5, 3 }, { 1, 5, 3 }, { 1, 5, 3 }, }, + { "006", { 1, 0, 2 }, { 1, 6, 3 }, { 1, 6, 3 }, { 1, 6, 3 }, { 1, 6, 3 }, }, + { "007", { 1, 0, 2 }, { 1, 7, 3 }, { 1, 7, 3 }, { 1, 7, 3 }, { 1, 7, 3 }, }, + { "008", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 8, 3 }, { 1, 8, 3 }, { 1, 0, 2 }, }, + { "009", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 9, 3 }, { 1, 9, 3 }, { 1, 0, 2 }, }, + { "00A", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 10, 3 }, { 1, 0, 2 }, }, + { "00B", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 11, 3 }, { 1, 0, 2 }, }, + { "00C", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 12, 3 }, { 1, 0, 2 }, }, + { "00D", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 13, 3 }, { 1, 0, 2 }, }, + { "00E", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 14, 3 }, { 1, 0, 2 }, }, + { "00F", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 15, 3 }, { 1, 0, 2 }, }, + { "00X", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, }, + { "00a", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 10, 3 }, { 1, 0, 2 }, }, + { "00b", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 11, 3 }, { 1, 0, 2 }, }, + { "00c", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 12, 3 }, { 1, 0, 2 }, }, + { "00d", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 13, 3 }, { 1, 0, 2 }, }, + { "00e", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 14, 3 }, { 1, 0, 2 }, }, + { "00f", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 15, 3 }, { 1, 0, 2 }, }, + { "00x", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, }, + // all digits with leading one + { "10", { 1, 2, 2 }, { 1, 8, 2 }, { 1, 10, 2 }, { 1, 16, 2 }, { 1, 10, 2 }, }, + { "11", { 1, 3, 2 }, { 1, 9, 2 }, { 1, 11, 2 }, { 1, 17, 2 }, { 1, 11, 2 }, }, + { "12", { 1, 1, 1 }, { 1, 10, 2 }, { 1, 12, 2 }, { 1, 18, 2 }, { 1, 12, 2 }, }, + { "13", { 1, 1, 1 }, { 1, 11, 2 }, { 1, 13, 2 }, { 1, 19, 2 }, { 1, 13, 2 }, }, + { "14", { 1, 1, 1 }, { 1, 12, 2 }, { 1, 14, 2 }, { 1, 20, 2 }, { 1, 14, 2 }, }, + { "15", { 1, 1, 1 }, { 1, 13, 2 }, { 1, 15, 2 }, { 1, 21, 2 }, { 1, 15, 2 }, }, + { "16", { 1, 1, 1 }, { 1, 14, 2 }, { 1, 16, 2 }, { 1, 22, 2 }, { 1, 16, 2 }, }, + { "17", { 1, 1, 1 }, { 1, 15, 2 }, { 1, 17, 2 }, { 1, 23, 2 }, { 1, 17, 2 }, }, + { "18", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 18, 2 }, { 1, 24, 2 }, { 1, 18, 2 }, }, + { "19", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 19, 2 }, { 1, 25, 2 }, { 1, 19, 2 }, }, + { "1A", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 26, 2 }, { 1, 1, 1 }, }, + { "1B", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 27, 2 }, { 1, 1, 1 }, }, + { "1C", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 28, 2 }, { 1, 1, 1 }, }, + { "1D", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 29, 2 }, { 1, 1, 1 }, }, + { "1E", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 30, 2 }, { 1, 1, 1 }, }, + { "1F", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 31, 2 }, { 1, 1, 1 }, }, + { "1X", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, }, + { "1a", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 26, 2 }, { 1, 1, 1 }, }, + { "1b", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 27, 2 }, { 1, 1, 1 }, }, + { "1c", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 28, 2 }, { 1, 1, 1 }, }, + { "1d", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 29, 2 }, { 1, 1, 1 }, }, + { "1e", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 30, 2 }, { 1, 1, 1 }, }, + { "1f", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 31, 2 }, { 1, 1, 1 }, }, + { "1x", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, }, + // all digits with leading binary prefix + { "0b0", { 1, 0, 3 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 176, 3 }, { 1, 0, 3 }, }, + { "0b1", { 1, 1, 3 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 177, 3 }, { 1, 1, 3 }, }, + { "0b2", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 178, 3 }, { 1, 0, 1 }, }, + { "0b3", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 179, 3 }, { 1, 0, 1 }, }, + { "0b4", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 180, 3 }, { 1, 0, 1 }, }, + { "0b5", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 181, 3 }, { 1, 0, 1 }, }, + { "0b6", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 182, 3 }, { 1, 0, 1 }, }, + { "0b7", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 183, 3 }, { 1, 0, 1 }, }, + { "0b8", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 184, 3 }, { 1, 0, 1 }, }, + { "0b9", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 185, 3 }, { 1, 0, 1 }, }, + { "0bA", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 186, 3 }, { 1, 0, 1 }, }, + { "0bB", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 187, 3 }, { 1, 0, 1 }, }, + { "0bC", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 188, 3 }, { 1, 0, 1 }, }, + { "0bD", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 189, 3 }, { 1, 0, 1 }, }, + { "0bE", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 190, 3 }, { 1, 0, 1 }, }, + { "0bF", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 191, 3 }, { 1, 0, 1 }, }, + { "0bX", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 11, 2 }, { 1, 0, 1 }, }, + { "0ba", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 186, 3 }, { 1, 0, 1 }, }, + { "0bb", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 187, 3 }, { 1, 0, 1 }, }, + { "0bc", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 188, 3 }, { 1, 0, 1 }, }, + { "0bd", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 189, 3 }, { 1, 0, 1 }, }, + { "0be", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 190, 3 }, { 1, 0, 1 }, }, + { "0bf", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 191, 3 }, { 1, 0, 1 }, }, + { "0bx", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 11, 2 }, { 1, 0, 1 }, }, + // all digits with leading hexadecimal prefix + { "0x0", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 3 }, { 1, 0, 3 }, }, + { "0x1", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 1, 3 }, { 1, 1, 3 }, }, + { "0x2", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 2, 3 }, { 1, 2, 3 }, }, + { "0x3", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 3, 3 }, { 1, 3, 3 }, }, + { "0x4", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 4, 3 }, { 1, 4, 3 }, }, + { "0x5", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 5, 3 }, { 1, 5, 3 }, }, + { "0x6", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 6, 3 }, { 1, 6, 3 }, }, + { "0x7", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 7, 3 }, { 1, 7, 3 }, }, + { "0x8", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 8, 3 }, { 1, 8, 3 }, }, + { "0x9", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 9, 3 }, { 1, 9, 3 }, }, + { "0xA", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 10, 3 }, { 1, 10, 3 }, }, + { "0xB", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 11, 3 }, { 1, 11, 3 }, }, + { "0xC", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 12, 3 }, { 1, 12, 3 }, }, + { "0xD", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 13, 3 }, { 1, 13, 3 }, }, + { "0xE", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 14, 3 }, { 1, 14, 3 }, }, + { "0xF", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 15, 3 }, { 1, 15, 3 }, }, + { "0xX", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, }, + { "0xa", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 10, 3 }, { 1, 10, 3 }, }, + { "0xb", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 11, 3 }, { 1, 11, 3 }, }, + { "0xc", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 12, 3 }, { 1, 12, 3 }, }, + { "0xd", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 13, 3 }, { 1, 13, 3 }, }, + { "0xe", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 14, 3 }, { 1, 14, 3 }, }, + { "0xf", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 15, 3 }, { 1, 15, 3 }, }, + { "0xX", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, }, + // terminator + { "" } +}; + +#define SSCANF_TEST(string, format, expret, expval, explen) \ + do { \ + int ret = 0, val = 0, len = 0; \ + ret = sscanf(string, format "%n", &val, &len); \ + ATF_CHECK_EQ(expret, ret); \ + if (expret && ret) { \ + ATF_CHECK_EQ(expval, val); \ + ATF_CHECK_EQ(explen, len); \ + } \ + } while (0) + +ATF_TC_WITHOUT_HEAD(sscanf_b); +ATF_TC_BODY(sscanf_b, tc) +{ + const struct sscanf_test_case *stc; + char input[16]; + + for (stc = sscanf_test_cases; *stc->input; stc++) { + strcpy(input + 1, stc->input); + SSCANF_TEST(input + 1, "%b", stc->b.ret, stc->b.val, stc->b.len); + input[0] = '+'; + SSCANF_TEST(input, "%b", stc->b.ret, stc->b.val, stc->b.len ? stc->b.len + 1 : 0); + input[0] = '-'; + SSCANF_TEST(input, "%b", stc->b.ret, -stc->b.val, stc->b.len ? stc->b.len + 1 : 0); + } +} + +ATF_TC_WITHOUT_HEAD(sscanf_o); +ATF_TC_BODY(sscanf_o, tc) +{ + const struct sscanf_test_case *stc; + char input[16]; + + for (stc = sscanf_test_cases; *stc->input; stc++) { + strcpy(input + 1, stc->input); + SSCANF_TEST(input + 1, "%o", stc->o.ret, stc->o.val, stc->o.len); + input[0] = '+'; + SSCANF_TEST(input, "%o", stc->o.ret, stc->o.val, stc->o.len ? stc->o.len + 1 : 0); + input[0] = '-'; + SSCANF_TEST(input, "%o", stc->o.ret, -stc->o.val, stc->o.len ? stc->o.len + 1 : 0); + } +} + +ATF_TC_WITHOUT_HEAD(sscanf_d); +ATF_TC_BODY(sscanf_d, tc) +{ + const struct sscanf_test_case *stc; + char input[16]; + + for (stc = sscanf_test_cases; *stc->input; stc++) { + strcpy(input + 1, stc->input); + SSCANF_TEST(input + 1, "%d", stc->d.ret, stc->d.val, stc->d.len); + input[0] = '+'; + SSCANF_TEST(input, "%d", stc->d.ret, stc->d.val, stc->d.len ? stc->d.len + 1 : 0); + input[0] = '-'; + SSCANF_TEST(input, "%d", stc->d.ret, -stc->d.val, stc->d.len ? stc->d.len + 1 : 0); + } +} + +ATF_TC_WITHOUT_HEAD(sscanf_x); +ATF_TC_BODY(sscanf_x, tc) +{ + const struct sscanf_test_case *stc; + char input[16]; + + for (stc = sscanf_test_cases; *stc->input; stc++) { + strcpy(input + 1, stc->input); + SSCANF_TEST(input + 1, "%x", stc->x.ret, stc->x.val, stc->x.len); + input[0] = '+'; + SSCANF_TEST(input, "%x", stc->x.ret, stc->x.val, stc->x.len ? stc->x.len + 1 : 0); + input[0] = '-'; + SSCANF_TEST(input, "%x", stc->x.ret, -stc->x.val, stc->x.len ? stc->x.len + 1 : 0); + } +} + +ATF_TC_WITHOUT_HEAD(sscanf_i); +ATF_TC_BODY(sscanf_i, tc) +{ + const struct sscanf_test_case *stc; + char input[16]; + + for (stc = sscanf_test_cases; *stc->input; stc++) { + strcpy(input + 1, stc->input); + SSCANF_TEST(input + 1, "%i", stc->i.ret, stc->i.val, stc->i.len); + input[0] = '+'; + SSCANF_TEST(input, "%i", stc->i.ret, stc->i.val, stc->i.len ? stc->i.len + 1 : 0); + input[0] = '-'; + SSCANF_TEST(input, "%i", stc->i.ret, -stc->i.val, stc->i.len ? stc->i.len + 1 : 0); + } +} + +ATF_TC_WITHOUT_HEAD(sscanf_wN); +ATF_TC_BODY(sscanf_wN, tc) +{ + const char x00[] = "0x00"; + const char x7f[] = "0x7fffffffffffffff"; + const char xff[] = "0xffffffffffffffff"; + +#define SSCANF_WN_TEST(N, imin, umax) \ + do { \ + int##N##_t i; \ + uint##N##_t u; \ + ATF_CHECK_EQ(1, sscanf(x00, "%w" #N "i", &i)); \ + ATF_CHECK_EQ(0, i); \ + ATF_CHECK_EQ(1, sscanf(x7f, "%w" #N "i", &i)); \ + ATF_CHECK_EQ(imin, i); \ + ATF_CHECK_EQ(1, sscanf(x00, "%w" #N "x", &u)); \ + ATF_CHECK_EQ(0, u); \ + ATF_CHECK_EQ(1, sscanf(xff, "%w" #N "x", &u)); \ + ATF_CHECK_EQ(umax, u); \ + } while (0) + SSCANF_WN_TEST(8, -1, UCHAR_MAX); + SSCANF_WN_TEST(16, -1, USHRT_MAX); + SSCANF_WN_TEST(32, -1, UINT_MAX); + SSCANF_WN_TEST(64, LLONG_MAX, ULLONG_MAX); +#undef SSCANF_WN_TEST + + ATF_CHECK_EQ(0, sscanf(x00, "%wi", (int *)NULL)); + ATF_CHECK_EQ(0, sscanf(x00, "%w1i", (int *)NULL)); + ATF_CHECK_EQ(0, sscanf(x00, "%w128i", (int *)NULL)); +} + +ATF_TC_WITHOUT_HEAD(sscanf_wfN); +ATF_TC_BODY(sscanf_wfN, tc) +{ + const char x00[] = "0x00"; + const char x7f[] = "0x7fffffffffffffff"; + const char xff[] = "0xffffffffffffffff"; + +#define SSCANF_WFN_TEST(N, imin, umax) \ + do { \ + int_fast##N##_t i; \ + uint_fast##N##_t u; \ + ATF_CHECK_EQ(1, sscanf(x00, "%wf" #N "i", &i)); \ + ATF_CHECK_EQ(0, i); \ + ATF_CHECK_EQ(1, sscanf(x7f, "%wf" #N "i", &i)); \ + ATF_CHECK_EQ(imin, i); \ + ATF_CHECK_EQ(1, sscanf(x00, "%wf" #N "x", &u)); \ + ATF_CHECK_EQ(0, u); \ + ATF_CHECK_EQ(1, sscanf(xff, "%wf" #N "x", &u)); \ + ATF_CHECK_EQ(umax, u); \ + } while (0) + SSCANF_WFN_TEST(8, -1, UINT_MAX); + SSCANF_WFN_TEST(16, -1, UINT_MAX); + SSCANF_WFN_TEST(32, -1, UINT_MAX); + SSCANF_WFN_TEST(64, LLONG_MAX, ULLONG_MAX); +#undef SSCANF_WFN_TEST + + ATF_CHECK_EQ(0, sscanf(x00, "%wfi", (int *)NULL)); + ATF_CHECK_EQ(0, sscanf(x00, "%wf1i", (int *)NULL)); + ATF_CHECK_EQ(0, sscanf(x00, "%wf128i", (int *)NULL)); +} + +/* + * Test termination cases: non-numeric character, fixed width, EOF + */ +ATF_TC_WITHOUT_HEAD(sscanf_termination); +ATF_TC_BODY(sscanf_termination, tc) +{ + int a = 0, b = 0, c = 0; + char d = 0; + + ATF_CHECK_EQ(4, sscanf("3.1415", "%d%c%2d%d", &a, &d, &b, &c)); + ATF_CHECK_EQ(3, a); + ATF_CHECK_EQ(14, b); + ATF_CHECK_EQ(15, c); + ATF_CHECK_EQ('.', d); +} + +ATF_TP_ADD_TCS(tp) +{ + setlocale(LC_NUMERIC, "en_US.UTF-8"); + ATF_TP_ADD_TC(tp, sscanf_b); + ATF_TP_ADD_TC(tp, sscanf_o); + ATF_TP_ADD_TC(tp, sscanf_d); + ATF_TP_ADD_TC(tp, sscanf_x); + ATF_TP_ADD_TC(tp, sscanf_i); + ATF_TP_ADD_TC(tp, sscanf_wN); + ATF_TP_ADD_TC(tp, sscanf_wfN); + ATF_TP_ADD_TC(tp, sscanf_termination); + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdio/swprintf_test.c b/lib/libc/tests/stdio/swprintf_test.c new file mode 100644 index 000000000000..f00ecc7f1c1d --- /dev/null +++ b/lib/libc/tests/stdio/swprintf_test.c @@ -0,0 +1,206 @@ +/*- + * Copyright (c) 2023 Dag-Erling Smørgrav + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <assert.h> +#include <limits.h> +#include <locale.h> +#include <stdint.h> +#include <stdio.h> +#include <wchar.h> + +#include <atf-c.h> + +#ifndef nitems +#define nitems(a) (sizeof(a) / sizeof(a[0])) +#endif + +#define SWPRINTF_TEST(output, format, ...) \ + do { \ + wchar_t buf[256]; \ + assert(wcslen(L##output) < nitems(buf)); \ + int ret = swprintf(buf, nitems(buf), L##format, \ + __VA_ARGS__); \ + ATF_CHECK_EQ(wcslen(L##output), ret); \ + if (ret > 0) { \ + ATF_CHECK_EQ(0, wcscmp(L##output, buf)); \ + } \ + } while (0) + +ATF_TC_WITHOUT_HEAD(swprintf_b); +ATF_TC_BODY(swprintf_b, tc) +{ + SWPRINTF_TEST("0", "%b", 0); + SWPRINTF_TEST(" 0", "%12b", 0); + SWPRINTF_TEST("000000000000", "%012b", 0); + SWPRINTF_TEST("1", "%b", 1); + SWPRINTF_TEST(" 1", "%12b", 1); + SWPRINTF_TEST("000000000001", "%012b", 1); + SWPRINTF_TEST("1111111111111111111111111111111", "%b", INT_MAX); + SWPRINTF_TEST("0", "%#b", 0); + SWPRINTF_TEST(" 0", "%#12b", 0); + SWPRINTF_TEST("000000000000", "%#012b", 0); + SWPRINTF_TEST("0b1", "%#b", 1); + SWPRINTF_TEST(" 0b1", "%#12b", 1); + SWPRINTF_TEST("0b0000000001", "%#012b", 1); + SWPRINTF_TEST("0b1111111111111111111111111111111", "%#b", INT_MAX); +} + +ATF_TC_WITHOUT_HEAD(swprintf_B); +ATF_TC_BODY(swprintf_B, tc) +{ + SWPRINTF_TEST("0", "%B", 0); + SWPRINTF_TEST(" 0", "%12B", 0); + SWPRINTF_TEST("000000000000", "%012B", 0); + SWPRINTF_TEST("1", "%B", 1); + SWPRINTF_TEST(" 1", "%12B", 1); + SWPRINTF_TEST("000000000001", "%012B", 1); + SWPRINTF_TEST("1111111111111111111111111111111", "%B", INT_MAX); + SWPRINTF_TEST("0", "%#B", 0); + SWPRINTF_TEST(" 0", "%#12B", 0); + SWPRINTF_TEST("000000000000", "%#012B", 0); + SWPRINTF_TEST("0B1", "%#B", 1); + SWPRINTF_TEST(" 0B1", "%#12B", 1); + SWPRINTF_TEST("0B0000000001", "%#012B", 1); + SWPRINTF_TEST("0B1111111111111111111111111111111", "%#B", INT_MAX); +} + +ATF_TC_WITHOUT_HEAD(swprintf_d); +ATF_TC_BODY(swprintf_d, tc) +{ + SWPRINTF_TEST("0", "%d", 0); + SWPRINTF_TEST(" 0", "%12d", 0); + SWPRINTF_TEST("000000000000", "%012d", 0); + SWPRINTF_TEST("1", "%d", 1); + SWPRINTF_TEST(" 1", "%12d", 1); + SWPRINTF_TEST("000000000001", "%012d", 1); + SWPRINTF_TEST("2147483647", "%d", INT_MAX); + SWPRINTF_TEST(" 2147483647", "%12d", INT_MAX); + SWPRINTF_TEST("002147483647", "%012d", INT_MAX); + SWPRINTF_TEST("2,147,483,647", "%'d", INT_MAX); +} + +ATF_TC_WITHOUT_HEAD(swprintf_x); +ATF_TC_BODY(swprintf_x, tc) +{ + SWPRINTF_TEST("0", "%x", 0); + SWPRINTF_TEST(" 0", "%12x", 0); + SWPRINTF_TEST("000000000000", "%012x", 0); + SWPRINTF_TEST("1", "%x", 1); + SWPRINTF_TEST(" 1", "%12x", 1); + SWPRINTF_TEST("000000000001", "%012x", 1); + SWPRINTF_TEST("7fffffff", "%x", INT_MAX); + SWPRINTF_TEST(" 7fffffff", "%12x", INT_MAX); + SWPRINTF_TEST("00007fffffff", "%012x", INT_MAX); + SWPRINTF_TEST("0", "%#x", 0); + SWPRINTF_TEST(" 0", "%#12x", 0); + SWPRINTF_TEST("000000000000", "%#012x", 0); + SWPRINTF_TEST("0x1", "%#x", 1); + SWPRINTF_TEST(" 0x1", "%#12x", 1); + SWPRINTF_TEST("0x0000000001", "%#012x", 1); + SWPRINTF_TEST("0x7fffffff", "%#x", INT_MAX); + SWPRINTF_TEST(" 0x7fffffff", "%#12x", INT_MAX); + SWPRINTF_TEST("0x007fffffff", "%#012x", INT_MAX); +} + +ATF_TC_WITHOUT_HEAD(swprintf_X); +ATF_TC_BODY(swprintf_X, tc) +{ + SWPRINTF_TEST("0", "%X", 0); + SWPRINTF_TEST(" 0", "%12X", 0); + SWPRINTF_TEST("000000000000", "%012X", 0); + SWPRINTF_TEST("1", "%X", 1); + SWPRINTF_TEST(" 1", "%12X", 1); + SWPRINTF_TEST("000000000001", "%012X", 1); + SWPRINTF_TEST("7FFFFFFF", "%X", INT_MAX); + SWPRINTF_TEST(" 7FFFFFFF", "%12X", INT_MAX); + SWPRINTF_TEST("00007FFFFFFF", "%012X", INT_MAX); + SWPRINTF_TEST("0", "%#X", 0); + SWPRINTF_TEST(" 0", "%#12X", 0); + SWPRINTF_TEST("000000000000", "%#012X", 0); + SWPRINTF_TEST("0X1", "%#X", 1); + SWPRINTF_TEST(" 0X1", "%#12X", 1); + SWPRINTF_TEST("0X0000000001", "%#012X", 1); + SWPRINTF_TEST("0X7FFFFFFF", "%#X", INT_MAX); + SWPRINTF_TEST(" 0X7FFFFFFF", "%#12X", INT_MAX); + SWPRINTF_TEST("0X007FFFFFFF", "%#012X", INT_MAX); +} + +ATF_TC_WITHOUT_HEAD(swprintf_wN); +ATF_TC_BODY(swprintf_wN, tc) +{ + SWPRINTF_TEST("0", "%w8d", (int8_t)0); + SWPRINTF_TEST("-128", "%w8d", (int8_t)SCHAR_MIN); + SWPRINTF_TEST("127", "%w8d", (int8_t)SCHAR_MAX); + SWPRINTF_TEST("0", "%w8u", (uint8_t)0); + SWPRINTF_TEST("255", "%w8u", (uint8_t)UCHAR_MAX); + + SWPRINTF_TEST("0", "%w16d", (int16_t)0); + SWPRINTF_TEST("-32768", "%w16d", (int16_t)SHRT_MIN); + SWPRINTF_TEST("32767", "%w16d", (int16_t)SHRT_MAX); + SWPRINTF_TEST("0", "%w16u", (uint16_t)0); + SWPRINTF_TEST("65535", "%w16u", (uint16_t)USHRT_MAX); + + SWPRINTF_TEST("0", "%w32d", (int32_t)0); + SWPRINTF_TEST("-2147483648", "%w32d", (int32_t)INT_MIN); + SWPRINTF_TEST("2147483647", "%w32d", (int32_t)INT_MAX); + SWPRINTF_TEST("0", "%w32u", (uint32_t)0); + SWPRINTF_TEST("4294967295", "%w32u", (uint32_t)UINT_MAX); + + SWPRINTF_TEST("0", "%w64d", (int64_t)0); + SWPRINTF_TEST("-9223372036854775808", "%w64d", (int64_t)LLONG_MIN); + SWPRINTF_TEST("9223372036854775807", "%w64d", (int64_t)LLONG_MAX); + SWPRINTF_TEST("0", "%w64u", (uint64_t)0); + SWPRINTF_TEST("18446744073709551615", "%w64u", (uint64_t)ULLONG_MAX); + + SWPRINTF_TEST("wd", "%wd", 0); + SWPRINTF_TEST("w1d", "%w1d", 0); + SWPRINTF_TEST("w128d", "%w128d", 0); +} + +ATF_TC_WITHOUT_HEAD(swprintf_wfN); +ATF_TC_BODY(swprintf_wfN, tc) +{ + SWPRINTF_TEST("0", "%wf8d", (int_fast8_t)0); + SWPRINTF_TEST("-2147483648", "%wf8d", (int_fast8_t)INT_MIN); + SWPRINTF_TEST("2147483647", "%wf8d", (int_fast8_t)INT_MAX); + SWPRINTF_TEST("0", "%wf8u", (uint8_t)0); + SWPRINTF_TEST("4294967295", "%wf8u", (uint_fast8_t)UINT_MAX); + + SWPRINTF_TEST("0", "%wf16d", (int_fast16_t)0); + SWPRINTF_TEST("-2147483648", "%wf16d", (int_fast16_t)INT_MIN); + SWPRINTF_TEST("2147483647", "%wf16d", (int_fast16_t)INT_MAX); + SWPRINTF_TEST("0", "%wf16u", (uint16_t)0); + SWPRINTF_TEST("4294967295", "%wf16u", (uint_fast16_t)UINT_MAX); + + SWPRINTF_TEST("0", "%wf32d", (int_fast32_t)0); + SWPRINTF_TEST("-2147483648", "%wf32d", (int_fast32_t)INT_MIN); + SWPRINTF_TEST("2147483647", "%wf32d", (int_fast32_t)INT_MAX); + SWPRINTF_TEST("0", "%wf32u", (uint32_t)0); + SWPRINTF_TEST("4294967295", "%wf32u", (uint_fast32_t)UINT_MAX); + + SWPRINTF_TEST("0", "%wf64d", (int_fast64_t)0); + SWPRINTF_TEST("-9223372036854775808", "%wf64d", (int_fast64_t)LLONG_MIN); + SWPRINTF_TEST("9223372036854775807", "%wf64d", (int_fast64_t)LLONG_MAX); + SWPRINTF_TEST("0", "%wf64u", (uint64_t)0); + SWPRINTF_TEST("18446744073709551615", "%wf64u", (uint_fast64_t)ULLONG_MAX); + + SWPRINTF_TEST("wfd", "%wfd", 0); + SWPRINTF_TEST("wf1d", "%wf1d", 0); + SWPRINTF_TEST("wf128d", "%wf128d", 0); +} + +ATF_TP_ADD_TCS(tp) +{ + setlocale(LC_NUMERIC, "en_US.UTF-8"); + ATF_TP_ADD_TC(tp, swprintf_b); + ATF_TP_ADD_TC(tp, swprintf_B); + ATF_TP_ADD_TC(tp, swprintf_d); + ATF_TP_ADD_TC(tp, swprintf_x); + ATF_TP_ADD_TC(tp, swprintf_X); + ATF_TP_ADD_TC(tp, swprintf_wN); + ATF_TP_ADD_TC(tp, swprintf_wfN); + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdio/swscanf_test.c b/lib/libc/tests/stdio/swscanf_test.c new file mode 100644 index 000000000000..f0638081e16f --- /dev/null +++ b/lib/libc/tests/stdio/swscanf_test.c @@ -0,0 +1,359 @@ +/*- + * Copyright (c) 2023 Dag-Erling Smørgrav + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <limits.h> +#include <locale.h> +#include <stdint.h> +#include <stdio.h> +#include <wchar.h> + +#include <atf-c.h> + +#define L(s) L ## s + +static const struct swscanf_test_case { + wchar_t input[8]; + struct { + int ret, val, len; + } b, o, d, x, i; +} swscanf_test_cases[] = { +// input binary octal decimal hexadecimal automatic + // all digits + { L"0", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, }, + { L"1", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, }, + { L"2", { 0, 0, 0 }, { 1, 2, 1 }, { 1, 2, 1 }, { 1, 2, 1 }, { 1, 2, 1 }, }, + { L"3", { 0, 0, 0 }, { 1, 3, 1 }, { 1, 3, 1 }, { 1, 3, 1 }, { 1, 3, 1 }, }, + { L"4", { 0, 0, 0 }, { 1, 4, 1 }, { 1, 4, 1 }, { 1, 4, 1 }, { 1, 4, 1 }, }, + { L"5", { 0, 0, 0 }, { 1, 5, 1 }, { 1, 5, 1 }, { 1, 5, 1 }, { 1, 5, 1 }, }, + { L"6", { 0, 0, 0 }, { 1, 6, 1 }, { 1, 6, 1 }, { 1, 6, 1 }, { 1, 6, 1 }, }, + { L"7", { 0, 0, 0 }, { 1, 7, 1 }, { 1, 7, 1 }, { 1, 7, 1 }, { 1, 7, 1 }, }, + { L"8", { 0, 0, 0 }, { 0, 0, 0 }, { 1, 8, 1 }, { 1, 8, 1 }, { 1, 8, 1 }, }, + { L"9", { 0, 0, 0 }, { 0, 0, 0 }, { 1, 9, 1 }, { 1, 9, 1 }, { 1, 9, 1 }, }, + { L"A", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 10, 1 }, { 0, 0, 0 }, }, + { L"B", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 11, 1 }, { 0, 0, 0 }, }, + { L"C", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 12, 1 }, { 0, 0, 0 }, }, + { L"D", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 13, 1 }, { 0, 0, 0 }, }, + { L"E", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 14, 1 }, { 0, 0, 0 }, }, + { L"F", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 15, 1 }, { 0, 0, 0 }, }, + { L"X", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, }, + { L"a", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 10, 1 }, { 0, 0, 0 }, }, + { L"b", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 11, 1 }, { 0, 0, 0 }, }, + { L"c", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 12, 1 }, { 0, 0, 0 }, }, + { L"d", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 13, 1 }, { 0, 0, 0 }, }, + { L"e", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 14, 1 }, { 0, 0, 0 }, }, + { L"f", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1, 15, 1 }, { 0, 0, 0 }, }, + { L"x", { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, }, + // all digits with leading zero + { L"00", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, }, + { L"01", { 1, 1, 2 }, { 1, 1, 2 }, { 1, 1, 2 }, { 1, 1, 2 }, { 1, 1, 2 }, }, + { L"02", { 1, 0, 1 }, { 1, 2, 2 }, { 1, 2, 2 }, { 1, 2, 2 }, { 1, 2, 2 }, }, + { L"03", { 1, 0, 1 }, { 1, 3, 2 }, { 1, 3, 2 }, { 1, 3, 2 }, { 1, 3, 2 }, }, + { L"04", { 1, 0, 1 }, { 1, 4, 2 }, { 1, 4, 2 }, { 1, 4, 2 }, { 1, 4, 2 }, }, + { L"05", { 1, 0, 1 }, { 1, 5, 2 }, { 1, 5, 2 }, { 1, 5, 2 }, { 1, 5, 2 }, }, + { L"06", { 1, 0, 1 }, { 1, 6, 2 }, { 1, 6, 2 }, { 1, 6, 2 }, { 1, 6, 2 }, }, + { L"07", { 1, 0, 1 }, { 1, 7, 2 }, { 1, 7, 2 }, { 1, 7, 2 }, { 1, 7, 2 }, }, + { L"08", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 8, 2 }, { 1, 8, 2 }, { 1, 0, 1 }, }, + { L"09", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 9, 2 }, { 1, 9, 2 }, { 1, 0, 1 }, }, + { L"0A", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 10, 2 }, { 1, 0, 1 }, }, + { L"0B", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 11, 2 }, { 1, 0, 1 }, }, + { L"0C", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 12, 2 }, { 1, 0, 1 }, }, + { L"0D", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 13, 2 }, { 1, 0, 1 }, }, + { L"0E", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 14, 2 }, { 1, 0, 1 }, }, + { L"0F", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 15, 2 }, { 1, 0, 1 }, }, + { L"0X", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, }, + { L"0a", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 10, 2 }, { 1, 0, 1 }, }, + { L"0b", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 11, 2 }, { 1, 0, 1 }, }, + { L"0c", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 12, 2 }, { 1, 0, 1 }, }, + { L"0d", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 13, 2 }, { 1, 0, 1 }, }, + { L"0e", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 14, 2 }, { 1, 0, 1 }, }, + { L"0f", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 15, 2 }, { 1, 0, 1 }, }, + { L"0x", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, }, + // all digits with two leading zeroes + { L"000", { 1, 0, 3 }, { 1, 0, 3 }, { 1, 0, 3 }, { 1, 0, 3 }, { 1, 0, 3 }, }, + { L"001", { 1, 1, 3 }, { 1, 1, 3 }, { 1, 1, 3 }, { 1, 1, 3 }, { 1, 1, 3 }, }, + { L"002", { 1, 0, 2 }, { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 }, }, + { L"003", { 1, 0, 2 }, { 1, 3, 3 }, { 1, 3, 3 }, { 1, 3, 3 }, { 1, 3, 3 }, }, + { L"004", { 1, 0, 2 }, { 1, 4, 3 }, { 1, 4, 3 }, { 1, 4, 3 }, { 1, 4, 3 }, }, + { L"005", { 1, 0, 2 }, { 1, 5, 3 }, { 1, 5, 3 }, { 1, 5, 3 }, { 1, 5, 3 }, }, + { L"006", { 1, 0, 2 }, { 1, 6, 3 }, { 1, 6, 3 }, { 1, 6, 3 }, { 1, 6, 3 }, }, + { L"007", { 1, 0, 2 }, { 1, 7, 3 }, { 1, 7, 3 }, { 1, 7, 3 }, { 1, 7, 3 }, }, + { L"008", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 8, 3 }, { 1, 8, 3 }, { 1, 0, 2 }, }, + { L"009", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 9, 3 }, { 1, 9, 3 }, { 1, 0, 2 }, }, + { L"00A", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 10, 3 }, { 1, 0, 2 }, }, + { L"00B", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 11, 3 }, { 1, 0, 2 }, }, + { L"00C", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 12, 3 }, { 1, 0, 2 }, }, + { L"00D", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 13, 3 }, { 1, 0, 2 }, }, + { L"00E", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 14, 3 }, { 1, 0, 2 }, }, + { L"00F", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 15, 3 }, { 1, 0, 2 }, }, + { L"00X", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, }, + { L"00a", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 10, 3 }, { 1, 0, 2 }, }, + { L"00b", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 11, 3 }, { 1, 0, 2 }, }, + { L"00c", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 12, 3 }, { 1, 0, 2 }, }, + { L"00d", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 13, 3 }, { 1, 0, 2 }, }, + { L"00e", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 14, 3 }, { 1, 0, 2 }, }, + { L"00f", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 15, 3 }, { 1, 0, 2 }, }, + { L"00x", { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, { 1, 0, 2 }, }, + // all digits with leading one + { L"10", { 1, 2, 2 }, { 1, 8, 2 }, { 1, 10, 2 }, { 1, 16, 2 }, { 1, 10, 2 }, }, + { L"11", { 1, 3, 2 }, { 1, 9, 2 }, { 1, 11, 2 }, { 1, 17, 2 }, { 1, 11, 2 }, }, + { L"12", { 1, 1, 1 }, { 1, 10, 2 }, { 1, 12, 2 }, { 1, 18, 2 }, { 1, 12, 2 }, }, + { L"13", { 1, 1, 1 }, { 1, 11, 2 }, { 1, 13, 2 }, { 1, 19, 2 }, { 1, 13, 2 }, }, + { L"14", { 1, 1, 1 }, { 1, 12, 2 }, { 1, 14, 2 }, { 1, 20, 2 }, { 1, 14, 2 }, }, + { L"15", { 1, 1, 1 }, { 1, 13, 2 }, { 1, 15, 2 }, { 1, 21, 2 }, { 1, 15, 2 }, }, + { L"16", { 1, 1, 1 }, { 1, 14, 2 }, { 1, 16, 2 }, { 1, 22, 2 }, { 1, 16, 2 }, }, + { L"17", { 1, 1, 1 }, { 1, 15, 2 }, { 1, 17, 2 }, { 1, 23, 2 }, { 1, 17, 2 }, }, + { L"18", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 18, 2 }, { 1, 24, 2 }, { 1, 18, 2 }, }, + { L"19", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 19, 2 }, { 1, 25, 2 }, { 1, 19, 2 }, }, + { L"1A", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 26, 2 }, { 1, 1, 1 }, }, + { L"1B", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 27, 2 }, { 1, 1, 1 }, }, + { L"1C", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 28, 2 }, { 1, 1, 1 }, }, + { L"1D", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 29, 2 }, { 1, 1, 1 }, }, + { L"1E", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 30, 2 }, { 1, 1, 1 }, }, + { L"1F", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 31, 2 }, { 1, 1, 1 }, }, + { L"1X", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, }, + { L"1a", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 26, 2 }, { 1, 1, 1 }, }, + { L"1b", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 27, 2 }, { 1, 1, 1 }, }, + { L"1c", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 28, 2 }, { 1, 1, 1 }, }, + { L"1d", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 29, 2 }, { 1, 1, 1 }, }, + { L"1e", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 30, 2 }, { 1, 1, 1 }, }, + { L"1f", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 31, 2 }, { 1, 1, 1 }, }, + { L"1x", { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, }, + // all digits with leading binary prefix + { L"0b0", { 1, 0, 3 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 176, 3 }, { 1, 0, 3 }, }, + { L"0b1", { 1, 1, 3 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 177, 3 }, { 1, 1, 3 }, }, + { L"0b2", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 178, 3 }, { 1, 0, 1 }, }, + { L"0b3", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 179, 3 }, { 1, 0, 1 }, }, + { L"0b4", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 180, 3 }, { 1, 0, 1 }, }, + { L"0b5", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 181, 3 }, { 1, 0, 1 }, }, + { L"0b6", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 182, 3 }, { 1, 0, 1 }, }, + { L"0b7", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 183, 3 }, { 1, 0, 1 }, }, + { L"0b8", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 184, 3 }, { 1, 0, 1 }, }, + { L"0b9", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 185, 3 }, { 1, 0, 1 }, }, + { L"0bA", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 186, 3 }, { 1, 0, 1 }, }, + { L"0bB", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 187, 3 }, { 1, 0, 1 }, }, + { L"0bC", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 188, 3 }, { 1, 0, 1 }, }, + { L"0bD", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 189, 3 }, { 1, 0, 1 }, }, + { L"0bE", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 190, 3 }, { 1, 0, 1 }, }, + { L"0bF", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 191, 3 }, { 1, 0, 1 }, }, + { L"0bX", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 11, 2 }, { 1, 0, 1 }, }, + { L"0ba", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 186, 3 }, { 1, 0, 1 }, }, + { L"0bb", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 187, 3 }, { 1, 0, 1 }, }, + { L"0bc", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 188, 3 }, { 1, 0, 1 }, }, + { L"0bd", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 189, 3 }, { 1, 0, 1 }, }, + { L"0be", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 190, 3 }, { 1, 0, 1 }, }, + { L"0bf", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 191, 3 }, { 1, 0, 1 }, }, + { L"0bx", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 11, 2 }, { 1, 0, 1 }, }, + // all digits with leading hexadecimal prefix + { L"0x0", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 3 }, { 1, 0, 3 }, }, + { L"0x1", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 1, 3 }, { 1, 1, 3 }, }, + { L"0x2", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 2, 3 }, { 1, 2, 3 }, }, + { L"0x3", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 3, 3 }, { 1, 3, 3 }, }, + { L"0x4", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 4, 3 }, { 1, 4, 3 }, }, + { L"0x5", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 5, 3 }, { 1, 5, 3 }, }, + { L"0x6", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 6, 3 }, { 1, 6, 3 }, }, + { L"0x7", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 7, 3 }, { 1, 7, 3 }, }, + { L"0x8", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 8, 3 }, { 1, 8, 3 }, }, + { L"0x9", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 9, 3 }, { 1, 9, 3 }, }, + { L"0xA", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 10, 3 }, { 1, 10, 3 }, }, + { L"0xB", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 11, 3 }, { 1, 11, 3 }, }, + { L"0xC", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 12, 3 }, { 1, 12, 3 }, }, + { L"0xD", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 13, 3 }, { 1, 13, 3 }, }, + { L"0xE", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 14, 3 }, { 1, 14, 3 }, }, + { L"0xF", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 15, 3 }, { 1, 15, 3 }, }, + { L"0xX", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, }, + { L"0xa", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 10, 3 }, { 1, 10, 3 }, }, + { L"0xb", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 11, 3 }, { 1, 11, 3 }, }, + { L"0xc", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 12, 3 }, { 1, 12, 3 }, }, + { L"0xd", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 13, 3 }, { 1, 13, 3 }, }, + { L"0xe", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 14, 3 }, { 1, 14, 3 }, }, + { L"0xf", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 15, 3 }, { 1, 15, 3 }, }, + { L"0xX", { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, { 1, 0, 1 }, }, + // terminator + { L"" } +}; + +#define SWSCANF_TEST(string, format, expret, expval, explen) \ + do { \ + int ret = 0, val = 0, len = 0; \ + ret = swscanf(string, format L"%n", &val, &len); \ + ATF_CHECK_EQ(expret, ret); \ + if (expret && ret) { \ + ATF_CHECK_EQ(expval, val); \ + ATF_CHECK_EQ(explen, len); \ + } \ + } while (0) + +ATF_TC_WITHOUT_HEAD(swscanf_b); +ATF_TC_BODY(swscanf_b, tc) +{ + const struct swscanf_test_case *stc; + wchar_t input[16]; + + for (stc = swscanf_test_cases; *stc->input; stc++) { + wcscpy(input + 1, stc->input); + SWSCANF_TEST(input + 1, L"%b", stc->b.ret, stc->b.val, stc->b.len); + input[0] = L'+'; + SWSCANF_TEST(input, L"%b", stc->b.ret, stc->b.val, stc->b.len ? stc->b.len + 1 : 0); + input[0] = L'-'; + SWSCANF_TEST(input, L"%b", stc->b.ret, -stc->b.val, stc->b.len ? stc->b.len + 1 : 0); + } +} + +ATF_TC_WITHOUT_HEAD(swscanf_o); +ATF_TC_BODY(swscanf_o, tc) +{ + const struct swscanf_test_case *stc; + wchar_t input[16]; + + for (stc = swscanf_test_cases; *stc->input; stc++) { + wcscpy(input + 1, stc->input); + SWSCANF_TEST(input + 1, L"%o", stc->o.ret, stc->o.val, stc->o.len); + input[0] = L'+'; + SWSCANF_TEST(input, L"%o", stc->o.ret, stc->o.val, stc->o.len ? stc->o.len + 1 : 0); + input[0] = L'-'; + SWSCANF_TEST(input, L"%o", stc->o.ret, -stc->o.val, stc->o.len ? stc->o.len + 1 : 0); + } +} + +ATF_TC_WITHOUT_HEAD(swscanf_d); +ATF_TC_BODY(swscanf_d, tc) +{ + const struct swscanf_test_case *stc; + wchar_t input[16]; + + for (stc = swscanf_test_cases; *stc->input; stc++) { + wcscpy(input + 1, stc->input); + SWSCANF_TEST(input + 1, L"%d", stc->d.ret, stc->d.val, stc->d.len); + input[0] = L'+'; + SWSCANF_TEST(input, L"%d", stc->d.ret, stc->d.val, stc->d.len ? stc->d.len + 1 : 0); + input[0] = L'-'; + SWSCANF_TEST(input, L"%d", stc->d.ret, -stc->d.val, stc->d.len ? stc->d.len + 1 : 0); + } +} + +ATF_TC_WITHOUT_HEAD(swscanf_x); +ATF_TC_BODY(swscanf_x, tc) +{ + const struct swscanf_test_case *stc; + wchar_t input[16]; + + for (stc = swscanf_test_cases; *stc->input; stc++) { + wcscpy(input + 1, stc->input); + SWSCANF_TEST(input + 1, L"%x", stc->x.ret, stc->x.val, stc->x.len); + input[0] = L'+'; + SWSCANF_TEST(input, L"%x", stc->x.ret, stc->x.val, stc->x.len ? stc->x.len + 1 : 0); + input[0] = L'-'; + SWSCANF_TEST(input, L"%x", stc->x.ret, -stc->x.val, stc->x.len ? stc->x.len + 1 : 0); + } +} + +ATF_TC_WITHOUT_HEAD(swscanf_i); +ATF_TC_BODY(swscanf_i, tc) +{ + const struct swscanf_test_case *stc; + wchar_t input[16]; + + for (stc = swscanf_test_cases; *stc->input; stc++) { + wcscpy(input + 1, stc->input); + SWSCANF_TEST(input + 1, L"%i", stc->i.ret, stc->i.val, stc->i.len); + input[0] = L'+'; + SWSCANF_TEST(input, L"%i", stc->i.ret, stc->i.val, stc->i.len ? stc->i.len + 1 : 0); + input[0] = L'-'; + SWSCANF_TEST(input, L"%i", stc->i.ret, -stc->i.val, stc->i.len ? stc->i.len + 1 : 0); + } +} + +ATF_TC_WITHOUT_HEAD(swscanf_wN); +ATF_TC_BODY(swscanf_wN, tc) +{ + const wchar_t x00[] = L"0x00"; + const wchar_t x7f[] = L"0x7fffffffffffffff"; + const wchar_t xff[] = L"0xffffffffffffffff"; + +#define SWSCANF_WN_TEST(N, imin, umax) \ + do { \ + int##N##_t i; \ + uint##N##_t u; \ + ATF_CHECK_EQ(1, swscanf(x00, L"%w" L(#N) L"i", &i)); \ + ATF_CHECK_EQ(0, i); \ + ATF_CHECK_EQ(1, swscanf(x7f, L"%w" L(#N) L"i", &i)); \ + ATF_CHECK_EQ(imin, i); \ + ATF_CHECK_EQ(1, swscanf(x00, L"%w" L(#N) L"x", &u)); \ + ATF_CHECK_EQ(0, u); \ + ATF_CHECK_EQ(1, swscanf(xff, L"%w" L(#N) L"x", &u)); \ + ATF_CHECK_EQ(umax, u); \ + } while (0) + SWSCANF_WN_TEST(8, -1, UCHAR_MAX); + SWSCANF_WN_TEST(16, -1, USHRT_MAX); + SWSCANF_WN_TEST(32, -1, UINT_MAX); + SWSCANF_WN_TEST(64, LLONG_MAX, ULLONG_MAX); +#undef SWSCANF_WN_TEST + + ATF_CHECK_EQ(0, swscanf(x00, L"%wi", (int *)NULL)); + ATF_CHECK_EQ(0, swscanf(x00, L"%w1i", (int *)NULL)); + ATF_CHECK_EQ(0, swscanf(x00, L"%w128i", (int *)NULL)); +} + +ATF_TC_WITHOUT_HEAD(swscanf_wfN); +ATF_TC_BODY(swscanf_wfN, tc) +{ + const wchar_t x00[] = L"0x00"; + const wchar_t x7f[] = L"0x7fffffffffffffff"; + const wchar_t xff[] = L"0xffffffffffffffff"; + +#define SWSCANF_WFN_TEST(N, imin, umax) \ + do { \ + int_fast##N##_t i; \ + uint_fast##N##_t u; \ + ATF_CHECK_EQ(1, swscanf(x00, L"%wf" L(#N) L"i", &i)); \ + ATF_CHECK_EQ(0, i); \ + ATF_CHECK_EQ(1, swscanf(x7f, L"%wf" L(#N) L"i", &i)); \ + ATF_CHECK_EQ(imin, i); \ + ATF_CHECK_EQ(1, swscanf(x00, L"%wf" L(#N) L"x", &u)); \ + ATF_CHECK_EQ(0, u); \ + ATF_CHECK_EQ(1, swscanf(xff, L"%wf" L(#N) L"x", &u)); \ + ATF_CHECK_EQ(umax, u); \ + } while (0) + SWSCANF_WFN_TEST(8, -1, UINT_MAX); + SWSCANF_WFN_TEST(16, -1, UINT_MAX); + SWSCANF_WFN_TEST(32, -1, UINT_MAX); + SWSCANF_WFN_TEST(64, LLONG_MAX, ULLONG_MAX); +#undef SWSCANF_WFN_TEST + + ATF_CHECK_EQ(0, swscanf(x00, L"%wfi", (int *)NULL)); + ATF_CHECK_EQ(0, swscanf(x00, L"%wf1i", (int *)NULL)); + ATF_CHECK_EQ(0, swscanf(x00, L"%wf128i", (int *)NULL)); +} + +/* + * Test termination cases: non-numeric character, fixed width, EOF + */ +ATF_TC_WITHOUT_HEAD(swscanf_termination); +ATF_TC_BODY(swscanf_termination, tc) +{ + int a = 0, b = 0, c = 0; + wchar_t d = 0; + + ATF_CHECK_EQ(4, swscanf(L"3.1415", L"%d%lc%2d%d", &a, &d, &b, &c)); + ATF_CHECK_EQ(3, a); + ATF_CHECK_EQ(14, b); + ATF_CHECK_EQ(15, c); + ATF_CHECK_EQ(L'.', d); +} + +ATF_TP_ADD_TCS(tp) +{ + setlocale(LC_NUMERIC, "en_US.UTF-8"); + ATF_TP_ADD_TC(tp, swscanf_b); + ATF_TP_ADD_TC(tp, swscanf_o); + ATF_TP_ADD_TC(tp, swscanf_d); + ATF_TP_ADD_TC(tp, swscanf_x); + ATF_TP_ADD_TC(tp, swscanf_i); + ATF_TP_ADD_TC(tp, swscanf_wN); + ATF_TP_ADD_TC(tp, swscanf_wfN); + ATF_TP_ADD_TC(tp, swscanf_termination); + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdlib/Makefile b/lib/libc/tests/stdlib/Makefile index ffba83443a9e..9d84becfbd1f 100644 --- a/lib/libc/tests/stdlib/Makefile +++ b/lib/libc/tests/stdlib/Makefile @@ -1,14 +1,20 @@ -# $FreeBSD$ - .include <src.opts.mk> ATF_TESTS_C+= clearenv_test +ATF_TESTS_C+= cxa_atexit_test ATF_TESTS_C+= dynthr_test +ATF_TESTS_C+= getenv_r_test ATF_TESTS_C+= heapsort_test +ATF_TESTS_C+= libc_exit_test ATF_TESTS_C+= mergesort_test ATF_TESTS_C+= qsort_test +.if ${COMPILER_FEATURES:Mblocks} +ATF_TESTS_C+= qsort_b_test +.endif +ATF_TESTS_C+= qsort_r_compat_test ATF_TESTS_C+= qsort_r_test ATF_TESTS_C+= qsort_s_test +ATF_TESTS_C+= qsort_bench ATF_TESTS_C+= set_constraint_handler_s_test ATF_TESTS_C+= strfmon_test ATF_TESTS_C+= tsearch_test @@ -55,10 +61,14 @@ PROGS+= h_getopt h_getopt_long CFLAGS+= -I${.CURDIR} -CXXSTD.cxa_thread_atexit_test= c++11 -CXXSTD.cxa_thread_atexit_nothr_test= c++11 LIBADD.cxa_thread_atexit_test+= pthread +# Tests that require blocks support +.for t in qsort_b_test +CFLAGS.${t}.c+= -fblocks +LIBADD.${t}+= BlocksRuntime +.endfor + .for t in h_getopt h_getopt_long CFLAGS.$t+= -I${LIBNETBSD_SRCDIR} -I${SRCTOP}/contrib/netbsd-tests LDFLAGS.$t+= -L${LIBNETBSD_OBJDIR} @@ -66,8 +76,10 @@ LDFLAGS.$t+= -L${LIBNETBSD_OBJDIR} LIBADD.${t}+= netbsd util .endfor +LIBADD.libc_exit_test+= pthread LIBADD.strtod_test+= m SUBDIR+= dynthr_mod +SUBDIR+= libatexit .include <bsd.test.mk> diff --git a/lib/libc/tests/stdlib/Makefile.depend b/lib/libc/tests/stdlib/Makefile.depend index 7332c13b1b62..777d716dbd01 100644 --- a/lib/libc/tests/stdlib/Makefile.depend +++ b/lib/libc/tests/stdlib/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/stdlib/clearenv_test.c b/lib/libc/tests/stdlib/clearenv_test.c index 40bd7f2ba0f5..003535a00060 100644 --- a/lib/libc/tests/stdlib/clearenv_test.c +++ b/lib/libc/tests/stdlib/clearenv_test.c @@ -1,5 +1,5 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (C) 2021 Mariusz Zaborski <oshogbo@FreeBSD.org> * @@ -29,9 +29,6 @@ * Test for clearenv(3) routine. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <atf-c.h> #include <stdio.h> diff --git a/lib/libc/tests/stdlib/cxa_atexit_test.c b/lib/libc/tests/stdlib/cxa_atexit_test.c new file mode 100644 index 000000000000..7e2cafbce850 --- /dev/null +++ b/lib/libc/tests/stdlib/cxa_atexit_test.c @@ -0,0 +1,132 @@ +/*- + * Copyright (c) 2025 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/wait.h> + +#include <dlfcn.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +#include <atf-c.h> + +#define ARBITRARY_EXIT_CODE 42 + +static char * +get_shlib(const char *srcdir) +{ + char *shlib; + + shlib = NULL; + if (asprintf(&shlib, "%s/libatexit.so", srcdir) < 0) + atf_tc_fail("failed to construct path to libatexit.so"); + return (shlib); +} + +static void +run_test(const atf_tc_t *tc, bool with_fatal_atexit, bool with_exit) +{ + pid_t p; + void (*set_fatal_atexit)(bool); + void (*set_exit_code)(int); + void *hdl; + char *shlib; + + shlib = get_shlib(atf_tc_get_config_var(tc, "srcdir")); + + hdl = dlopen(shlib, RTLD_LAZY); + ATF_REQUIRE_MSG(hdl != NULL, "dlopen: %s", dlerror()); + + free(shlib); + + if (with_fatal_atexit) { + set_fatal_atexit = dlsym(hdl, "set_fatal_atexit"); + ATF_REQUIRE_MSG(set_fatal_atexit != NULL, + "set_fatal_atexit: %s", dlerror()); + } + if (with_exit) { + set_exit_code = dlsym(hdl, "set_exit_code"); + ATF_REQUIRE_MSG(set_exit_code != NULL, "set_exit_code: %s", + dlerror()); + } + + p = atf_utils_fork(); + if (p == 0) { + /* + * Don't let the child clobber the results file; stderr/stdout + * have been replaced by atf_utils_fork() to capture it. We're + * intentionally using exit() instead of _exit() here to run + * __cxa_finalize at exit, otherwise we'd just leave it be. + */ + closefrom(3); + + if (with_fatal_atexit) + set_fatal_atexit(true); + if (with_exit) + set_exit_code(ARBITRARY_EXIT_CODE); + + dlclose(hdl); + + /* + * If the dtor was supposed to exit (most cases), then we should + * not have made it to this point. If it's not supposed to + * exit, then we just exit with success here because we might + * be expecting either a clean exit or a signal on our way out + * as the final __cxa_finalize tries to run a callback in the + * unloaded DSO. + */ + if (with_exit) + exit(1); + exit(0); + } + + dlclose(hdl); + atf_utils_wait(p, with_exit ? ARBITRARY_EXIT_CODE : 0, "", ""); +} + +ATF_TC_WITHOUT_HEAD(simple_cxa_atexit); +ATF_TC_BODY(simple_cxa_atexit, tc) +{ + /* + * This test exits in a global object's dtor so that we check for our + * dtor being run at dlclose() time. If it isn't, then the forked child + * will have a chance to exit(1) after dlclose() to raise a failure. + */ + run_test(tc, false, true); +} + +ATF_TC_WITHOUT_HEAD(late_cxa_atexit); +ATF_TC_BODY(late_cxa_atexit, tc) +{ + /* + * This test creates another global object during a __cxa_atexit handler + * invocation. It's been observed in the wild that we weren't executing + * it, then the DSO gets torn down and it was executed at application + * exit time instead. In the best case scenario we would crash if + * something else hadn't been mapped there. + */ + run_test(tc, true, false); +} + +ATF_TC_WITHOUT_HEAD(late_cxa_atexit_ran); +ATF_TC_BODY(late_cxa_atexit_ran, tc) +{ + /* + * This is a slight variation of the previous test where we trigger an + * exit() in our late-registered __cxa_atexit handler so that we can + * ensure it was ran *before* dlclose() finished and not through some + * weird chain of events afterwards. + */ + run_test(tc, true, true); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, simple_cxa_atexit); + ATF_TP_ADD_TC(tp, late_cxa_atexit); + ATF_TP_ADD_TC(tp, late_cxa_atexit_ran); + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdlib/cxa_thread_atexit_nothr_test.cc b/lib/libc/tests/stdlib/cxa_thread_atexit_nothr_test.cc index 3ac360279e8a..0b3b9497a6bd 100644 --- a/lib/libc/tests/stdlib/cxa_thread_atexit_nothr_test.cc +++ b/lib/libc/tests/stdlib/cxa_thread_atexit_nothr_test.cc @@ -25,9 +25,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <dlfcn.h> #include <atf-c++.hpp> #include <cstdio> diff --git a/lib/libc/tests/stdlib/cxa_thread_atexit_test.cc b/lib/libc/tests/stdlib/cxa_thread_atexit_test.cc index ded91c943c8a..628a70b510d1 100644 --- a/lib/libc/tests/stdlib/cxa_thread_atexit_test.cc +++ b/lib/libc/tests/stdlib/cxa_thread_atexit_test.cc @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <dlfcn.h> #include <atf-c++.hpp> #include <cstdio> diff --git a/lib/libc/tests/stdlib/dynthr_mod/Makefile b/lib/libc/tests/stdlib/dynthr_mod/Makefile index b2a93b3af6d6..3602e81e5be1 100644 --- a/lib/libc/tests/stdlib/dynthr_mod/Makefile +++ b/lib/libc/tests/stdlib/dynthr_mod/Makefile @@ -1,9 +1,8 @@ -# $FreeBSD$ - SHLIB_NAME= dynthr_mod.so SHLIBDIR= ${TESTSDIR} SRCS= dynthr_mod.c LIBADD= pthread +PACKAGE= tests TESTSDIR:= ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/:H} diff --git a/lib/libc/tests/stdlib/dynthr_mod/dynthr_mod.c b/lib/libc/tests/stdlib/dynthr_mod/dynthr_mod.c index c19a1a54a8b6..eccffcd0bd49 100644 --- a/lib/libc/tests/stdlib/dynthr_mod/dynthr_mod.c +++ b/lib/libc/tests/stdlib/dynthr_mod/dynthr_mod.c @@ -31,9 +31,6 @@ * may be omitted in redistributions. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <stdio.h> #include <stdlib.h> #include <stdarg.h> diff --git a/lib/libc/tests/stdlib/dynthr_test.c b/lib/libc/tests/stdlib/dynthr_test.c index d72ee280ccb2..5b0af718afc7 100644 --- a/lib/libc/tests/stdlib/dynthr_test.c +++ b/lib/libc/tests/stdlib/dynthr_test.c @@ -31,9 +31,6 @@ * may be omitted in redistributions. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <stdio.h> #include <stdlib.h> #include <stdarg.h> diff --git a/lib/libc/tests/stdlib/getenv_r_test.c b/lib/libc/tests/stdlib/getenv_r_test.c new file mode 100644 index 000000000000..8085b92b1064 --- /dev/null +++ b/lib/libc/tests/stdlib/getenv_r_test.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <atf-c.h> + +ATF_TC_WITHOUT_HEAD(getenv_r_ok); +ATF_TC_BODY(getenv_r_ok, tc) +{ + const char *ident = atf_tc_get_ident(tc); + char buf[256]; + + ATF_REQUIRE_EQ(0, setenv("ATF_TC_IDENT", ident, 1)); + ATF_REQUIRE_EQ(0, getenv_r("ATF_TC_IDENT", buf, sizeof(buf))); + ATF_REQUIRE_STREQ(ident, buf); +} + +ATF_TC_WITHOUT_HEAD(getenv_r_einval); +ATF_TC_BODY(getenv_r_einval, tc) +{ + char buf[256]; + + errno = 0; + ATF_REQUIRE_EQ(-1, getenv_r(NULL, buf, sizeof(buf))); + ATF_REQUIRE_EQ(EINVAL, errno); + errno = 0; + ATF_REQUIRE_EQ(-1, getenv_r("", buf, sizeof(buf))); + ATF_REQUIRE_EQ(EINVAL, errno); + errno = 0; + ATF_REQUIRE_EQ(-1, getenv_r("A=B", buf, sizeof(buf))); + ATF_REQUIRE_EQ(EINVAL, errno); +} + +ATF_TC_WITHOUT_HEAD(getenv_r_enoent); +ATF_TC_BODY(getenv_r_enoent, tc) +{ + char buf[256]; + + errno = 0; + ATF_REQUIRE_EQ(-1, getenv_r("no such variable", buf, sizeof(buf))); + ATF_REQUIRE_EQ(ENOENT, errno); +} + +ATF_TC_WITHOUT_HEAD(getenv_r_erange); +ATF_TC_BODY(getenv_r_erange, tc) +{ + const char *ident = atf_tc_get_ident(tc); + char buf[256]; + + ATF_REQUIRE_EQ(0, setenv("ATF_TC_IDENT", ident, 1)); + errno = 0; + ATF_REQUIRE_EQ(-1, getenv_r("ATF_TC_IDENT", buf, strlen(ident))); + ATF_REQUIRE_EQ(ERANGE, errno); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, getenv_r_ok); + ATF_TP_ADD_TC(tp, getenv_r_einval); + ATF_TP_ADD_TC(tp, getenv_r_enoent); + ATF_TP_ADD_TC(tp, getenv_r_erange); + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdlib/heapsort_test.c b/lib/libc/tests/stdlib/heapsort_test.c index a83786d1cc5f..b6747ff5d3aa 100644 --- a/lib/libc/tests/stdlib/heapsort_test.c +++ b/lib/libc/tests/stdlib/heapsort_test.c @@ -28,9 +28,6 @@ * Test for heapsort() routine. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <assert.h> #include <stdio.h> #include <stdlib.h> diff --git a/lib/libc/tests/stdlib/libatexit/Makefile b/lib/libc/tests/stdlib/libatexit/Makefile new file mode 100644 index 000000000000..9ba04c77af62 --- /dev/null +++ b/lib/libc/tests/stdlib/libatexit/Makefile @@ -0,0 +1,11 @@ +SHLIB_CXX= libatexit +SHLIB_NAME= libatexit.so +SHLIB_MAJOR= 1 +SHLIBDIR= ${TESTSDIR} +PACKAGE= tests +SRCS= libatexit.cc + +TESTSDIR:= ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/:H} + + +.include <bsd.lib.mk> diff --git a/lib/libc/tests/stdlib/libatexit/libatexit.cc b/lib/libc/tests/stdlib/libatexit/libatexit.cc new file mode 100644 index 000000000000..bb286c97e421 --- /dev/null +++ b/lib/libc/tests/stdlib/libatexit/libatexit.cc @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2025 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + * + */ + +#include <unistd.h> + +static int exit_code = -1; +static bool fatal_atexit; + +extern "C" { + void set_fatal_atexit(bool); + void set_exit_code(int); +} + +void +set_fatal_atexit(bool fexit) +{ + fatal_atexit = fexit; +} + +void +set_exit_code(int code) +{ + exit_code = code; +} + +struct other_object { + ~other_object() { + + /* + * In previous versions of our __cxa_atexit handling, we would + * never actually execute this handler because it's added during + * ~object() below; __cxa_finalize would never revisit it. We + * will allow the caller to configure us to exit with a certain + * exit code so that it can run us twice: once to ensure we + * don't crash at the end, and again to make sure the handler + * actually ran. + */ + if (exit_code != -1) + _exit(exit_code); + } +}; + +void +create_staticobj() +{ + static other_object obj; +} + +struct object { + ~object() { + /* + * If we're doing the fatal_atexit behavior (i.e., create an + * object that will add its own dtor for __cxa_finalize), then + * we don't exit here. + */ + if (fatal_atexit) + create_staticobj(); + else if (exit_code != -1) + _exit(exit_code); + } +}; + +static object obj; diff --git a/lib/libc/tests/stdlib/libc_exit_test.c b/lib/libc/tests/stdlib/libc_exit_test.c new file mode 100644 index 000000000000..12965261bdb3 --- /dev/null +++ b/lib/libc/tests/stdlib/libc_exit_test.c @@ -0,0 +1,154 @@ +/*- + * Copyright (c) 2023 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/wait.h> + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <atf-c.h> + +static void +func_a(void) +{ + if (write(STDOUT_FILENO, "a", 1) != 1) + _Exit(1); +} + +static void +func_b(void) +{ + if (write(STDOUT_FILENO, "b", 1) != 1) + _Exit(1); +} + +static void +func_c(void) +{ + if (write(STDOUT_FILENO, "c", 1) != 1) + _Exit(1); +} + +static void +child(void) +{ + /* this will be received by the parent */ + printf("hello, "); + fflush(stdout); + /* this won't, because quick_exit() does not flush */ + printf("world"); + /* these will be called in reverse order, producing "abc" */ + if (at_quick_exit(func_c) != 0 || + at_quick_exit(func_b) != 0 || + at_quick_exit(func_a) != 0) + _Exit(1); + quick_exit(0); +} + +ATF_TC_WITHOUT_HEAD(quick_exit); +ATF_TC_BODY(quick_exit, tc) +{ + char buf[100] = ""; + ssize_t len; + int p[2], wstatus = 0; + pid_t pid; + + ATF_REQUIRE(pipe(p) == 0); + pid = fork(); + if (pid == 0) { + if (dup2(p[1], STDOUT_FILENO) < 0) + _Exit(1); + (void)close(p[1]); + (void)close(p[0]); + child(); + _Exit(1); + } + ATF_REQUIRE_MSG(pid > 0, + "expect fork() to succeed"); + ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0), + "expect to collect child process"); + ATF_CHECK_EQ_MSG(0, wstatus, + "expect child to exit cleanly"); + ATF_CHECK_MSG((len = read(p[0], buf, sizeof(buf))) > 0, + "expect to receive output from child"); + ATF_CHECK_STREQ("hello, abc", buf); +} + +static void +myatexit1(void) +{ + exit(12); +} + +ATF_TC_WITHOUT_HEAD(recursive_exit1); +ATF_TC_BODY(recursive_exit1, tc) +{ + pid_t pid; + int wstatus; + + pid = fork(); + if (pid == 0) { + atexit(myatexit1); + exit(1); + } + ATF_REQUIRE_MSG(pid > 0, + "expect fork() to succeed"); + ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0), + "expect to collect child process"); + ATF_CHECK(WIFEXITED(wstatus)); + ATF_CHECK_EQ(WEXITSTATUS(wstatus), 12); +} + +static pthread_barrier_t barrier; + +static void +myatexit2(void) +{ + pthread_barrier_wait(&barrier); + exit(12); +} + +static void * +mythreadexit(void *arg) +{ + pthread_barrier_wait(&barrier); + exit(15); +} + +ATF_TC_WITHOUT_HEAD(recursive_exit2); +ATF_TC_BODY(recursive_exit2, tc) +{ + pid_t pid; + int wstatus; + + pid = fork(); + if (pid == 0) { + pthread_t thr; + + atexit(myatexit2); + + pthread_barrier_init(&barrier, NULL, 2); + pthread_create(&thr, NULL, mythreadexit, NULL); + + exit(1); + } + ATF_REQUIRE_MSG(pid > 0, + "expect fork() to succeed"); + ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0), + "expect to collect child process"); + ATF_CHECK(WIFEXITED(wstatus)); + ATF_CHECK_EQ(WEXITSTATUS(wstatus), 12); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, quick_exit); + ATF_TP_ADD_TC(tp, recursive_exit1); + ATF_TP_ADD_TC(tp, recursive_exit2); + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdlib/mergesort_test.c b/lib/libc/tests/stdlib/mergesort_test.c index 4334b924f6bb..156d6bb7c2c3 100644 --- a/lib/libc/tests/stdlib/mergesort_test.c +++ b/lib/libc/tests/stdlib/mergesort_test.c @@ -28,9 +28,6 @@ * Test for mergesort() routine. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <assert.h> #include <stdio.h> #include <stdlib.h> diff --git a/lib/libc/tests/stdlib/qsort_b_test.c b/lib/libc/tests/stdlib/qsort_b_test.c new file mode 100644 index 000000000000..60cd30ac222a --- /dev/null +++ b/lib/libc/tests/stdlib/qsort_b_test.c @@ -0,0 +1,76 @@ +/*- + * Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org> + * All rights reserved. + * + * 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. + */ + +/* + * Test for qsort_b() routine. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include "test-sort.h" + +ATF_TC_WITHOUT_HEAD(qsort_b_test); +ATF_TC_BODY(qsort_b_test, tc) +{ + int testvector[IVEC_LEN]; + int sresvector[IVEC_LEN]; + int i, j; + + for (j = 2; j < IVEC_LEN; j++) { + /* Populate test vectors */ + for (i = 0; i < j; i++) + testvector[i] = sresvector[i] = initvector[i]; + + /* Sort using qsort_b(3) */ + qsort_b(testvector, j, sizeof(testvector[0]), + ^(const void* a, const void* b) { + if (*(int *)a > *(int *)b) + return (1); + else if (*(int *)a < *(int *)b) + return (-1); + else + return (0); + }); + /* Sort using reference slow sorting routine */ + ssort(sresvector, j); + + /* Compare results */ + for (i = 0; i < j; i++) + ATF_CHECK_MSG(testvector[i] == sresvector[i], + "item at index %d didn't match: %d != %d", + i, testvector[i], sresvector[i]); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, qsort_b_test); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdlib/qsort_bench.c b/lib/libc/tests/stdlib/qsort_bench.c new file mode 100644 index 000000000000..5f2cfae40140 --- /dev/null +++ b/lib/libc/tests/stdlib/qsort_bench.c @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 2025 Dag-Erling Smørgrav <des@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <atf-c.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +/*- + * Measures qsort(3) runtime with pathological input and verify that it + * stays close to N * log2(N). + * + * Thanks to Vivian Hussey for the proof of concept. + * + * The input we construct is similar to a sweep from 0 to N where each + * half, except for the first element, has been reversed; for instance, + * with N = 8, we get { 0, 3, 2, 1, 4, 8, 7, 6 }. This triggers a bug in + * the BSD qsort(3) where it will switch to insertion sort if the pivots + * are sorted. + * + * This article goes into more detail about the bug and its origin: + * + * https://www.raygard.net/2022/02/26/Re-engineering-a-qsort-part-3 + * + * With this optimization (the `if (swap_cnt == 0)` block), qsort(3) needs + * roughly N * N / 4 comparisons to sort our pathological input. Without + * it, it needs only a little more than N * log2(N) comparisons. + */ + +/* we stop testing once a single takes longer than this */ +#define MAXRUNSECS 10 + +static bool debugging; + +static uintmax_t ncmp; + +static int +intcmp(const void *a, const void *b) +{ + ncmp++; + return ((*(int *)a > *(int *)b) - (*(int *)a < *(int *)b)); +} + +static void +qsort_bench(int log2n) +{ + uintmax_t n = 1LLU << log2n; + int *buf; + + /* fill an array with a pathological pattern */ + ATF_REQUIRE(buf = malloc(n * sizeof(*buf))); + buf[0] = 0; + buf[n / 2] = n / 2; + for (unsigned int i = 1; i < n / 2; i++) { + buf[i] = n / 2 - i; + buf[n / 2 + i] = n - i; + } + + ncmp = 0; + qsort(buf, n, sizeof(*buf), intcmp); + + /* check result and free array */ + if (debugging) { + for (unsigned int i = 1; i < n; i++) { + ATF_REQUIRE_MSG(buf[i] > buf[i - 1], + "array is not sorted"); + } + } + free(buf); + + /* check that runtime does not exceed N² */ + ATF_CHECK_MSG(ncmp / n < n, + "runtime %ju exceeds N² for N = %ju", ncmp, n); + + /* check that runtime does not exceed N log N by much */ + ATF_CHECK_MSG(ncmp / n <= log2n + 1, + "runtime %ju exceeds N log N for N = %ju", ncmp, n); +} + +ATF_TC_WITHOUT_HEAD(qsort_bench); +ATF_TC_BODY(qsort_bench, tc) +{ + struct timespec t0, t1; + uintmax_t tus; + + for (int i = 10; i <= 30; i++) { + clock_gettime(CLOCK_UPTIME, &t0); + qsort_bench(i); + clock_gettime(CLOCK_UPTIME, &t1); + tus = t1.tv_sec * 1000000 + t1.tv_nsec / 1000; + tus -= t0.tv_sec * 1000000 + t0.tv_nsec / 1000; + if (debugging) { + fprintf(stderr, "N = 2^%d in %ju.%06jus\n", + i, tus / 1000000, tus % 1000000); + } + /* stop once an individual run exceeds our limit */ + if (tus / 1000000 >= MAXRUNSECS) + break; + } +} + +ATF_TP_ADD_TCS(tp) +{ + debugging = !getenv("__RUNNING_INSIDE_ATF_RUN") && + isatty(STDERR_FILENO); + ATF_TP_ADD_TC(tp, qsort_bench); + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdlib/qsort_r_compat_test.c b/lib/libc/tests/stdlib/qsort_r_compat_test.c new file mode 100644 index 000000000000..d7b06615292e --- /dev/null +++ b/lib/libc/tests/stdlib/qsort_r_compat_test.c @@ -0,0 +1,89 @@ +/*- + * Copyright (C) 2020 Edward Tomasz Napierala <trasz@FreeBSD.org> + * Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org> + * All rights reserved. + * + * 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. + */ + +/* + * Test for historical qsort_r(3) routine. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "test-sort.h" + +#define THUNK 42 + +static int +sorthelp_r(void *thunk, const void *a, const void *b) +{ + const int *oa, *ob; + + ATF_REQUIRE_EQ(*(int *)thunk, THUNK); + + oa = a; + ob = b; + /* Don't use "return *oa - *ob" since it's easy to cause overflow! */ + if (*oa > *ob) + return (1); + if (*oa < *ob) + return (-1); + return (0); +} + +ATF_TC_WITHOUT_HEAD(qsort_r_compat_test); +ATF_TC_BODY(qsort_r_compat_test, tc) +{ + int testvector[IVEC_LEN]; + int sresvector[IVEC_LEN]; + int i, j; + int thunk = THUNK; + + for (j = 2; j < IVEC_LEN; j++) { + /* Populate test vectors */ + for (i = 0; i < j; i++) + testvector[i] = sresvector[i] = initvector[i]; + + /* Sort using qsort_r(3) */ + qsort_r(testvector, j, sizeof(testvector[0]), &thunk, + sorthelp_r); + /* Sort using reference slow sorting routine */ + ssort(sresvector, j); + + /* Compare results */ + for (i = 0; i < j; i++) + ATF_CHECK_MSG(testvector[i] == sresvector[i], + "item at index %d didn't match: %d != %d", + i, testvector[i], sresvector[i]); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, qsort_r_compat_test); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdlib/qsort_r_test.c b/lib/libc/tests/stdlib/qsort_r_test.c index c27e6d92d587..446d63279fbf 100644 --- a/lib/libc/tests/stdlib/qsort_r_test.c +++ b/lib/libc/tests/stdlib/qsort_r_test.c @@ -29,9 +29,6 @@ * Test for qsort_r(3) routine. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <stdio.h> #include <stdlib.h> @@ -40,7 +37,7 @@ __FBSDID("$FreeBSD$"); #define THUNK 42 static int -sorthelp_r(void *thunk, const void *a, const void *b) +sorthelp_r(const void *a, const void *b, void *thunk) { const int *oa, *ob; @@ -70,8 +67,8 @@ ATF_TC_BODY(qsort_r_test, tc) testvector[i] = sresvector[i] = initvector[i]; /* Sort using qsort_r(3) */ - qsort_r(testvector, j, sizeof(testvector[0]), &thunk, - sorthelp_r); + qsort_r(testvector, j, sizeof(testvector[0]), sorthelp_r, + &thunk); /* Sort using reference slow sorting routine */ ssort(sresvector, j); diff --git a/lib/libc/tests/stdlib/qsort_s_test.c b/lib/libc/tests/stdlib/qsort_s_test.c index e3ed7ae3b208..c3210caf24e1 100644 --- a/lib/libc/tests/stdlib/qsort_s_test.c +++ b/lib/libc/tests/stdlib/qsort_s_test.c @@ -30,9 +30,6 @@ * Test for qsort_s(3) routine. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <stdint.h> #include <stdio.h> #include <stdlib.h> diff --git a/lib/libc/tests/stdlib/qsort_test.c b/lib/libc/tests/stdlib/qsort_test.c index 14e02925dfa5..a6202e55fd62 100644 --- a/lib/libc/tests/stdlib/qsort_test.c +++ b/lib/libc/tests/stdlib/qsort_test.c @@ -28,9 +28,6 @@ * Test for qsort() routine. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <assert.h> #include <stdio.h> #include <stdlib.h> diff --git a/lib/libc/tests/stdlib/set_constraint_handler_s_test.c b/lib/libc/tests/stdlib/set_constraint_handler_s_test.c index 6a33c98c9279..87db1f71ed4d 100644 --- a/lib/libc/tests/stdlib/set_constraint_handler_s_test.c +++ b/lib/libc/tests/stdlib/set_constraint_handler_s_test.c @@ -23,9 +23,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <assert.h> #include <stdlib.h> diff --git a/lib/libc/tests/stdlib/strfmon_test.c b/lib/libc/tests/stdlib/strfmon_test.c index 35825ec31b5b..86f6256dba0b 100644 --- a/lib/libc/tests/stdlib/strfmon_test.c +++ b/lib/libc/tests/stdlib/strfmon_test.c @@ -10,7 +10,7 @@ * 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 @@ -24,8 +24,7 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +#include <sys/param.h> #include <locale.h> #include <monetary.h> @@ -53,19 +52,201 @@ ATF_TC_BODY(strfmon_locale_thousands, tc) atf_tc_skip("multi-byte thousands-separator not found"); n = 1234.56; - strfmon(actual, sizeof(actual), "%i", n); + strfmon(actual, sizeof(actual) - 1, "%i", n); strcpy(expected, "1"); strlcat(expected, ts, sizeof(expected)); strlcat(expected, "234", sizeof(expected)); - /* We're just testing the thousands separator, not all of strmon. */ + /* We're just testing the thousands separator, not all of strfmon. */ actual[strlen(expected)] = '\0'; ATF_CHECK_STREQ(expected, actual); } +ATF_TC_WITHOUT_HEAD(strfmon_examples); +ATF_TC_BODY(strfmon_examples, tc) +{ + const struct { + const char *format; + const char *expected; + } tests[] = { + { "%n", "[$123.45] [-$123.45] [$3,456.78]" }, + { "%11n", "[ $123.45] [ -$123.45] [ $3,456.78]" }, + { "%#5n", "[ $ 123.45] [-$ 123.45] [ $ 3,456.78]" }, + { "%=*#5n", "[ $***123.45] [-$***123.45] [ $*3,456.78]" }, + { "%=0#5n", "[ $000123.45] [-$000123.45] [ $03,456.78]" }, + { "%^#5n", "[ $ 123.45] [-$ 123.45] [ $ 3456.78]" }, + { "%^#5.0n", "[ $ 123] [-$ 123] [ $ 3457]" }, + { "%^#5.4n", "[ $ 123.4500] [-$ 123.4500] [ $ 3456.7810]" }, + { "%(#5n", "[ $ 123.45 ] [($ 123.45)] [ $ 3,456.78 ]" }, + { "%!(#5n", "[ 123.45 ] [( 123.45)] [ 3,456.78 ]" }, + { "%-14#5.4n", "[ $ 123.4500 ] [-$ 123.4500 ] [ $ 3,456.7810 ]" }, + { "%14#5.4n", "[ $ 123.4500] [ -$ 123.4500] [ $ 3,456.7810]" }, + }; + size_t i; + char actual[100], format[50]; + + if (setlocale(LC_MONETARY, "en_US.UTF-8") == NULL) + atf_tc_skip("unable to setlocale()"); + + for (i = 0; i < nitems(tests); ++i) { + snprintf(format, sizeof(format), "[%s] [%s] [%s]", + tests[i].format, tests[i].format, tests[i].format); + strfmon(actual, sizeof(actual) - 1, format, + 123.45, -123.45, 3456.781); + ATF_CHECK_STREQ_MSG(tests[i].expected, actual, + "[%s]", tests[i].format); + } +} + +ATF_TC(strfmon_cs_precedes_0); +ATF_TC_HEAD(strfmon_cs_precedes_0, tc) +{ + atf_tc_set_md_var(tc, "descr", + "sep_by_space x sign_posn when cs_precedes = 0"); +} +ATF_TC_BODY(strfmon_cs_precedes_0, tc) +{ + const struct { + const char *expected; + } tests[] = { + /* sep_by_space x sign_posn */ + { "[(123.00$)] [-123.00$] [123.00$-] [123.00-$] [123.00$-]" }, + { "[(123.00 $)] [-123.00 $] [123.00 $-] [123.00 -$] [123.00 $-]" }, + { "[(123.00$)] [- 123.00$] [123.00$ -] [123.00- $] [123.00$ -]" }, + }; + size_t i, j; + struct lconv *lc; + char actual[100], buf[100]; + + if (setlocale(LC_MONETARY, "en_US.UTF-8") == NULL) + atf_tc_skip("unable to setlocale()"); + + lc = localeconv(); + lc->n_cs_precedes = 0; + + for (i = 0; i < nitems(tests); ++i) { + actual[0] = '\0'; + lc->n_sep_by_space = i; + + for (j = 0; j < 5; ++j) { + lc->n_sign_posn = j; + + strfmon(buf, sizeof(buf) - 1, "[%n] ", -123.0); + strlcat(actual, buf, sizeof(actual)); + } + + actual[strlen(actual) - 1] = '\0'; + ATF_CHECK_STREQ_MSG(tests[i].expected, actual, + "sep_by_space = %zu", i); + } +} + +ATF_TC(strfmon_cs_precedes_1); +ATF_TC_HEAD(strfmon_cs_precedes_1, tc) +{ + atf_tc_set_md_var(tc, "descr", + "sep_by_space x sign_posn when cs_precedes = 1"); +} +ATF_TC_BODY(strfmon_cs_precedes_1, tc) +{ + const struct { + const char *expected; + } tests[] = { + /* sep_by_space x sign_posn */ + { "[($123.00)] [-$123.00] [$123.00-] [-$123.00] [$-123.00]" }, + { "[($ 123.00)] [-$ 123.00] [$ 123.00-] [-$ 123.00] [$- 123.00]" }, + { "[($123.00)] [- $123.00] [$123.00 -] [- $123.00] [$ -123.00]" }, + }; + size_t i, j; + struct lconv *lc; + char actual[100], buf[100]; + + if (setlocale(LC_MONETARY, "en_US.UTF-8") == NULL) + atf_tc_skip("unable to setlocale()"); + + lc = localeconv(); + lc->n_cs_precedes = 1; + + for (i = 0; i < nitems(tests); ++i) { + actual[0] = '\0'; + lc->n_sep_by_space = i; + + for (j = 0; j < 5; ++j) { + lc->n_sign_posn = j; + + strfmon(buf, sizeof(buf) - 1, "[%n] ", -123.0); + strlcat(actual, buf, sizeof(actual)); + } + + actual[strlen(actual) - 1] = '\0'; + ATF_CHECK_STREQ_MSG(tests[i].expected, actual, + "sep_by_space = %zu", i); + } +} + +ATF_TC_WITHOUT_HEAD(strfmon_international_currency_code); +ATF_TC_BODY(strfmon_international_currency_code, tc) +{ + const struct { + const char *locale; + const char *expected; + } tests[] = { + { "en_US.UTF-8", "[USD123.45]" }, + { "de_DE.UTF-8", "[123,45 EUR]" }, + { "C", "[123.45]" }, + }; + size_t i; + char actual[100]; + + for (i = 0; i < nitems(tests); ++i) { + if (setlocale(LC_MONETARY, tests[i].locale) == NULL) + atf_tc_skip("unable to setlocale()"); + + strfmon(actual, sizeof(actual) - 1, "[%i]", 123.45); + ATF_CHECK_STREQ(tests[i].expected, actual); + } +} + +ATF_TC(strfmon_l); +ATF_TC_HEAD(strfmon_l, tc) +{ + atf_tc_set_md_var(tc, "descr", + "checks strfmon_l under different locales"); +} +ATF_TC_BODY(strfmon_l, tc) +{ + const struct { + const char *locale; + const char *expected; + } tests[] = { + { "C", "[ **1234.57 ] [ **1234.57 ]" }, + { "de_DE.UTF-8", "[ **1234,57 €] [ **1.234,57 EUR]" }, + { "en_GB.UTF-8", "[ £**1234.57] [ GBP**1,234.57]" }, + }; + locale_t loc; + size_t i; + char buf[100]; + + for (i = 0; i < nitems(tests); ++i) { + loc = newlocale(LC_MONETARY_MASK, tests[i].locale, NULL); + ATF_REQUIRE(loc != NULL); + + strfmon_l(buf, sizeof(buf) - 1, loc, "[%^=*#6n] [%=*#6i]", + 1234.567, 1234.567); + ATF_REQUIRE_STREQ(tests[i].expected, buf); + + freelocale(loc); + } +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, strfmon_locale_thousands); + ATF_TP_ADD_TC(tp, strfmon_examples); + ATF_TP_ADD_TC(tp, strfmon_cs_precedes_0); + ATF_TP_ADD_TC(tp, strfmon_cs_precedes_1); + ATF_TP_ADD_TC(tp, strfmon_international_currency_code); + ATF_TP_ADD_TC(tp, strfmon_l); return (atf_no_error()); } diff --git a/lib/libc/tests/stdlib/test-sort.h b/lib/libc/tests/stdlib/test-sort.h index f038acdb42cc..562f92b6748c 100644 --- a/lib/libc/tests/stdlib/test-sort.h +++ b/lib/libc/tests/stdlib/test-sort.h @@ -22,8 +22,6 @@ * 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. - * - * $FreeBSD$ */ #ifndef _TEST_SORT_H diff --git a/lib/libc/tests/stdlib/tsearch_test.c b/lib/libc/tests/stdlib/tsearch_test.c index ee25743f10b0..ee9deec588cb 100644 --- a/lib/libc/tests/stdlib/tsearch_test.c +++ b/lib/libc/tests/stdlib/tsearch_test.c @@ -23,9 +23,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <atf-c.h> #define _SEARCH_PRIVATE #include <search.h> diff --git a/lib/libc/tests/stdtime/Makefile b/lib/libc/tests/stdtime/Makefile new file mode 100644 index 000000000000..6b9068e1641b --- /dev/null +++ b/lib/libc/tests/stdtime/Makefile @@ -0,0 +1,12 @@ +.include <src.opts.mk> + +ATF_TESTS_C+= strptime_test +ATF_TESTS_C+= detect_tz_changes_test + +.if ${MK_DETECT_TZ_CHANGES} != "no" +CFLAGS.detect_tz_changes_test+= -DDETECT_TZ_CHANGES +.endif + +TESTSDIR:= ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/} + +.include <bsd.test.mk> diff --git a/lib/libc/tests/stdtime/detect_tz_changes_test.c b/lib/libc/tests/stdtime/detect_tz_changes_test.c new file mode 100644 index 000000000000..6648d8498cc5 --- /dev/null +++ b/lib/libc/tests/stdtime/detect_tz_changes_test.c @@ -0,0 +1,390 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include <dlfcn.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +#include <atf-c.h> + +static const struct tzcase { + const char *tzfn; + const char *expect; +} tzcases[] = { + /* + * A handful of time zones and the expected result of + * strftime("%z (%Z)", tm) when that time zone is active + * and tm represents a date in the summer of 2025. + */ + { "America/Vancouver", "-0700 (PDT)" }, + { "America/New_York", "-0400 (EDT)" }, + { "Europe/London", "+0100 (BST)" }, + { "Europe/Paris", "+0200 (CEST)" }, + { "Asia/Kolkata", "+0530 (IST)" }, + { "Asia/Tokyo", "+0900 (JST)" }, + { "Australia/Canberra", "+1000 (AEST)" }, + { "UTC", "+0000 (UTC)" }, + { 0 }, +}; + +static const time_t then = 1751328000; /* 2025-07-01 00:00:00 UTC */ + +static bool debugging; + +static void +debug(const char *fmt, ...) +{ + va_list ap; + + if (debugging) { + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputc('\n', stderr); + } +} + +static void +change_tz(const char *tzn) +{ + static const char *zfn = "/usr/share/zoneinfo"; + static const char *tfn = "root/etc/.localtime"; + static const char *dfn = "root/etc/localtime"; + ssize_t clen; + int zfd, sfd, dfd; + + ATF_REQUIRE((zfd = open(zfn, O_DIRECTORY | O_SEARCH)) >= 0); + ATF_REQUIRE((sfd = openat(zfd, tzn, O_RDONLY)) >= 0); + ATF_REQUIRE((dfd = open(tfn, O_CREAT | O_TRUNC | O_WRONLY, 0644)) >= 0); + do { + clen = copy_file_range(sfd, NULL, dfd, NULL, SSIZE_MAX, 0); + ATF_REQUIRE_MSG(clen != -1, "failed to copy %s/%s: %m", + zfn, tzn); + } while (clen > 0); + ATF_CHECK_EQ(0, close(dfd)); + ATF_CHECK_EQ(0, close(sfd)); + ATF_CHECK_EQ(0, close(zfd)); + ATF_REQUIRE_EQ(0, rename(tfn, dfn)); + debug("time zone %s installed", tzn); +} + +static void +test_tz(const char *expect) +{ + char buf[128]; + struct tm *tm; + size_t len; + + ATF_REQUIRE((tm = localtime(&then)) != NULL); + len = strftime(buf, sizeof(buf), "%z (%Z)", tm); + ATF_REQUIRE(len > 0); + ATF_CHECK_STREQ(expect, buf); +} + +ATF_TC(thin_jail); +ATF_TC_HEAD(thin_jail, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test typical thin jail scenario"); + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(thin_jail, tc) +{ + const struct tzcase *tzcase = tzcases; + + /* prepare chroot */ + ATF_REQUIRE_EQ(0, mkdir("root", 0755)); + ATF_REQUIRE_EQ(0, mkdir("root/etc", 0755)); + change_tz(tzcase->tzfn); + /* enter chroot */ + ATF_REQUIRE_EQ(0, chroot("root")); + ATF_REQUIRE_EQ(0, chdir("/")); + /* check timezone */ + unsetenv("TZ"); + test_tz(tzcase->expect); +} + +#ifdef DETECT_TZ_CHANGES +/* + * Test time zone change detection. + * + * The parent creates a chroot containing only /etc/localtime, initially + * set to UTC. It then forks a child which enters the chroot, repeatedly + * checks the current time zone, and prints it to stdout if it changes + * (including once on startup). Meanwhile, the parent waits for output + * from the child. Every time it receives a line of text from the child, + * it checks that it is as expected, then changes /etc/localtime within + * the chroot to the next case in the list. Once it reaches the end of + * the list, it closes a pipe to notify the child, which terminates. + * + * Note that ATF and / or Kyua may have set the timezone before the test + * case starts (even unintentionally). Therefore, we start the test only + * after we've received and discarded the first report from the child, + * which should come almost immediately on startup. + */ +static const char *tz_change_interval_sym = "__tz_change_interval"; +static int *tz_change_interval_p; +static const int tz_change_interval = 3; +static int tz_change_timeout = 90; + +ATF_TC(detect_tz_changes); +ATF_TC_HEAD(detect_tz_changes, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test timezone change detection"); + atf_tc_set_md_var(tc, "require.user", "root"); + atf_tc_set_md_var(tc, "timeout", "600"); +} +ATF_TC_BODY(detect_tz_changes, tc) +{ + char obuf[1024] = ""; + char ebuf[1024] = ""; + struct pollfd fds[3]; + int opd[2], epd[2], spd[2]; + time_t changed, now; + const struct tzcase *tzcase = NULL; + struct tm *tm; + size_t olen = 0, elen = 0; + ssize_t rlen; + long curoff = LONG_MIN; + pid_t pid; + int nfds, status; + + /* speed up the test if possible */ + tz_change_interval_p = dlsym(RTLD_SELF, tz_change_interval_sym); + if (tz_change_interval_p != NULL && + *tz_change_interval_p > tz_change_interval) { + debug("reducing detection interval from %d to %d", + *tz_change_interval_p, tz_change_interval); + *tz_change_interval_p = tz_change_interval; + tz_change_timeout = tz_change_interval * 3; + } + /* prepare chroot */ + ATF_REQUIRE_EQ(0, mkdir("root", 0755)); + ATF_REQUIRE_EQ(0, mkdir("root/etc", 0755)); + change_tz("UTC"); + time(&changed); + /* output, error, sync pipes */ + if (pipe(opd) != 0 || pipe(epd) != 0 || pipe(spd) != 0) + atf_tc_fail("failed to pipe"); + /* fork child */ + if ((pid = fork()) < 0) + atf_tc_fail("failed to fork"); + if (pid == 0) { + /* child */ + dup2(opd[1], STDOUT_FILENO); + close(opd[0]); + close(opd[1]); + dup2(epd[1], STDERR_FILENO); + close(epd[0]); + close(epd[1]); + close(spd[0]); + unsetenv("TZ"); + ATF_REQUIRE_EQ(0, chroot("root")); + ATF_REQUIRE_EQ(0, chdir("/")); + fds[0].fd = spd[1]; + fds[0].events = POLLIN; + for (;;) { + ATF_REQUIRE(poll(fds, 1, 100) >= 0); + if (fds[0].revents & POLLHUP) { + /* parent closed sync pipe */ + _exit(0); + } + ATF_REQUIRE((tm = localtime(&then)) != NULL); + if (tm->tm_gmtoff == curoff) + continue; + olen = strftime(obuf, sizeof(obuf), "%z (%Z)", tm); + ATF_REQUIRE(olen > 0); + fprintf(stdout, "%s\n", obuf); + fflush(stdout); + curoff = tm->tm_gmtoff; + } + _exit(2); + } + /* parent */ + close(opd[1]); + close(epd[1]); + close(spd[1]); + /* receive output until child terminates */ + fds[0].fd = opd[0]; + fds[0].events = POLLIN; + fds[1].fd = epd[0]; + fds[1].events = POLLIN; + fds[2].fd = spd[0]; + fds[2].events = POLLIN; + nfds = 3; + for (;;) { + ATF_REQUIRE(poll(fds, 3, 1000) >= 0); + time(&now); + if (fds[0].revents & POLLIN && olen < sizeof(obuf)) { + rlen = read(opd[0], obuf + olen, sizeof(obuf) - olen); + ATF_REQUIRE(rlen >= 0); + olen += rlen; + } + if (olen > 0) { + ATF_REQUIRE_EQ('\n', obuf[olen - 1]); + obuf[--olen] = '\0'; + /* tzcase will be NULL at first */ + if (tzcase != NULL) { + debug("%s", obuf); + ATF_REQUIRE_STREQ(tzcase->expect, obuf); + debug("change to %s detected after %d s", + tzcase->tzfn, (int)(now - changed)); + if (tz_change_interval_p != NULL) { + ATF_CHECK((int)(now - changed) >= + *tz_change_interval_p - 1); + ATF_CHECK((int)(now - changed) <= + *tz_change_interval_p + 1); + } + } + olen = 0; + /* first / next test case */ + if (tzcase == NULL) + tzcase = tzcases; + else + tzcase++; + if (tzcase->tzfn == NULL) { + /* test is over */ + break; + } + change_tz(tzcase->tzfn); + changed = now; + } + if (fds[1].revents & POLLIN && elen < sizeof(ebuf)) { + rlen = read(epd[0], ebuf + elen, sizeof(ebuf) - elen); + ATF_REQUIRE(rlen >= 0); + elen += rlen; + } + if (elen > 0) { + ATF_REQUIRE_EQ(elen, fwrite(ebuf, 1, elen, stderr)); + elen = 0; + } + if (nfds > 2 && fds[2].revents & POLLHUP) { + /* child closed sync pipe */ + break; + } + /* + * The timeout for this test case is set to 10 minutes, + * because it can take that long to run with the default + * 61-second interval. However, each individual tzcase + * entry should not take much longer than the detection + * interval to test, so we can detect a problem long + * before Kyua terminates us. + */ + if ((now - changed) > tz_change_timeout) { + close(spd[0]); + if (tz_change_interval_p == NULL && + tzcase == tzcases) { + /* + * The most likely explanation in this + * case is that libc was built without + * time zone change detection. + */ + atf_tc_skip("time zone change detection " + "does not appear to be enabled"); + } + atf_tc_fail("timed out waiting for change to %s " + "to be detected", tzcase->tzfn); + } + } + close(opd[0]); + close(epd[0]); + close(spd[0]); /* this will wake up and terminate the child */ + if (olen > 0) + ATF_REQUIRE_EQ(olen, fwrite(obuf, 1, olen, stdout)); + if (elen > 0) + ATF_REQUIRE_EQ(elen, fwrite(ebuf, 1, elen, stderr)); + ATF_REQUIRE_EQ(pid, waitpid(pid, &status, 0)); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(0, WEXITSTATUS(status)); +} +#endif /* DETECT_TZ_CHANGES */ + +static void +test_tz_env(const char *tzval, const char *expect) +{ + setenv("TZ", tzval, 1); + test_tz(expect); +} + +ATF_TC(tz_env); +ATF_TC_HEAD(tz_env, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test TZ environment variable"); +} +ATF_TC_BODY(tz_env, tc) +{ + const struct tzcase *tzcase; + + for (tzcase = tzcases; tzcase->tzfn != NULL; tzcase++) + test_tz_env(tzcase->tzfn, tzcase->expect); +} + +ATF_TC(setugid); +ATF_TC_HEAD(setugid, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test setugid process"); + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(setugid, tc) +{ + const struct tzcase *tzcase = tzcases; + + /* prepare chroot */ + ATF_REQUIRE_EQ(0, mkdir("root", 0755)); + ATF_REQUIRE_EQ(0, mkdir("root/etc", 0755)); + change_tz(tzcase->tzfn); + /* enter chroot */ + ATF_REQUIRE_EQ(0, chroot("root")); + ATF_REQUIRE_EQ(0, chdir("/")); + /* become setugid */ + ATF_REQUIRE_EQ(0, seteuid(UID_NOBODY)); + ATF_REQUIRE(issetugid()); + /* check timezone */ + unsetenv("TZ"); + test_tz(tzcases->expect); +} + +ATF_TC(tz_env_setugid); +ATF_TC_HEAD(tz_env_setugid, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test TZ environment variable " + "in setugid process"); + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(tz_env_setugid, tc) +{ + const struct tzcase *tzcase = tzcases; + + ATF_REQUIRE_EQ(0, seteuid(UID_NOBODY)); + ATF_REQUIRE(issetugid()); + for (tzcase = tzcases; tzcase->tzfn != NULL; tzcase++) + test_tz_env(tzcase->tzfn, tzcase->expect); +} + +ATF_TP_ADD_TCS(tp) +{ + debugging = !getenv("__RUNNING_INSIDE_ATF_RUN") && + isatty(STDERR_FILENO); + ATF_TP_ADD_TC(tp, thin_jail); +#ifdef DETECT_TZ_CHANGES + ATF_TP_ADD_TC(tp, detect_tz_changes); +#endif /* DETECT_TZ_CHANGES */ + ATF_TP_ADD_TC(tp, tz_env); + ATF_TP_ADD_TC(tp, setugid); + ATF_TP_ADD_TC(tp, tz_env_setugid); + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdtime/strptime_test.c b/lib/libc/tests/stdtime/strptime_test.c new file mode 100644 index 000000000000..79a97764999c --- /dev/null +++ b/lib/libc/tests/stdtime/strptime_test.c @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2024 Dag-Erling Smørgrav + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <time.h> + +#include <atf-c.h> + +ATF_TC_WITHOUT_HEAD(dayofweek); +ATF_TC_BODY(dayofweek, tc) +{ + static const struct { + const char *str; + int wday; + } cases[] = { + { "1582-12-20", 1 }, + { "1700-03-01", 1 }, + { "1752-09-14", 4 }, + { "1800-12-31", 3 }, + { "1801-01-01", 4 }, + { "1900-12-31", 1 }, + { "1901-01-01", 2 }, + { "2000-12-31", 0 }, + { "2001-01-01", 1 }, + { "2100-12-31", 5 }, + { "2101-01-01", 6 }, + { "2200-12-31", 3 }, + { "2201-01-01", 4 }, + { }, + }; + struct tm tm; + + for (unsigned int i = 0; cases[i].str != NULL; i++) { + if (strptime(cases[i].str, "%Y-%m-%d", &tm) == NULL) { + atf_tc_fail_nonfatal("failed to parse %s", + cases[i].str); + } else if (tm.tm_wday != cases[i].wday) { + atf_tc_fail_nonfatal("expected %d for %s, got %d", + cases[i].wday, cases[i].str, tm.tm_wday); + } + } +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, dayofweek); + return (atf_no_error()); +} diff --git a/lib/libc/tests/string/Makefile b/lib/libc/tests/string/Makefile index c6a98572564d..a019939c30af 100644 --- a/lib/libc/tests/string/Makefile +++ b/lib/libc/tests/string/Makefile @@ -1,13 +1,33 @@ -# $FreeBSD$ +# 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+= wcscasecmp_test -ATF_TESTS_C+= wcsnlen_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 # TODO: popcount, stresep @@ -17,16 +37,17 @@ NETBSD_ATF_TESTS_C+= memmem_test NETBSD_ATF_TESTS_C+= memset_test NETBSD_ATF_TESTS_C+= strcat_test 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/Makefile.depend b/lib/libc/tests/string/Makefile.depend index 8e6506e2f706..946944e9e951 100644 --- a/lib/libc/tests/string/Makefile.depend +++ b/lib/libc/tests/string/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ 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 new file mode 100644 index 000000000000..4b59385d712e --- /dev/null +++ b/lib/libc/tests/string/ffs_test.c @@ -0,0 +1,87 @@ +/*- + * 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 <limits.h> +#include <stdint.h> +#include <strings.h> + +#ifndef FFS +# define FFS ffs +# define TYPE int +# define TYPE_MIN INT_MIN +#endif + +ATF_TC_WITHOUT_HEAD(zero); +ATF_TC_BODY(zero, tc) +{ + ATF_CHECK_EQ((TYPE)0, FFS(0)); +} + +ATF_TC_WITHOUT_HEAD(twobit); +ATF_TC_BODY(twobit, tc) +{ + const TYPE one = 1; + TYPE x; + const int n = sizeof(TYPE) * CHAR_BIT; + int i, j; + + for (i = 0; i < n - 1; i++) + for (j = 0; j <= i; j++) { + x = one << i | one << j; + ATF_CHECK_EQ_MSG(j + 1, FFS(x), + "%s(%#jx) == %d != %d", __STRING(FFS), (intmax_t)x, FFS(x), j + 1); + } +} + +ATF_TC_WITHOUT_HEAD(twobitneg); +ATF_TC_BODY(twobitneg, tc) +{ + const TYPE one = 1; + TYPE x; + const int n = sizeof(TYPE) * CHAR_BIT; + int i, j; + + for (i = 0; i < n - 1; i++) + for (j = 0; j <= i; j++) { + x = one << i | one << j | TYPE_MIN; + ATF_CHECK_EQ_MSG(j + 1, FFS(x), + "%s(%#jx) == %d != %d", __STRING(FFS), (intmax_t)x, FFS(x), j + 1); + } +} + + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, zero); + ATF_TP_ADD_TC(tp, twobit); + ATF_TP_ADD_TC(tp, twobitneg); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/string/ffsl_test.c b/lib/libc/tests/string/ffsl_test.c new file mode 100644 index 000000000000..809cea3d3a93 --- /dev/null +++ b/lib/libc/tests/string/ffsl_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 FFS ffsl +#define TYPE long +#define TYPE_MIN LONG_MIN + +#include "ffs_test.c" diff --git a/lib/libc/tests/string/ffsll_test.c b/lib/libc/tests/string/ffsll_test.c new file mode 100644 index 000000000000..1a620cbf9aba --- /dev/null +++ b/lib/libc/tests/string/ffsll_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 FFS ffsll +#define TYPE long long +#define TYPE_MIN LLONG_MIN + +#include "ffs_test.c" diff --git a/lib/libc/tests/string/fls_test.c b/lib/libc/tests/string/fls_test.c new file mode 100644 index 000000000000..55691b36617c --- /dev/null +++ b/lib/libc/tests/string/fls_test.c @@ -0,0 +1,87 @@ +/*- + * 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 <limits.h> +#include <stdint.h> +#include <strings.h> + +#ifndef FLS +# define FLS fls +# define TYPE int +# define TYPE_MIN INT_MIN +#endif + +ATF_TC_WITHOUT_HEAD(zero); +ATF_TC_BODY(zero, tc) +{ + ATF_CHECK_EQ((TYPE)0, FLS(0)); +} + +ATF_TC_WITHOUT_HEAD(twobit); +ATF_TC_BODY(twobit, tc) +{ + const TYPE one = 1; + TYPE x; + const int n = sizeof(TYPE) * CHAR_BIT; + int i, j; + + for (i = 0; i < n - 1; i++) + for (j = 0; j <= i; j++) { + x = one << i | one << j; + ATF_CHECK_EQ_MSG(i + 1, FLS(x), + "%s(%#jx) == %d != %d", __STRING(FLS), (intmax_t)x, FLS(x), i + 1); + } +} + +ATF_TC_WITHOUT_HEAD(twobitneg); +ATF_TC_BODY(twobitneg, tc) +{ + const TYPE one = 1; + TYPE x; + const int n = sizeof(TYPE) * CHAR_BIT; + int i, j; + + for (i = 0; i < n - 1; i++) + for (j = 0; j <= i; j++) { + x = one << i | one << j | TYPE_MIN; + ATF_CHECK_EQ_MSG(n, FLS(x), + "%s(%#jx) == %d != %d", __STRING(FLS), (intmax_t)x, FLS(x), n); + } +} + + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, zero); + ATF_TP_ADD_TC(tp, twobit); + ATF_TP_ADD_TC(tp, twobitneg); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/string/flsl_test.c b/lib/libc/tests/string/flsl_test.c new file mode 100644 index 000000000000..4b1e330d4564 --- /dev/null +++ b/lib/libc/tests/string/flsl_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 FLS flsl +#define TYPE long +#define TYPE_MIN LONG_MIN + +#include "fls_test.c" diff --git a/lib/libc/tests/string/flsll_test.c b/lib/libc/tests/string/flsll_test.c new file mode 100644 index 000000000000..23f469b7b5de --- /dev/null +++ b/lib/libc/tests/string/flsll_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 FLS flsll +#define TYPE long long +#define TYPE_MIN LLONG_MIN + +#include "fls_test.c" 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 d7fbd8c342bd..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,22 +28,48 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #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); @@ -51,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); @@ -67,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); @@ -83,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 e0cfd867ff2a..c822a2ee4554 100644 --- a/lib/libc/tests/string/memset_s_test.c +++ b/lib/libc/tests/string/memset_s_test.c @@ -23,9 +23,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #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 618fa7d0a2ce..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,18 +28,18 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #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) { @@ -72,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'); @@ -81,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/strerror_test.c b/lib/libc/tests/string/strerror_test.c index 51bbf1765804..8f6cbfe38a59 100644 --- a/lib/libc/tests/string/strerror_test.c +++ b/lib/libc/tests/string/strerror_test.c @@ -22,8 +22,6 @@ * 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. - * - * $FreeBSD$ */ #include <assert.h> 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/strverscmp_test.c b/lib/libc/tests/string/strverscmp_test.c new file mode 100644 index 000000000000..fd6a2620cb48 --- /dev/null +++ b/lib/libc/tests/string/strverscmp_test.c @@ -0,0 +1,93 @@ +/*- +* SPDX-License-Identifier: BSD-2-Clause +* Copyright (c) 2022 Aymeric Wibo <obiwac@gmail.com> +*/ + +#include <atf-c.h> +#include <string.h> + +static void +check_all(size_t len, const char *ordered[len]) +{ + const char *a, *b; + + for (size_t i = 0; i < len; i++) { + for (size_t j = 0; j < len; j++) { + a = ordered[i]; + b = ordered[j]; + + if (i == j) + ATF_CHECK_MSG( + strverscmp(a, b) == 0, + "strverscmp(\"%s\", \"%s\") == 0", + a, b + ); + else if (i < j) + ATF_CHECK_MSG( + strverscmp(a, b) < 0, + "strverscmp(\"%s\", \"%s\") < 0", + a, b + ); + else if (i > j) + ATF_CHECK_MSG( + strverscmp(a, b) > 0, + "strverscmp(\"%s\", \"%s\") > 0", + a, b + ); + } + } +} + +#define CHECK_ALL(...) do { \ + const char *ordered[] = { __VA_ARGS__ }; \ + check_all(sizeof(ordered) / sizeof(*ordered), ordered); \ +} while (0) + +ATF_TC_WITHOUT_HEAD(strcmp_functionality); +ATF_TC_BODY(strcmp_functionality, tc) +{ + CHECK_ALL("", "a", "b"); +} + +/* from Linux man page strverscmp(3) */ + +ATF_TC_WITHOUT_HEAD(vers_ordering); +ATF_TC_BODY(vers_ordering, tc) +{ + CHECK_ALL("000", "00", "01", "010", "09", "0", "1", "9", "10"); +} + +ATF_TC_WITHOUT_HEAD(natural_ordering); +ATF_TC_BODY(natural_ordering, tc) +{ + CHECK_ALL("jan1", "jan2", "jan9", "jan10", "jan11", "jan19", "jan20"); +} + +/* https://sourceware.org/bugzilla/show_bug.cgi?id=9913 */ + +ATF_TC_WITHOUT_HEAD(glibc_bug_9913); +ATF_TC_BODY(glibc_bug_9913, tc) +{ + CHECK_ALL( + "B0075022800016.gbp.corp.com", + "B007502280067.gbp.corp.com", + "B007502357019.GBP.CORP.COM" + ); +} + +ATF_TC_WITHOUT_HEAD(semver_ordering); +ATF_TC_BODY(semver_ordering, tc) +{ + CHECK_ALL("2.6.20", "2.6.21"); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, strcmp_functionality); + ATF_TP_ADD_TC(tp, vers_ordering); + ATF_TP_ADD_TC(tp, natural_ordering); + ATF_TP_ADD_TC(tp, glibc_bug_9913); + ATF_TP_ADD_TC(tp, semver_ordering); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/string/strxfrm_test.c b/lib/libc/tests/string/strxfrm_test.c index 98f3b3bddee7..becc620ba79c 100644 --- a/lib/libc/tests/string/strxfrm_test.c +++ b/lib/libc/tests/string/strxfrm_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #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 4385f3a8f0d2..9a47c0d91b31 100644 --- a/lib/libc/tests/string/wcscasecmp_test.c +++ b/lib/libc/tests/string/wcscasecmp_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #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 022ad8e98297..2ce85bbb986b 100644 --- a/lib/libc/tests/string/wcscoll_test.c +++ b/lib/libc/tests/string/wcscoll_test.c @@ -26,9 +26,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #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 7bcd046de5af..ba2e1c8d7c57 100644 --- a/lib/libc/tests/string/wcsnlen_test.c +++ b/lib/libc/tests/string/wcsnlen_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/mman.h> #include <assert.h> diff --git a/lib/libc/tests/sys/Makefile b/lib/libc/tests/sys/Makefile index e4a1bf30a8f9..88f8191a16eb 100644 --- a/lib/libc/tests/sys/Makefile +++ b/lib/libc/tests/sys/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - PACKAGE= tests .include <bsd.own.mk> @@ -8,11 +6,12 @@ PACKAGE= tests ATF_TESTS_C+= brk_test .endif ATF_TESTS_C+= cpuset_test +ATF_TESTS_C+= errno_test +ATF_TESTS_C+= swapcontext_test ATF_TESTS_C+= queue_test ATF_TESTS_C+= sendfile_test -# TODO: clone, lwp_create, lwp_ctl, posix_fadvise, recvmmsg, -# swapcontext +# TODO: clone, lwp_create, lwp_ctl, posix_fadvise, recvmmsg NETBSD_ATF_TESTS_C+= access_test NETBSD_ATF_TESTS_C+= bind_test NETBSD_ATF_TESTS_C+= chroot_test @@ -74,6 +73,13 @@ NETBSD_ATF_TESTS_C+= write_test LIBADD.getpid_test+= pthread LIBADD.timer_create_test+= rt +# Message queue IPC tests need to be executed serially since they variously +# use global keys and exhaust global IPC limits. +TEST_METADATA.msgctl_test+= is_exclusive="true" +TEST_METADATA.msgget_test+= is_exclusive="true" +TEST_METADATA.msgsnd_test+= is_exclusive="true" +TEST_METADATA.msgrcv_test+= is_exclusive="true" + .include "../Makefile.netbsd-tests" SRCS.mlock_test+= mlock_helper.c diff --git a/lib/libc/tests/sys/Makefile.depend b/lib/libc/tests/sys/Makefile.depend index 0e9a9cda6452..c9d1296c4e9c 100644 --- a/lib/libc/tests/sys/Makefile.depend +++ b/lib/libc/tests/sys/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/sys/brk_test.c b/lib/libc/tests/sys/brk_test.c index 57b3d605e775..2d8c7af38ff7 100644 --- a/lib/libc/tests/sys/brk_test.c +++ b/lib/libc/tests/sys/brk_test.c @@ -1,5 +1,5 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 Mark Johnston <markj@FreeBSD.org> * @@ -25,9 +25,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/mman.h> diff --git a/lib/libc/tests/sys/cpuset_test.c b/lib/libc/tests/sys/cpuset_test.c index 52c0dc877ab8..53d6a8215bbc 100644 --- a/lib/libc/tests/sys/cpuset_test.c +++ b/lib/libc/tests/sys/cpuset_test.c @@ -25,9 +25,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD"); - #include <sys/param.h> #include <sys/cpuset.h> #include <sys/jail.h> diff --git a/lib/libc/tests/sys/errno_test.c b/lib/libc/tests/sys/errno_test.c new file mode 100644 index 000000000000..27d0548fc29d --- /dev/null +++ b/lib/libc/tests/sys/errno_test.c @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2024 The FreeBSD Foundation + * + * SPDX-License-Identifier: BSD-2-Clause + * + * This software were developed by Konstantin Belousov <kib@FreeBSD.org> + * under sponsorship from the FreeBSD Foundation. + */ + +#include <errno.h> +#include <unistd.h> + +#include <atf-c.h> + +ATF_TC(errno_basic); +ATF_TC_HEAD(errno_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify basic functionality of errno"); +} + +ATF_TC_BODY(errno_basic, tc) +{ + int res; + + res = unlink("/non/existent/file"); + ATF_REQUIRE(res == -1); + ATF_REQUIRE(errno == ENOENT); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, errno_basic); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/sys/mlock_helper.c b/lib/libc/tests/sys/mlock_helper.c index a483207aa5d6..e7a3d5e39c3f 100644 --- a/lib/libc/tests/sys/mlock_helper.c +++ b/lib/libc/tests/sys/mlock_helper.c @@ -28,9 +28,6 @@ * Helper for mlock(3) to avoid EAGAIN errors */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/types.h> #include <sys/sysctl.h> diff --git a/lib/libc/tests/sys/queue_test.c b/lib/libc/tests/sys/queue_test.c index 2405e3a69f5c..cfe9ac934cbd 100644 --- a/lib/libc/tests/sys/queue_test.c +++ b/lib/libc/tests/sys/queue_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/queue.h> #include <stdio.h> #include <stdlib.h> diff --git a/lib/libc/tests/sys/sendfile_test.c b/lib/libc/tests/sys/sendfile_test.c index c8df110c2a96..d46e7b0cb186 100644 --- a/lib/libc/tests/sys/sendfile_test.c +++ b/lib/libc/tests/sys/sendfile_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/mman.h> #include <sys/socket.h> diff --git a/lib/libc/tests/sys/swapcontext_test.c b/lib/libc/tests/sys/swapcontext_test.c new file mode 100644 index 000000000000..f341a746e515 --- /dev/null +++ b/lib/libc/tests/sys/swapcontext_test.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2025 Raptor Computing Systems, LLC + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ucontext.h> +#include <errno.h> + +#include <atf-c.h> + +#define STACK_SIZE (64ull << 10) + +static volatile int callback_reached = 0; + +static ucontext_t uctx_save, uctx_switch; + +static void swapcontext_callback() +{ + // Increment callback reached variable + // If this is called multiple times, we will fail the test + // If this is not called at all, we will fail the test + callback_reached++; +} + +ATF_TC(swapcontext_basic); +ATF_TC_HEAD(swapcontext_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify basic functionality of swapcontext"); +} + +ATF_TC_BODY(swapcontext_basic, tc) +{ + char *stack; + int res; + + stack = malloc(STACK_SIZE); + ATF_REQUIRE_MSG(stack != NULL, "malloc failed: %s", strerror(errno)); + res = getcontext(&uctx_switch); + ATF_REQUIRE_MSG(res == 0, "getcontext failed: %s", strerror(errno)); + + uctx_switch.uc_stack.ss_sp = stack; + uctx_switch.uc_stack.ss_size = STACK_SIZE; + uctx_switch.uc_link = &uctx_save; + makecontext(&uctx_switch, swapcontext_callback, 0); + + res = swapcontext(&uctx_save, &uctx_switch); + + ATF_REQUIRE_MSG(res == 0, "swapcontext failed: %s", strerror(errno)); + ATF_REQUIRE_MSG(callback_reached == 1, + "callback failed, reached %d times", callback_reached); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, swapcontext_basic); + + return (atf_no_error()); +} + diff --git a/lib/libc/tests/termios/Makefile b/lib/libc/tests/termios/Makefile index 0495d684b505..76879b805035 100644 --- a/lib/libc/tests/termios/Makefile +++ b/lib/libc/tests/termios/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> NETBSD_ATF_TESTS_C= tcsetpgrp_test diff --git a/lib/libc/tests/termios/Makefile.depend b/lib/libc/tests/termios/Makefile.depend index 10e58b789640..e89a5c52c82a 100644 --- a/lib/libc/tests/termios/Makefile.depend +++ b/lib/libc/tests/termios/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/time/Makefile b/lib/libc/tests/time/Makefile index feb543dad243..9e0230a70f54 100644 --- a/lib/libc/tests/time/Makefile +++ b/lib/libc/tests/time/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> NETBSD_ATF_TESTS_C= mktime_test diff --git a/lib/libc/tests/time/Makefile.depend b/lib/libc/tests/time/Makefile.depend index 10e58b789640..e89a5c52c82a 100644 --- a/lib/libc/tests/time/Makefile.depend +++ b/lib/libc/tests/time/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/tls/Makefile b/lib/libc/tests/tls/Makefile index 3cfaaadce590..6d53493f56f5 100644 --- a/lib/libc/tests/tls/Makefile +++ b/lib/libc/tests/tls/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> .if !defined(NO_PIC) diff --git a/lib/libc/tests/tls/Makefile.depend b/lib/libc/tests/tls/Makefile.depend index eae2edfd9e27..e53b1a169e02 100644 --- a/lib/libc/tests/tls/Makefile.depend +++ b/lib/libc/tests/tls/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/tls/dso/Makefile b/lib/libc/tests/tls/dso/Makefile index 84225f4a1d0e..5efd8b29a6bd 100644 --- a/lib/libc/tests/tls/dso/Makefile +++ b/lib/libc/tests/tls/dso/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libc/tls/${.CURDIR:T} LIB= h_tls_dlopen @@ -7,6 +5,7 @@ SHLIB_NAME= h_tls_dlopen.so SRCS= h_tls_dlopen.c MAN= +PACKAGE= tests LIBDIR= ${TESTSBASE}/lib/libc/tls SHLIB_MAJOR= 1 diff --git a/lib/libc/tests/tls/dso/Makefile.depend b/lib/libc/tests/tls/dso/Makefile.depend index c062f6026d94..1af0c88e099c 100644 --- a/lib/libc/tests/tls/dso/Makefile.depend +++ b/lib/libc/tests/tls/dso/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/tls_dso/Makefile b/lib/libc/tests/tls_dso/Makefile index 5449799de96c..89296c643695 100644 --- a/lib/libc/tests/tls_dso/Makefile +++ b/lib/libc/tests/tls_dso/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> LIB= h_tls_dynamic @@ -8,6 +6,7 @@ SRCS= h_tls_dynamic.c LIBDIR= ${TESTSBASE}/lib/libc/tls SHLIBDIR= ${TESTSBASE}/lib/libc/tls SHLIB_MAJOR= 1 +PACKAGE= tests WITHOUT_STATIC= WITHOUT_PROFILE= diff --git a/lib/libc/tests/tls_dso/Makefile.depend b/lib/libc/tests/tls_dso/Makefile.depend index 1c1a9bee1d67..93249906da4f 100644 --- a/lib/libc/tests/tls_dso/Makefile.depend +++ b/lib/libc/tests/tls_dso/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/ttyio/Makefile b/lib/libc/tests/ttyio/Makefile index d5b8f0168558..2d2dda2f854f 100644 --- a/lib/libc/tests/ttyio/Makefile +++ b/lib/libc/tests/ttyio/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> # TODO: ptm_test diff --git a/lib/libc/tests/ttyio/Makefile.depend b/lib/libc/tests/ttyio/Makefile.depend index 1b5e74fae1b0..9df74fa6efd2 100644 --- a/lib/libc/tests/ttyio/Makefile.depend +++ b/lib/libc/tests/ttyio/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ |