Module Name: src Committed By: riastradh Date: Fri Mar 28 18:41:55 UTC 2025
Modified Files: src/distrib/sets/lists/debug: mi src/distrib/sets/lists/tests: mi src/tests/lib/libc/gen: Makefile Added Files: src/tests/lib/libc/gen: t_ctype.c Log Message: t_ctype: New test for ctype(3) functions/macros. PR lib/58208: ctype(3) provides poor runtime feedback of abuse To generate a diff of this commit: cvs rdiff -u -r1.469 -r1.470 src/distrib/sets/lists/debug/mi cvs rdiff -u -r1.1361 -r1.1362 src/distrib/sets/lists/tests/mi cvs rdiff -u -r1.57 -r1.58 src/tests/lib/libc/gen/Makefile cvs rdiff -u -r0 -r1.1 src/tests/lib/libc/gen/t_ctype.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/debug/mi diff -u src/distrib/sets/lists/debug/mi:1.469 src/distrib/sets/lists/debug/mi:1.470 --- src/distrib/sets/lists/debug/mi:1.469 Thu Mar 13 01:27:27 2025 +++ src/distrib/sets/lists/debug/mi Fri Mar 28 18:41:55 2025 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.469 2025/03/13 01:27:27 riastradh Exp $ +# $NetBSD: mi,v 1.470 2025/03/28 18:41:55 riastradh Exp $ # ./etc/mtree/set.debug comp-sys-root ./usr/lib comp-sys-usr compatdir @@ -2029,6 +2029,7 @@ ./usr/libdata/debug/usr/tests/lib/libc/gen/t_basedirname.debug tests-lib-debug debug,atf,compattestfile ./usr/libdata/debug/usr/tests/lib/libc/gen/t_closefrom.debug tests-lib-debug debug,atf,compattestfile ./usr/libdata/debug/usr/tests/lib/libc/gen/t_cpuset.debug tests-lib-debug debug,atf,compattestfile +./usr/libdata/debug/usr/tests/lib/libc/gen/t_ctype.debug tests-lib-debug debug,atf,compattestfile ./usr/libdata/debug/usr/tests/lib/libc/gen/t_dir.debug tests-lib-debug debug,atf,compattestfile ./usr/libdata/debug/usr/tests/lib/libc/gen/t_floatunditf.debug tests-lib-debug debug,atf,compattestfile ./usr/libdata/debug/usr/tests/lib/libc/gen/t_fmtcheck.debug tests-lib-debug debug,atf,compattestfile Index: src/distrib/sets/lists/tests/mi diff -u src/distrib/sets/lists/tests/mi:1.1361 src/distrib/sets/lists/tests/mi:1.1362 --- src/distrib/sets/lists/tests/mi:1.1361 Thu Mar 13 01:27:27 2025 +++ src/distrib/sets/lists/tests/mi Fri Mar 28 18:41:55 2025 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.1361 2025/03/13 01:27:27 riastradh Exp $ +# $NetBSD: mi,v 1.1362 2025/03/28 18:41:55 riastradh Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -3009,6 +3009,7 @@ ./usr/tests/lib/libc/gen/t_basedirname tests-lib-tests compattestfile,atf ./usr/tests/lib/libc/gen/t_closefrom tests-lib-tests compattestfile,atf ./usr/tests/lib/libc/gen/t_cpuset tests-lib-tests compattestfile,atf +./usr/tests/lib/libc/gen/t_ctype tests-lib-tests compattestfile,atf ./usr/tests/lib/libc/gen/t_dir tests-lib-tests compattestfile,atf ./usr/tests/lib/libc/gen/t_floatunditf tests-lib-tests compattestfile,atf ./usr/tests/lib/libc/gen/t_fmtcheck tests-lib-tests compattestfile,atf Index: src/tests/lib/libc/gen/Makefile diff -u src/tests/lib/libc/gen/Makefile:1.57 src/tests/lib/libc/gen/Makefile:1.58 --- src/tests/lib/libc/gen/Makefile:1.57 Thu Mar 13 01:27:27 2025 +++ src/tests/lib/libc/gen/Makefile Fri Mar 28 18:41:55 2025 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.57 2025/03/13 01:27:27 riastradh Exp $ +# $NetBSD: Makefile,v 1.58 2025/03/28 18:41:55 riastradh Exp $ NOMAN= # defined @@ -16,6 +16,7 @@ TESTS_C+= t_assert TESTS_C+= t_basedirname TESTS_C+= t_closefrom TESTS_C+= t_cpuset +TESTS_C+= t_ctype TESTS_C+= t_dir TESTS_C+= t_floatunditf TESTS_C+= t_fmtcheck Added files: Index: src/tests/lib/libc/gen/t_ctype.c diff -u /dev/null src/tests/lib/libc/gen/t_ctype.c:1.1 --- /dev/null Fri Mar 28 18:41:55 2025 +++ src/tests/lib/libc/gen/t_ctype.c Fri Mar 28 18:41:55 2025 @@ -0,0 +1,944 @@ +/* $NetBSD: t_ctype.c,v 1.1 2025/03/28 18:41:55 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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> +__RCSID("$NetBSD: t_ctype.c,v 1.1 2025/03/28 18:41:55 riastradh Exp $"); + +#include <atf-c.h> +#include <ctype.h> +#include <locale.h> +#include <limits.h> +#include <setjmp.h> +#include <signal.h> +#include <stdio.h> + +#include "h_macros.h" + +static const char *locales[] = { "C.UTF-8", "fr_FR.ISO8859-1" }; + +static int isalpha_wrapper(int ch) { return isalpha(ch); } +static int isupper_wrapper(int ch) { return isupper(ch); } +static int islower_wrapper(int ch) { return islower(ch); } +static int isdigit_wrapper(int ch) { return isdigit(ch); } +static int isxdigit_wrapper(int ch) { return isxdigit(ch); } +static int isalnum_wrapper(int ch) { return isalnum(ch); } +static int isspace_wrapper(int ch) { return isspace(ch); } +static int ispunct_wrapper(int ch) { return ispunct(ch); } +static int isprint_wrapper(int ch) { return isprint(ch); } +static int isgraph_wrapper(int ch) { return isgraph(ch); } +static int iscntrl_wrapper(int ch) { return iscntrl(ch); } +static int isblank_wrapper(int ch) { return isblank(ch); } +static int toupper_wrapper(int ch) { return toupper(ch); } +static int tolower_wrapper(int ch) { return tolower(ch); } + +#ifndef __CHAR_UNSIGNED__ +jmp_buf env; + +static void +handle_sigsegv(int signo) +{ + + longjmp(env, 1); +} +#endif + +static void +test_abuse(const char *name, int (*ctypefn)(int)) +{ +#ifdef __CHAR_UNSIGNED__ + atf_tc_skip("runtime ctype(3) abuse is impossible with unsigned char"); +#else + volatile int ch; /* for longjmp */ + + for (ch = CHAR_MIN; ch < 0; ch++) { + void (*h)(int) = SIG_DFL; + volatile int result; + + if (ch == EOF) + continue; + ATF_REQUIRE_MSG(ch != (int)(unsigned char)ch, "ch=%d", ch); + if (setjmp(env) == 0) { + REQUIRE_LIBC(h = signal(SIGSEGV, &handle_sigsegv), + SIG_ERR); + result = (*ctypefn)(ch); + REQUIRE_LIBC(signal(SIGSEGV, h), SIG_ERR); + atf_tc_fail_nonfatal("%s failed to detect invalid %d," + " returned %d", + name, ch, result); + } else { + REQUIRE_LIBC(signal(SIGSEGV, h), SIG_ERR); + } + } + + for (; ch <= CHAR_MAX; ch++) + ATF_REQUIRE_MSG(ch == (int)(unsigned char)ch, "ch=%d", ch); +#endif +} + +static void +test_use(const char *name, int (*ctypefn)(int)) +{ + volatile int ch; /* for longjmp */ + + for (ch = EOF; ch <= CHAR_MAX; ch = (ch == EOF ? 0 : ch + 1)) { + void (*h)(int) = SIG_DFL; + volatile int result; + + if (setjmp(env) == 0) { + REQUIRE_LIBC(h = signal(SIGSEGV, &handle_sigsegv), + SIG_ERR); + result = (*ctypefn)(ch); + REQUIRE_LIBC(signal(SIGSEGV, h), SIG_ERR); + (void)result; + } else { + atf_tc_fail_nonfatal("%s(%d) raised SIGSEGV", + name, ch); + REQUIRE_LIBC(signal(SIGSEGV, h), SIG_ERR); + } + } +} + +static void +test_isalpha_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isalpha", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isupper_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isupper", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_islower_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("islower", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isdigit_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isdigit", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isxdigit_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isxdigit", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isalnum_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isalnum", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isspace_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isspace", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_ispunct_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("ispunct", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isprint_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isprint", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isgraph_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isgraph", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_iscntrl_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("iscntrl", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isblank_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isblank", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_toupper_locale(const char *L, int (*ctypefn)(int)) +{ + int result; + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("toupper", ctypefn); + ATF_CHECK_MSG((result = (*ctypefn)(EOF)) == EOF, + "result=%d, expected EOF=%d", result, EOF); +} + +static void +test_tolower_locale(const char *L, int (*ctypefn)(int)) +{ + int result; + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("tolower", ctypefn); + ATF_CHECK_MSG((result = (*ctypefn)(EOF)) == EOF, + "result=%d, expected EOF=%d", result, EOF); +} + +static void +test_isalpha_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + case 'a': case 'A': + case 'b': case 'B': + case 'c': case 'C': + case 'd': case 'D': + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + case 'h': case 'H': + case 'i': case 'I': + case 'j': case 'J': + case 'k': case 'K': + case 'l': case 'L': + case 'm': case 'M': + case 'n': case 'N': + case 'o': case 'O': + case 'p': case 'P': + case 'q': case 'Q': + case 'r': case 'R': + case 's': case 'S': + case 't': case 'T': + case 'u': case 'U': + case 'v': case 'V': + case 'w': case 'W': + case 'x': case 'X': + case 'y': case 'Y': + case 'z': case 'Z': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isupper_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_islower_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isdigit_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isxdigit_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'a': case 'A': + case 'b': case 'B': + case 'c': case 'C': + case 'd': case 'D': + case 'e': case 'E': + case 'f': case 'F': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isalnum_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + case 'a': case 'A': + case 'b': case 'B': + case 'c': case 'C': + case 'd': case 'D': + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + case 'h': case 'H': + case 'i': case 'I': + case 'j': case 'J': + case 'k': case 'K': + case 'l': case 'L': + case 'm': case 'M': + case 'n': case 'N': + case 'o': case 'O': + case 'p': case 'P': + case 'q': case 'Q': + case 'r': case 'R': + case 's': case 'S': + case 't': case 'T': + case 'u': case 'U': + case 'v': case 'V': + case 'w': case 'W': + case 'x': case 'X': + case 'y': case 'Y': + case 'z': case 'Z': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isspace_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + case ' ': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_ispunct_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + default: + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + case 0 ... 0x1f: + case 0x20: /* space is printing but not punctuation */ + case 0x7f: + case 0x80 ... 0xff: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + case 'a': case 'A': + case 'b': case 'B': + case 'c': case 'C': + case 'd': case 'D': + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + case 'h': case 'H': + case 'i': case 'I': + case 'j': case 'J': + case 'k': case 'K': + case 'l': case 'L': + case 'm': case 'M': + case 'n': case 'N': + case 'o': case 'O': + case 'p': case 'P': + case 'q': case 'Q': + case 'r': case 'R': + case 's': case 'S': + case 't': case 'T': + case 'u': case 'U': + case 'v': case 'V': + case 'w': case 'W': + case 'x': case 'X': + case 'y': case 'Y': + case 'z': case 'Z': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isprint_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + case 0x20: /* space is printing but not graphic */ + default: + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + case 0 ... 0x1f: + case 0x7f: + case 0x80 ... 0xff: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isgraph_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + default: + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + case 0 ... 0x1f: + case 0x20: /* space is printing but not graphic */ + case 0x7f: + case 0x80 ... 0xff: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_iscntrl_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + case 0 ... 0x1f: + case 0x7f: + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isblank_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + case ' ': + case '\t': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_toupper_c(int (*ctypefn)(int)) +{ + int ch, result, expected; + + ATF_CHECK_MSG((result = (*ctypefn)(EOF)) == EOF, + "result=%d, expected EOF=%d", result, EOF); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + case 'a': case 'A': expected = 'A'; break; + case 'b': case 'B': expected = 'B'; break; + case 'c': case 'C': expected = 'C'; break; + case 'd': case 'D': expected = 'D'; break; + case 'e': case 'E': expected = 'E'; break; + case 'f': case 'F': expected = 'F'; break; + case 'g': case 'G': expected = 'G'; break; + case 'h': case 'H': expected = 'H'; break; + case 'i': case 'I': expected = 'I'; break; + case 'j': case 'J': expected = 'J'; break; + case 'k': case 'K': expected = 'K'; break; + case 'l': case 'L': expected = 'L'; break; + case 'm': case 'M': expected = 'M'; break; + case 'n': case 'N': expected = 'N'; break; + case 'o': case 'O': expected = 'O'; break; + case 'p': case 'P': expected = 'P'; break; + case 'q': case 'Q': expected = 'Q'; break; + case 'r': case 'R': expected = 'R'; break; + case 's': case 'S': expected = 'S'; break; + case 't': case 'T': expected = 'T'; break; + case 'u': case 'U': expected = 'U'; break; + case 'v': case 'V': expected = 'V'; break; + case 'w': case 'W': expected = 'W'; break; + case 'x': case 'X': expected = 'X'; break; + case 'y': case 'Y': expected = 'Y'; break; + case 'z': case 'Z': expected = 'Z'; break; + default: + expected = ch; + break; + } + ATF_CHECK_MSG((result = (*ctypefn)(ch)) == expected, + "result=%d expected=%d", result, expected); + } +} + +static void +test_tolower_c(int (*ctypefn)(int)) +{ + int ch, result, expected; + + ATF_CHECK_MSG((result = (*ctypefn)(EOF)) == EOF, + "result=%d, expected EOF=%d", result, EOF); + for (ch = 0; ch < UCHAR_MAX; ch++) { + switch (ch) { + case 'a': case 'A': expected = 'a'; break; + case 'b': case 'B': expected = 'b'; break; + case 'c': case 'C': expected = 'c'; break; + case 'd': case 'D': expected = 'd'; break; + case 'e': case 'E': expected = 'e'; break; + case 'f': case 'F': expected = 'f'; break; + case 'g': case 'G': expected = 'g'; break; + case 'h': case 'H': expected = 'h'; break; + case 'i': case 'I': expected = 'i'; break; + case 'j': case 'J': expected = 'j'; break; + case 'k': case 'K': expected = 'k'; break; + case 'l': case 'L': expected = 'l'; break; + case 'm': case 'M': expected = 'm'; break; + case 'n': case 'N': expected = 'n'; break; + case 'o': case 'O': expected = 'o'; break; + case 'p': case 'P': expected = 'p'; break; + case 'q': case 'Q': expected = 'q'; break; + case 'r': case 'R': expected = 'r'; break; + case 's': case 'S': expected = 's'; break; + case 't': case 'T': expected = 't'; break; + case 'u': case 'U': expected = 'u'; break; + case 'v': case 'V': expected = 'v'; break; + case 'w': case 'W': expected = 'w'; break; + case 'x': case 'X': expected = 'x'; break; + case 'y': case 'Y': expected = 'y'; break; + case 'z': case 'Z': expected = 'z'; break; + default: + expected = ch; + break; + } + ATF_CHECK_MSG((result = (*ctypefn)(ch)) == expected, + "result=%d expected=%d", result, expected); + } +} + +#define ADD_TEST_ABUSE(TP, FN) do \ +{ \ + ATF_TP_ADD_TC(TP, abuse_##FN##_macro_c); \ + ATF_TP_ADD_TC(TP, abuse_##FN##_function_c); \ + ATF_TP_ADD_TC(TP, abuse_##FN##_macro_locale); \ + ATF_TP_ADD_TC(TP, abuse_##FN##_function_locale); \ +} while (0) + +#define DEF_TEST_ABUSE(FN) \ +ATF_TC(abuse_##FN##_macro_c); \ +ATF_TC_HEAD(abuse_##FN##_macro_c, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test abusing "#FN" macro with default LC_CTYPE=C"); \ +} \ +ATF_TC_BODY(abuse_##FN##_macro_c, tc) \ +{ \ + atf_tc_expect_fail("PR lib/58208:" \ + " ctype(3) provides poor runtime feedback of abuse"); \ + test_abuse(#FN, &FN##_wrapper); \ +} \ +ATF_TC(abuse_##FN##_function_c); \ +ATF_TC_HEAD(abuse_##FN##_function_c, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test abusing "#FN" function with default LC_CTYPE=C"); \ +} \ +ATF_TC_BODY(abuse_##FN##_function_c, tc) \ +{ \ + atf_tc_expect_fail("PR lib/58208:" \ + " ctype(3) provides poor runtime feedback of abuse"); \ + test_abuse(#FN, &FN); \ +} \ +ATF_TC(abuse_##FN##_macro_locale); \ +ATF_TC_HEAD(abuse_##FN##_macro_locale, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test abusing "#FN" macro with locales"); \ +} \ +ATF_TC_BODY(abuse_##FN##_macro_locale, tc) \ +{ \ + size_t i; \ + \ + atf_tc_expect_fail("PR lib/58208:" \ + " ctype(3) provides poor runtime feedback of abuse"); \ + for (i = 0; i < __arraycount(locales); i++) { \ + char buf[128]; \ + \ + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, locales[i]) != NULL, \ + "locales[i]=%s", locales[i]); \ + snprintf(buf, sizeof(buf), "[%s]%s", locales[i], #FN); \ + test_abuse(buf, &FN##_wrapper); \ + } \ +} \ +ATF_TC(abuse_##FN##_function_locale); \ +ATF_TC_HEAD(abuse_##FN##_function_locale, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test abusing "#FN" function with locales"); \ +} \ +ATF_TC_BODY(abuse_##FN##_function_locale, tc) \ +{ \ + size_t i; \ + \ + atf_tc_expect_fail("PR lib/58208:" \ + " ctype(3) provides poor runtime feedback of abuse"); \ + for (i = 0; i < __arraycount(locales); i++) { \ + char buf[128]; \ + \ + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, locales[i]) != NULL, \ + "locales[i]=%s", locales[i]); \ + snprintf(buf, sizeof(buf), "[%s]%s", locales[i], #FN); \ + test_abuse(buf, &FN); \ + } \ +} + +#define ADD_TEST_USE(TP, FN) do \ +{ \ + ATF_TP_ADD_TC(TP, FN##_macro_c); \ + ATF_TP_ADD_TC(TP, FN##_function_c); \ + ATF_TP_ADD_TC(TP, FN##_macro_locale); \ + ATF_TP_ADD_TC(TP, FN##_function_locale); \ +} while (0) + +#define DEF_TEST_USE(FN) \ +ATF_TC(FN##_macro_c); \ +ATF_TC_HEAD(FN##_macro_c, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test "#FN" macro with default LC_CTYPE=C"); \ +} \ +ATF_TC_BODY(FN##_macro_c, tc) \ +{ \ + test_##FN##_c(&FN##_wrapper); \ +} \ +ATF_TC(FN##_function_c); \ +ATF_TC_HEAD(FN##_function_c, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test "#FN" function with default LC_CTYPE=C"); \ +} \ +ATF_TC_BODY(FN##_function_c, tc) \ +{ \ + test_##FN##_c(&FN); \ +} \ +ATF_TC(FN##_macro_locale); \ +ATF_TC_HEAD(FN##_macro_locale, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test "#FN" macro with locales"); \ +} \ +ATF_TC_BODY(FN##_macro_locale, tc) \ +{ \ + size_t i; \ + \ + for (i = 0; i < __arraycount(locales); i++) \ + test_##FN##_locale(locales[i], &FN##_wrapper); \ +} \ +ATF_TC(FN##_function_locale); \ +ATF_TC_HEAD(FN##_function_locale, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test "#FN" function with locales"); \ +} \ +ATF_TC_BODY(FN##_function_locale, tc) \ +{ \ + size_t i; \ + \ + for (i = 0; i < __arraycount(locales); i++) \ + test_##FN##_locale(locales[i], &FN); \ +} + +DEF_TEST_ABUSE(isalpha) +DEF_TEST_ABUSE(isupper) +DEF_TEST_ABUSE(islower) +DEF_TEST_ABUSE(isdigit) +DEF_TEST_ABUSE(isxdigit) +DEF_TEST_ABUSE(isalnum) +DEF_TEST_ABUSE(isspace) +DEF_TEST_ABUSE(ispunct) +DEF_TEST_ABUSE(isprint) +DEF_TEST_ABUSE(isgraph) +DEF_TEST_ABUSE(iscntrl) +DEF_TEST_ABUSE(isblank) +DEF_TEST_ABUSE(toupper) +DEF_TEST_ABUSE(tolower) + +DEF_TEST_USE(isalpha) +DEF_TEST_USE(isupper) +DEF_TEST_USE(islower) +DEF_TEST_USE(isdigit) +DEF_TEST_USE(isxdigit) +DEF_TEST_USE(isalnum) +DEF_TEST_USE(isspace) +DEF_TEST_USE(ispunct) +DEF_TEST_USE(isprint) +DEF_TEST_USE(isgraph) +DEF_TEST_USE(iscntrl) +DEF_TEST_USE(isblank) +DEF_TEST_USE(toupper) +DEF_TEST_USE(tolower) + +ATF_TP_ADD_TCS(tp) +{ + + ADD_TEST_ABUSE(tp, isalpha); + ADD_TEST_ABUSE(tp, isupper); + ADD_TEST_ABUSE(tp, islower); + ADD_TEST_ABUSE(tp, isdigit); + ADD_TEST_ABUSE(tp, isxdigit); + ADD_TEST_ABUSE(tp, isalnum); + ADD_TEST_ABUSE(tp, isspace); + ADD_TEST_ABUSE(tp, ispunct); + ADD_TEST_ABUSE(tp, isprint); + ADD_TEST_ABUSE(tp, isgraph); + ADD_TEST_ABUSE(tp, iscntrl); + ADD_TEST_ABUSE(tp, isblank); + ADD_TEST_ABUSE(tp, toupper); + ADD_TEST_ABUSE(tp, tolower); + + ADD_TEST_USE(tp, isalpha); + ADD_TEST_USE(tp, isupper); + ADD_TEST_USE(tp, islower); + ADD_TEST_USE(tp, isdigit); + ADD_TEST_USE(tp, isxdigit); + ADD_TEST_USE(tp, isalnum); + ADD_TEST_USE(tp, isspace); + ADD_TEST_USE(tp, ispunct); + ADD_TEST_USE(tp, isprint); + ADD_TEST_USE(tp, isgraph); + ADD_TEST_USE(tp, iscntrl); + ADD_TEST_USE(tp, isblank); + ADD_TEST_USE(tp, toupper); + ADD_TEST_USE(tp, tolower); + + return atf_no_error(); +}