Index: include/string.h =================================================================== --- include/string.h +++ include/string.h @@ -154,8 +154,31 @@ typedef int errno_t; #endif -/* ISO/IEC 9899:2011 K.3.7.4.1.1 */ +/* ISO/IEC 9899:2011 K.3.7.1.1 */ +errno_t memcpy_s(void * __restrict, rsize_t, const void * __restrict, rsize_t); +/* ISO/IEC 9899:2011 K.3.7.1.2 */ +errno_t memmove_s(void *, rsize_t, const void *, rsize_t); +/* ISO/IEC 9899:2011 K.3.7.1.3 */ +errno_t strcpy_s(char * __restrict, rsize_t, const char * __restrict); +/* ISO/IEC 9899:2011 K.3.7.1.4 */ +errno_t strncpy_s(char * __restrict, rsize_t, const char * __restrict, + rsize_t); +/* ISO/IEC 9899:2011 K.3.7.2.1 */ +errno_t strcat_s(char * __restrict, rsize_t, const char * __restrict); +/* ISO/IEC 9899:2011 K.3.7.2.2 */ +errno_t strncat_s(char * __restrict, rsize_t, const char * __restrict, + rsize_t); +/* ISO/IEC 9899:2011 K.3.7.3.1 */ +char *strtok_s(char * __restrict, rsize_t * __restrict, + const char * __restrict, char ** __restrict); +/* ISO/IEC 9899:2011 K.3.7.4.1 */ errno_t memset_s(void *, rsize_t, int, rsize_t); +/* ISO/IEC 9899:2011 K.3.7.4.2 */ +errno_t strerror_s(char *, rsize_t, errno_t); +/* ISO/IEC 9899:2011 K.3.7.4.3 */ +size_t strerrorlen_s(errno_t); +/* ISO/IEC 9899:2011 K.3.7.4.4 */ +size_t strnlen_s(const char *, size_t); #endif /* __EXT1_VISIBLE */ __END_DECLS Index: lib/libc/string/Makefile.inc =================================================================== --- lib/libc/string/Makefile.inc +++ lib/libc/string/Makefile.inc @@ -9,17 +9,16 @@ # machine-independent string sources MISRCS+=bcmp.c bcopy.c bzero.c explicit_bzero.c \ ffs.c ffsl.c ffsll.c fls.c flsl.c flsll.c \ - memccpy.c memchr.c memrchr.c memcmp.c \ - memcpy.c memmem.c memmove.c memset.c memset_s.c \ - stpcpy.c stpncpy.c strcasecmp.c \ - strcat.c strcasestr.c strchr.c strchrnul.c strcmp.c strcoll.c strcpy.c\ - strcspn.c strdup.c strerror.c strlcat.c strlcpy.c strlen.c strmode.c \ - strncat.c strncmp.c strncpy.c strndup.c strnlen.c strnstr.c \ - strpbrk.c strrchr.c strsep.c strsignal.c strspn.c strstr.c strtok.c \ - strxfrm.c swab.c \ - timingsafe_bcmp.c \ - timingsafe_memcmp.c \ - wcpcpy.c wcpncpy.c wcscasecmp.c wcscat.c \ + memccpy.c memchr.c memrchr.c memcmp.c memcpy.c memcpy_s.c \ + memmem.c memmove.c memmove_s.c memset.c memset_s.c stpcpy.c \ + stpncpy.c strcasecmp.c strcat.c strcat_s.c strcasestr.c \ + strchr.c strchrnul.c strcmp.c strcoll.c strcpy.c strcpy_s.c \ + strcspn.c strdup.c strerror.c strerror_s.c strerrorlen_s.c \ + strlcat.c strlcpy.c strlen.c strmode.c strncat.c strncat_s.c \ + strncmp.c strncpy.c strncpy_s.c strndup.c strnlen.c strnlen_s.c \ + strnstr.c strpbrk.c strrchr.c strsep.c strsignal.c strspn.c \ + strstr.c strtok.c strtok_s.c strxfrm.c swab.c timingsafe_bcmp.c \ + timingsafe_memcmp.c wcpcpy.c wcpncpy.c wcscasecmp.c wcscat.c \ wcschr.c wcscmp.c wcscoll.c wcscpy.c wcscspn.c wcsdup.c \ wcslcat.c wcslcpy.c wcslen.c wcsncasecmp.c wcsncat.c wcsncmp.c \ wcsncpy.c wcsnlen.c wcspbrk.c \ Index: lib/libc/string/Symbol.map =================================================================== --- lib/libc/string/Symbol.map +++ lib/libc/string/Symbol.map @@ -105,7 +105,17 @@ }; FBSD_1.5 { + memcpy_s; + memmove_s; memset_s; + strcat_s; + strcpy_s; + strerror_s; + strerrorlen_s; + strncat_s; + strncpy_s; + strnlen_s; + strtok_s; timingsafe_bcmp; timingsafe_memcmp; }; Index: lib/libc/string/memcpy_s.c =================================================================== --- /dev/null +++ lib/libc/string/memcpy_s.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include "libc_private.h" + +/* ISO/IEC 9899:2011 K.3.7.1.1 */ +errno_t memcpy_s(void * __restrict s1, rsize_t s1max, + const void * __restrict s2, rsize_t n) +{ + rsize_t lim; + uintptr_t s1e, s2e; + errno_t ret; + int zero_fill; + + ret = EINVAL; + zero_fill = 0; + + if (s1 == NULL) { + __throw_constraint_handler_s("memcpy_s : s1 is NULL", ret); + } else if (s1max > RSIZE_MAX) { + __throw_constraint_handler_s("memcpy_s : s1max > RSIZE_MAX", + ret); + } else if (s2 == NULL) { + zero_fill = 1; + __throw_constraint_handler_s("memcpy_s : s2 is NULL", ret); + } else if (n > RSIZE_MAX) { + zero_fill = 1; + __throw_constraint_handler_s("memcpy_s : n > RSIZE_MAX", ret); + } else { + lim = s1max; + if (n < s1max) + lim = n; + if (lim > 0) { + s1e = (uintptr_t) s1 + lim; + s2e = (uintptr_t) s2 + lim; + if (((uintptr_t) s1 >= (uintptr_t) s2 && + (uintptr_t) s1 < s2e) || + ((uintptr_t) s2 >= (uintptr_t) s1 && + (uintptr_t) s2 < s1e)) { + /* do not zero fill on overlap */ + __throw_constraint_handler_s( + "memcpy_s : memory overlaps", ret); + } else { + memcpy(s1, s2, lim); + ret = 0; + } + } else { + /* trivial, do nothing */ + ret = 0; + } + } + if (ret && zero_fill) + memset_s(s1, s1max, 0, s1max); + return (ret); +} Index: lib/libc/string/memmove_s.c =================================================================== --- /dev/null +++ lib/libc/string/memmove_s.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include "libc_private.h" + +/* ISO/IEC 9899:2011 K.3.7.1.2 */ +errno_t memmove_s(void * s1, rsize_t s1max, const void *s2, rsize_t n) +{ + rsize_t lim; + errno_t ret; + int zero_fill; + + ret = EINVAL; + zero_fill = 0; + + if (s1 == NULL) { + __throw_constraint_handler_s("memmove_s : s1 is NULL", ret); + } else if (s1max > RSIZE_MAX) { + __throw_constraint_handler_s("memmove_s : s1max > RSIZE_MAX", + ret); + } else if (s2 == NULL) { + zero_fill = 1; + __throw_constraint_handler_s("memmove_s : s2 is NULL", ret); + } else if (n > RSIZE_MAX) { + zero_fill = 1; + __throw_constraint_handler_s("memmove_s : n > RSIZE_MAX", ret); + } else { + lim = s1max; + if (n < s1max) + lim = n; + /* assume trival noop */ + ret = 0; + if (lim > 0) + memmove(s1, s2, lim); + } + if (ret && zero_fill) + memset_s(s1, s1max, 0, s1max); + return (ret); +} Index: lib/libc/string/strcat_s.c =================================================================== --- /dev/null +++ lib/libc/string/strcat_s.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include "libc_private.h" + +/* ISO/IEC 9899:2011 K.3.7.2.1 */ +errno_t strcat_s(char * __restrict s1, rsize_t s1max, + const char * __restrict s2) +{ + rsize_t lim; + uintptr_t s1e, s2e; + errno_t ret; + size_t m, n; + int zero_fill; + + ret = EINVAL; + zero_fill = 0; + if (s1 == NULL) { + __throw_constraint_handler_s("strcat_s : s1 is NULL", ret); + } else if (s1max > RSIZE_MAX) { + __throw_constraint_handler_s("strcat_s : s1max > RSIZE_MAX", + ret); + } else if (s1max == 0) { + __throw_constraint_handler_s("strcat_s : s1max == 0", ret); + } else if (s2 == NULL) { + zero_fill = 1; + __throw_constraint_handler_s("strcat_s : s2 is NULL", ret); + } else { + m = s1max - strnlen_s(s1, s1max); + if (m == 0) { + zero_fill = 1; + __throw_constraint_handler_s("strcat_s : s1 is full", + ret); + } else { + n = strnlen_s(s2, m); + if (n >= m) { + zero_fill = 1; + __throw_constraint_handler_s( + "strcat_s : s1 will overflow", ret); + } else { + lim = n; + if (lim > 0) { + s1e = (uintptr_t) s1 + m; + s2e = (uintptr_t) s2 + n; + if (((uintptr_t) s1 >= + (uintptr_t) s2 && + (uintptr_t) s1 < s2e) || + ((uintptr_t) s2 >= + (uintptr_t) s1 && + (uintptr_t) s2 < s1e)) { + zero_fill = 1; + __throw_constraint_handler_s( + "strcat_s : memory overlaps", ret); + } else { + strncat(s1, s2, lim); + ret = 0; + } + } else { + /* trivial noop */ + ret = 0; + } + } + } + } + /* do not zero fill on overlapping starts */ + if (ret && zero_fill && s1 != s2) + s1[0] = 0; + return (ret); +} Index: lib/libc/string/strcpy_s.c =================================================================== --- /dev/null +++ lib/libc/string/strcpy_s.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include "libc_private.h" + +/* ISO/IEC 9899:2011 K.3.7.1.3 */ +errno_t strcpy_s(char * __restrict s1, rsize_t s1max, + const char * __restrict s2) +{ + rsize_t lim; + uintptr_t s1e, s2e; + errno_t ret; + int zero_fill; + size_t n; + + ret = EINVAL; + zero_fill = 0; + if (s1 == NULL) { + __throw_constraint_handler_s("strcpy_s : s1 is NULL", ret); + } else if (s1max > RSIZE_MAX) { + __throw_constraint_handler_s("strcpy_s : s1max > RSIZE_MAX", + ret); + } else if (s1max == 0) { + __throw_constraint_handler_s("strcpy_s : s1max == 0", ret); + } else if (s2 == NULL) { + zero_fill = 1; + __throw_constraint_handler_s("strcpy_s : s2 is NULL", ret); + } else { + lim = s1max; + /* + * number of char's + * slmax -1 to account for the +1 added to result for + * null terminator. If it turns out there isn't a null + * terminator then the truncation will take care of + * reporting the error. + */ + n = strnlen_s(s2, s1max - 1); + /* +1 to include null terminator */ + n++; + if (n < s1max) + lim = n; + if (lim > 0) { + s1e = (uintptr_t) s1 + lim; + s2e = (uintptr_t) s2 + lim; + if (((uintptr_t) s1 >= (uintptr_t) s2 && + (uintptr_t) s1 < s2e) || + ((uintptr_t) s2 >= (uintptr_t) s1 && + (uintptr_t) s2 < s1e)) { + /* do not zero fill on overlapping starts */ + if (s1 != s2) + zero_fill = 1; + __throw_constraint_handler_s( + "strcpy_s : memory overlaps", ret); + } else { + if (n == s1max && s2[s1max -1] != 0) { + zero_fill = 1; + __throw_constraint_handler_s( + "strcpy_s : s2 will be truncated", + ret); + } else { + strncpy(s1, s2, lim); + ret = 0; + } + } + } + } + if (ret && zero_fill) + s1[0] = 0; + return (ret); +} Index: lib/libc/string/strerror_s.c =================================================================== --- /dev/null +++ lib/libc/string/strerror_s.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include "libc_private.h" + +/* ISO/IEC 9899:2011 K.3.7.4.2 */ +errno_t strerror_s(char *s, rsize_t maxsize, errno_t errnum) +{ + errno_t ret; + size_t err_len; + char *err_str; + char *e = "..."; + + ret = EINVAL; + if (s == NULL) { + __throw_constraint_handler_s("strerror_s : s is NULL", ret); + } else if (maxsize > RSIZE_MAX) { + __throw_constraint_handler_s( + "strerror_s : maxsize > RSIZE_MAX", ret); + } else if (maxsize == 0) { + __throw_constraint_handler_s("strerror_s : maxsize == 0", ret); + } else { + err_len = strerrorlen_s(errnum)+1; + err_str = strerror(errnum); + if (err_len <= maxsize) { + strcpy_s(s, err_len, err_str); + ret = 0; + } else { + if (maxsize < 5) { + strcpy_s(s, maxsize, &e[4-maxsize]); + } else { + /* + * err_str is going to be truncated + * use normal call + */ + strncpy(s, err_str, maxsize - 4); + /* + * strncpy does not null terminate + * so advance to end + */ + strcpy_s(&s[maxsize - 4], 4, e); + } + } + } + return (ret); +} Index: lib/libc/string/strerrorlen_s.c =================================================================== --- /dev/null +++ lib/libc/string/strerrorlen_s.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include "libc_private.h" + +/* ISO/IEC 9899:2011 K.3.7.4.3 */ +size_t strerrorlen_s(errno_t errnum) +{ + size_t ret; + char *e; + + ret = 0; + e = strerror(errnum); + if (e != NULL) + ret = strlen(e); + return (ret); +} Index: lib/libc/string/strncat_s.c =================================================================== --- /dev/null +++ lib/libc/string/strncat_s.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include "libc_private.h" + +/* ISO/IEC 9899:2011 K.3.7.2.2 */ +errno_t strncat_s(char * __restrict s1, rsize_t s1max, + const char * __restrict s2, rsize_t n) +{ + rsize_t lim; + uintptr_t s1e, s2e; + errno_t ret; + size_t m, o; + int zero_fill; + + ret = EINVAL; + zero_fill = 0; + if (s1 == NULL) { + __throw_constraint_handler_s("strncat_s : s1 is NULL", ret); + } else if (s1max > RSIZE_MAX) { + __throw_constraint_handler_s("strncat_s : s1max > RSIZE_MAX", + ret); + } else if (s1max == 0) { + __throw_constraint_handler_s("strncat_s : s1max == 0", ret); + } else if (s2 == NULL) { + zero_fill = 1; + __throw_constraint_handler_s("strncat_s : s2 is NULL", ret); + } else if (n > RSIZE_MAX) { + zero_fill = 1; + __throw_constraint_handler_s("strncat_s : n > RSIZE_MAX", ret); + } else { + m = s1max - strnlen_s(s1, s1max); + if (m == 0) { + zero_fill = 1; + __throw_constraint_handler_s( + "strncat_s : s1 is full", ret); + } else { + o = strnlen_s(s2, n); + if (o >= m) { + zero_fill = 1; + __throw_constraint_handler_s( + "strncat_s : s1 will overflow", ret); + } else { + lim = o; + if (lim > 0) { + s1e = (uintptr_t) s1 + m; + s2e = (uintptr_t) s2 + o; + if (((uintptr_t) s1 >= + (uintptr_t) s2 && + (uintptr_t) s1 < s2e) || + ((uintptr_t) s2 >= + (uintptr_t) s1 && + (uintptr_t) s2 < s1e)) { + zero_fill = 1; + __throw_constraint_handler_s("strncat_s : memory overlaps", ret); + } else { + strncat(s1, s2, lim); + ret = 0; + } + } else { + /* trivial noop */ + ret = 0; + } + } + } + } + /* do not zero fill on overlapping starts */ + if (ret && zero_fill && s1 != s2) + s1[0] = 0; + return (ret); +} Index: lib/libc/string/strncpy_s.c =================================================================== --- /dev/null +++ lib/libc/string/strncpy_s.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include "libc_private.h" + +/* ISO/IEC 9899:2011 K.3.7.1.4 */ +errno_t strncpy_s(char * __restrict s1, rsize_t s1max, + const char * __restrict s2, rsize_t n) +{ + rsize_t lim; + uintptr_t s1e, s2e; + errno_t ret; + int zero_fill; + size_t s, t; + + ret = EINVAL; + zero_fill = 0; + if (s1 == NULL) { + __throw_constraint_handler_s("strncpy_s : s1 is NULL", ret); + } else if (s1max > RSIZE_MAX) { + __throw_constraint_handler_s("strncpy_s : s1max > RSIZE_MAX", + ret); + } else if (s1max == 0) { + __throw_constraint_handler_s("strncpy_s : s1max == 0", ret); + } else if (s2 == NULL) { + zero_fill = 1; + __throw_constraint_handler_s("strncpy_s : s2 is NULL", ret); + } else { + lim = s1max; + /* assume s2 size will be ok */ + s = n; + /* + * reset s2 size if n > s1max + * + * the '=' handles this corner case: + * n == s1max and s2[n-1] != 0 + * then s1 will not be null terminated + */ + if (n >= s1max) { + /* + * number of char's + * slmax -1 to account for the +1 added to result for + * null terminator. + */ + s = strnlen_s(s2, s1max - 1); + /* +1 to include null terminator */ + s++; + } + if (s < s1max) + lim = s; + if (lim > 0) { + s1e = (uintptr_t) s1 + lim; + s2e = (uintptr_t) s2 + lim; + if (((uintptr_t) s1 >= (uintptr_t) s2 && + (uintptr_t) s1 < s2e) || + ((uintptr_t) s2 >= (uintptr_t) s1 && + (uintptr_t) s2 < s1e)) { + /* do not zero fill on overlapping starts */ + if (s1 != s2) + zero_fill = 1; + __throw_constraint_handler_s( + "strncpy_s : memory overlaps", ret); + } else { + if (s == s1max && s2[s1max -1] != 0) { + zero_fill = 1; + /* + * Do not have a special throw string + * for n == s1max corner case + */ + __throw_constraint_handler_s( + "strncpy_s : s2 will be truncated", + ret); + } else { + /* strncpy does not null terminate. */ + for (t = 0; t < lim; t++) { + if (s2[t] == 0) + break; + s1[t] = s2[t]; + } + s1[t] = 0; + ret = 0; + } + } + } else { + /* trivial, still need to null terminate */ + s1[0] = 0; + ret = 0; + } + } + if (ret && zero_fill) + s1[0] = 0; + return (ret); +} Index: lib/libc/string/strnlen_s.c =================================================================== --- /dev/null +++ lib/libc/string/strnlen_s.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include "libc_private.h" + +/* ISO/IEC 9899:2011 K.3.7.4.4 */ +size_t strnlen_s(const char *s, size_t maxsize) +{ + size_t ret; + + ret = 0; + if (s != NULL) + ret = strnlen(s, maxsize); + return (ret); +} Index: lib/libc/string/strtok_s.c =================================================================== --- /dev/null +++ lib/libc/string/strtok_s.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include "libc_private.h" + +static int _check_first(char a, const char *b, size_t n) +{ + int ret; + size_t i; + + ret = 1; + for (i = 0; i < n; i++) { + if (a == b[i]) { + ret = 0; + break; + } + } + return (ret); +} + +static void _setptr_first(char *a, size_t i, size_t max __unused, char **b) +{ + *b = a + i; +} + +static void _setret_first(char *cur, size_t i, char **ret) +{ + *ret = &cur[i]; +} + +static void _setmax_first(rsize_t *max, size_t i, size_t lim) +{ + *max = lim - i; +} + +static int _check_next(char a, const char *b, size_t n) +{ + int ret; + size_t i; + + ret = 0; + for (i = 0; i < n; i++) { + if (a == b[i]) { + ret = 1; + break; + } + } + return (ret); +} + +static void _setptr_next(char *a, size_t i, size_t max, char **b) +{ + a[i] = 0; + if (i+1 < max) + *b = &a[i + 1]; +} + +static void _setret_next(char *cur, size_t i __unused, char **ret) +{ + *ret = cur; +} + +static void _setmax_next(rsize_t *max, size_t i, size_t lim) +{ + if (i < lim) + *max = lim - i - 1; + else + *max = 0; +} + +/* ISO/IEC 9899:2011 K.3.7.3.1 */ +char *strtok_s(char * __restrict s1, rsize_t * __restrict s1max, + const char * __restrict s2, char ** __restrict ptr) +{ + char *ret, *cur; + rsize_t i, lim, s2len; + int (*check)(char, const char *, size_t); + void (*setptr)(char *, size_t, size_t, char **); + void (*setret)(char *, size_t, char **); + void (*setmax)(rsize_t *, size_t, size_t); + + ret = NULL; + if (s1max == NULL) { + __throw_constraint_handler_s("strtok_s : s1max is NULL", + EINVAL); + } else if (s2 == NULL) { + __throw_constraint_handler_s("strtok_s : s2 is NULL", EINVAL); + } else if (ptr == NULL) { + __throw_constraint_handler_s("strtok_s : ptr is NULL", EINVAL); + } else if (s1 == NULL && *ptr == NULL) { + __throw_constraint_handler_s("strtok_s : *ptr is NULL", + EINVAL); + } else if (*s1max > RSIZE_MAX) { + __throw_constraint_handler_s("strtok_s : *s1max > RSIZE_MAX", + EINVAL); + } else { + s2len = strlen(s2); + if (s2len != 0) { + if (s1 != NULL) { + cur = s1; + check = _check_first; + setptr = _setptr_first; + setret = _setret_first; + setmax = _setmax_first; + } else { + cur = *ptr; + check = _check_next; + setptr = _setptr_next; + setret = _setret_next; + setmax = _setmax_next; + } + lim = *s1max; + *ptr = NULL; + for (i = 0; i < lim; i++) { + if (check(cur[i], s2, s2len)) { + setptr(cur, i, lim, ptr); + break; + } + } + if (i < lim) + setret(cur, i, &ret); + setmax(s1max, i, lim); + } + } + return (ret); +} Index: lib/libc/tests/string/Makefile =================================================================== --- lib/libc/tests/string/Makefile +++ lib/libc/tests/string/Makefile @@ -1,14 +1,24 @@ # $FreeBSD$ +ATF_TESTS_C+= memcpy_s_test ATF_TESTS_C+= memcmp_test +ATF_TESTS_C+= memmove_s_test ATF_TESTS_C+= memset_s_test ATF_TESTS_C+= stpncpy_test +ATF_TESTS_C+= strcat_s_test +ATF_TESTS_C+= strcpy_s_test ATF_TESTS_C+= strerror2_test +ATF_TESTS_C+= strerror_s_test +ATF_TESTS_C+= strncat_s_test +ATF_TESTS_C+= strncpy_s_test +ATF_TESTS_C+= strnlen_s_test +ATF_TESTS_C+= strtok_s_test ATF_TESTS_C+= wcscasecmp_test ATF_TESTS_C+= wcsnlen_test ATF_TESTS_C+= strxfrm_test ATF_TESTS_C+= wcscoll_test + # TODO: popcount, stresep NETBSD_ATF_TESTS_C+= memchr_test Index: lib/libc/tests/string/memcpy_s_test.c =================================================================== --- /dev/null +++ lib/libc/tests/string/memcpy_s_test.c @@ -0,0 +1,467 @@ +/*- + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +static errno_t e; +static const char * restrict m; + +void +h(const char * restrict msg, void * restrict ptr __unused, errno_t error) +{ + e = error; + m = msg; +} + +/* s1 null ptr */ +ATF_TC_WITHOUT_HEAD(s1_null_ptr); +ATF_TC_BODY(s1_null_ptr, tc) +{ + char b; + + b = 5; + assert(memcpy_s(0, 1, &b, 1) != 0); + assert(b == 5); +} + +/* s1max > rmax */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rmax); +ATF_TC_BODY(s1max_gt_rmax, tc) +{ + char a, b; + + a = 3; + b = 5; + assert(memcpy_s(&a, RSIZE_MAX + 1, &b, 1) != 0); + assert(a == 3); + assert(b == 5); +} + +/* s1max < 0 */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0); +ATF_TC_BODY(s1max_lt_0, tc) +{ + char a, b; + + a = 3; + b = 5; + assert(memcpy_s(&a, -1, &b, 1) != 0); + assert(a == 3); + assert(b == 5); +} + +/* normal */ +ATF_TC_WITHOUT_HEAD(normal); +ATF_TC_BODY(normal, tc) +{ + char a, b; + + a = 3; + b = 5; + assert(memcpy_s(&a, 1, &b, 1) == 0); + assert(a == 5); + assert(b == 5); +} + +/* s2 null ptr */ +ATF_TC_WITHOUT_HEAD(s2_null_ptr); +ATF_TC_BODY(s2_null_ptr, tc) +{ + char a; + + a = 5; + assert(memcpy_s(&a, 1, 0, 1) != 0); + assert(a == 0); +} + +/* n > rmax */ +ATF_TC_WITHOUT_HEAD(n_gt_rmax); +ATF_TC_BODY(n_gt_rmax, tc) +{ + char a, b; + + a = 3; + b = 5; + assert(memcpy_s(&a, 1, &b, RSIZE_MAX + 1) != 0); + assert(a == 0); + assert(b == 5); +} + +/* n < 0 */ +ATF_TC_WITHOUT_HEAD(n_lt_0); +ATF_TC_BODY(n_lt_0, tc) +{ + char a, b; + + a = 3; + b = 5; + assert(memcpy_s(&a, 1, &b, -1) != 0); + assert(a == 0); + assert(b == 5); +} + +/* n < s1max */ +ATF_TC_WITHOUT_HEAD(n_lt_s1max); +ATF_TC_BODY(n_lt_s1max, tc) +{ + char a[3] = { 1, 2, 3 }; + char b[3] = { 5, 6, 7 }; + + assert(memcpy_s(&a[0], 3, &b[0], 2) == 0); + assert(a[0] == 5); + assert(a[1] == 6); + assert(a[2] == 3); +} + +/* n > s1max */ +ATF_TC_WITHOUT_HEAD(n_gt_s1max); +ATF_TC_BODY(n_gt_s1max, tc) +{ + char a[3] = { 1, 2, 3 }; + char b[3] = { 5, 6, 7 }; + + assert(memcpy_s(&a[0], 2, &b[0], 3) == 0); + assert(a[0] == 5); + assert(a[1] == 6); + assert(a[2] == 3); +} + +/* null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s1_null_ptr_handler); +ATF_TC_BODY(s1_null_ptr_handler, tc) +{ + char b; + + b = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memcpy_s(0, 1, &b, 1) != 0); + assert(e != 0); + assert(0 == strcmp(m, "memcpy_s : s1 is NULL")); +} + +/* s1max > rmax, handler */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rmax_handler); +ATF_TC_BODY(s1max_gt_rmax_handler, tc) +{ + char a, b; + + a = 3; + b = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memcpy_s(&b, RSIZE_MAX + 1, &b, 1) != 0); + assert(a == 3); + assert(b == 5); + assert(e != 0); + assert(0 == strcmp(m, "memcpy_s : s1max > RSIZE_MAX")); +} + +/* s1max < 0, handler */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0_handler); +ATF_TC_BODY(s1max_lt_0_handler, tc) +{ + char a, b; + + a = 3; + b = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memcpy_s(&b, -1, &b, 1) != 0); + assert(a == 3); + assert(b == 5); + assert(e != 0); + assert(0 == strcmp(m, "memcpy_s : s1max > RSIZE_MAX")); +} + +/* normal, handler */ +ATF_TC_WITHOUT_HEAD(normal_handler); +ATF_TC_BODY(normal_handler, tc) +{ + char a, b; + + a = 3; + b = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memcpy_s(&a, 1, &b, 1) == 0); + assert(a == 5); + assert(b == 5); + assert(e == 0); + assert(m == NULL); +} + +/* s2 null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s2_null_ptr_handler); +ATF_TC_BODY(s2_null_ptr_handler, tc) +{ + char a; + + a = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memcpy_s(&a, 1, 0, 1) != 0); + assert(a == 0); + assert(e != 0); + assert(0 == strcmp(m, "memcpy_s : s2 is NULL")); +} + +/* n > rmax, handler */ +ATF_TC_WITHOUT_HEAD(n_gt_rmax_handler); +ATF_TC_BODY(n_gt_rmax_handler, tc) +{ + char a, b; + + a = 3; + b = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memcpy_s(&a, 1, &b, RSIZE_MAX + 1) != 0); + assert(a == 0); + assert(b == 5); + assert(e != 0); + assert(0 == strcmp(m, "memcpy_s : n > RSIZE_MAX")); +} + +/* n < 0, handler */ +ATF_TC_WITHOUT_HEAD(n_lt_0_handler); +ATF_TC_BODY(n_lt_0_handler, tc) +{ + char a, b; + + a = 3; + b = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memcpy_s(&a, 1, &b, -1) != 0); + assert(a == 0); + assert(b == 5); + assert(e != 0); + assert(0 == strcmp(m, "memcpy_s : n > RSIZE_MAX")); +} + +/* overlap, beginning */ +ATF_TC_WITHOUT_HEAD(overlap_beginning); +ATF_TC_BODY(overlap_beginning, tc) +{ + char a[6] = { 1, 2, 3, 4, 5, 6 }; + + assert(memcpy_s(&a[0], 1, &a[0], 1) != 0); + assert(a[0] == 1); +} + +/* overlap, ending 1 */ +ATF_TC_WITHOUT_HEAD(overlap_ending_1); +ATF_TC_BODY(overlap_ending_1, tc) +{ + char a[6] = { 1, 2, 3, 4, 5, 6 }; + + assert(memcpy_s(&a[0], 3, &a[2], 3) != 0); + assert(a[0] == 1); + assert(a[1] == 2); + assert(a[2] == 3); +} + +/* overlap, ending 2 */ +ATF_TC_WITHOUT_HEAD(overlap_ending_2); +ATF_TC_BODY(overlap_ending_2, tc) +{ + char a[6] = { 1, 2, 3, 4, 5, 6 }; + + assert(memcpy_s(&a[2], 3, &a[0], 3) != 0); + assert(a[0] == 1); + assert(a[1] == 2); + assert(a[2] == 3); +} + +/* overlap, beginning, handler */ +ATF_TC_WITHOUT_HEAD(overlap_beginning_handler); +ATF_TC_BODY(overlap_beginning_handler, tc) +{ + char a[6] = { 1, 2, 3, 4, 5, 6 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memcpy_s(&a[0], 1, &a[0], 1) != 0); + assert(a[0] == 1); + assert(e != 0); + assert(0 == strcmp(m, "memcpy_s : memory overlaps")); +} + +/* overlap, ending 1, handler */ +ATF_TC_WITHOUT_HEAD(overlap_ending_1_handler); +ATF_TC_BODY(overlap_ending_1_handler, tc) +{ + char a[6] = { 1, 2, 3, 4, 5, 6 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memcpy_s(&a[0], 3, &a[2], 3) != 0); + assert(a[0] == 1); + assert(a[1] == 2); + assert(a[2] == 3); + assert(e != 0); + assert(0 == strcmp(m, "memcpy_s : memory overlaps")); +} + +/* overlap, ending 2, handler */ +ATF_TC_WITHOUT_HEAD(overlap_ending_2_handler); +ATF_TC_BODY(overlap_ending_2_handler, tc) +{ + char a[6] = { 1, 2, 3, 4, 5, 6 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memcpy_s(&a[2], 3, &a[0], 3) != 0); + assert(a[0] == 1); + assert(a[1] == 2); + assert(a[2] == 3); + assert(e != 0); + assert(0 == strcmp(m, "memcpy_s : memory overlaps")); +} + +/* no overlap 1 */ +ATF_TC_WITHOUT_HEAD(no_overlap_1); +ATF_TC_BODY(no_overlap_1, tc) +{ + char a[6] = { 1, 2, 3, 4, 5, 6 }; + + assert(memcpy_s(&a[0], 1, &a[1], 1) == 0); + assert(a[0] == 2); +} + +/* no overlap 2 */ +ATF_TC_WITHOUT_HEAD(no_overlap_2); +ATF_TC_BODY(no_overlap_2, tc) +{ + char a[6] = { 1, 2, 3, 4, 5, 6 }; + + assert(memcpy_s(&a[1], 1, &a[0], 1) == 0); + assert(a[1] == 1); +} + +/* no overlap 3 */ +ATF_TC_WITHOUT_HEAD(no_overlap_3); +ATF_TC_BODY(no_overlap_3, tc) +{ + char a[6] = { 1, 2, 3, 4, 5, 6 }; + + assert(memcpy_s(&a[0], 2, &a[2], 2) == 0); + assert(a[0] == 3); + assert(a[1] == 4); +} + +/* no overlap 4 */ +ATF_TC_WITHOUT_HEAD(no_overlap_4); +ATF_TC_BODY(no_overlap_4, tc) +{ + char a[6] = { 1, 2, 3, 4, 5, 6 }; + + assert(memcpy_s(&a[2], 2, &a[0], 2) == 0); + assert(a[2] == 1); + assert(a[3] == 2); +} + +/* overlap, middle 1, handler */ +ATF_TC_WITHOUT_HEAD(overlap_middle_1_handler); +ATF_TC_BODY(overlap_middle_1_handler, tc) +{ + char a[6] = { 1, 2, 3, 4, 5, 6 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memcpy_s(&a[0], 4, &a[1], 2) != 0); + assert(a[0] == 1); + assert(a[1] == 2); + assert(a[2] == 3); + assert(e != 0); + assert(0 == strcmp(m, "memcpy_s : memory overlaps")); +} + +/* noop */ +ATF_TC_WITHOUT_HEAD(noop); +ATF_TC_BODY(noop, tc) +{ + char a, b; + + a = 3; + b = 5; + assert(memcpy_s(&a, 1, &b, 0) == 0); + assert(a == 3); + assert(b == 5); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, s1_null_ptr); + ATF_TP_ADD_TC(tp, s1max_gt_rmax); + ATF_TP_ADD_TC(tp, s1max_lt_0); + ATF_TP_ADD_TC(tp, normal); + ATF_TP_ADD_TC(tp, s2_null_ptr); + ATF_TP_ADD_TC(tp, n_gt_rmax); + ATF_TP_ADD_TC(tp, n_lt_0); + ATF_TP_ADD_TC(tp, n_lt_s1max); + ATF_TP_ADD_TC(tp, n_gt_s1max); + ATF_TP_ADD_TC(tp, s1_null_ptr_handler); + ATF_TP_ADD_TC(tp, s1max_gt_rmax_handler); + ATF_TP_ADD_TC(tp, s1max_lt_0_handler); + ATF_TP_ADD_TC(tp, normal_handler); + ATF_TP_ADD_TC(tp, s2_null_ptr_handler); + ATF_TP_ADD_TC(tp, n_gt_rmax_handler); + ATF_TP_ADD_TC(tp, n_lt_0_handler); + ATF_TP_ADD_TC(tp, overlap_beginning); + ATF_TP_ADD_TC(tp, overlap_ending_1); + ATF_TP_ADD_TC(tp, overlap_ending_2); + ATF_TP_ADD_TC(tp, overlap_beginning_handler); + ATF_TP_ADD_TC(tp, overlap_ending_1_handler); + ATF_TP_ADD_TC(tp, overlap_ending_2_handler); + ATF_TP_ADD_TC(tp, no_overlap_1); + ATF_TP_ADD_TC(tp, no_overlap_2); + ATF_TP_ADD_TC(tp, no_overlap_3); + ATF_TP_ADD_TC(tp, no_overlap_4); + ATF_TP_ADD_TC(tp, overlap_middle_1_handler); + ATF_TP_ADD_TC(tp, noop); + return (atf_no_error()); +} + Index: lib/libc/tests/string/memmove_s_test.c =================================================================== --- /dev/null +++ lib/libc/tests/string/memmove_s_test.c @@ -0,0 +1,298 @@ +/*- + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +static errno_t e; +static const char * restrict m; + +void +h(const char * restrict msg, void * restrict ptr __unused, errno_t error) +{ + e = error; + m = msg; +} + +/* s1 null ptr */ +ATF_TC_WITHOUT_HEAD(s1_null_ptr); +ATF_TC_BODY(s1_null_ptr, tc) +{ + char b; + + b = 5; + assert(memmove_s(0, 1, &b, 1) != 0); + assert(b == 5); +} + +/* s1max > rmax */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rmax); +ATF_TC_BODY(s1max_gt_rmax, tc) +{ + char a, b; + + a = 3; + b = 5; + assert(memmove_s(&b, RSIZE_MAX + 1, &b, 1) != 0); + assert(a == 3); + assert(b == 5); +} + +/* s1max < 0 */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0); +ATF_TC_BODY(s1max_lt_0, tc) +{ + char a, b; + + a = 3; + b = 5; + assert(memmove_s(&b, -1, &b, 1) != 0); + assert(a == 3); + assert(b == 5); +} + +/* normal */ +ATF_TC_WITHOUT_HEAD(normal); +ATF_TC_BODY(normal, tc) +{ + char a, b; + + a = 3; + b = 5; + assert(memmove_s(&a, 1, &b, 1) == 0); + assert(a == 5); + assert(b == 5); +} + +/* s2 null ptr */ +ATF_TC_WITHOUT_HEAD(s2_null_ptr); +ATF_TC_BODY(s2_null_ptr, tc) +{ + char a; + + a = 5; + assert(memmove_s(&a, 1, 0, 1) != 0); + assert(a == 0); +} + +/* n > rmax */ +ATF_TC_WITHOUT_HEAD(n_gt_rmax); +ATF_TC_BODY(n_gt_rmax, tc) +{ + char a, b; + + a = 3; + b = 5; + assert(memmove_s(&a, 1, &b, RSIZE_MAX + 1) != 0); + assert(a == 0); + assert(b == 5); +} + +/* n < 0 */ +ATF_TC_WITHOUT_HEAD(n_lt_0); +ATF_TC_BODY(n_lt_0, tc) +{ + char a, b; + + a = 3; + b = 5; + assert(memmove_s(&a, 1, &b, -1) != 0); + assert(a == 0); + assert(b == 5); +} + +/* n < s1max */ +ATF_TC_WITHOUT_HEAD(n_lt_s1max); +ATF_TC_BODY(n_lt_s1max, tc) +{ + char a[3] = { 1, 2, 3 }; + char b[3] = { 5, 6, 7 }; + assert(memmove_s(&a[0], 3, &b[0], 2) == 0); + assert(a[0] == 5); + assert(a[1] == 6); + assert(a[2] == 3); +} + +/* n > s1max */ +ATF_TC_WITHOUT_HEAD(n_gt_s1max); +ATF_TC_BODY(n_gt_s1max, tc) +{ + char a[3] = { 1, 2, 3 }; + char b[3] = { 5, 6, 7 }; + + assert(memmove_s(&a[0], 2, &b[0], 3) == 0); + assert(a[0] == 5); + assert(a[1] == 6); + assert(a[2] == 3); +} + +/* null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s1_null_ptr_handler); +ATF_TC_BODY(s1_null_ptr_handler, tc) +{ + char b; + + b = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memmove_s(0, 1, &b, 1) != 0); + assert(e != 0); + assert(0 == strcmp(m, "memmove_s : s1 is NULL")); +} + +/* s1max > rmax, handler */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rmax_handler); +ATF_TC_BODY(s1max_gt_rmax_handler, tc) +{ + char a, b; + + a = 3; + b = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memmove_s(&b, RSIZE_MAX + 1, &b, 1) != 0); + assert(a == 3); + assert(b == 5); + assert(e != 0); + assert(0 == strcmp(m, "memmove_s : s1max > RSIZE_MAX")); +} + +/* s1max < 0, handler */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0_handler); +ATF_TC_BODY(s1max_lt_0_handler, tc) +{ + char a, b; + + a = 3; + b = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memmove_s(&b, -1, &b, 1) != 0); + assert(a == 3); + assert(b == 5); + assert(e != 0); + assert(0 == strcmp(m, "memmove_s : s1max > RSIZE_MAX")); +} + +/* normal, handler */ +ATF_TC_WITHOUT_HEAD(normal_handler); +ATF_TC_BODY(normal_handler, tc) +{ + char a, b; + + a = 3; + b = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memmove_s(&a, 1, &b, 1) == 0); + assert(a == 5); + assert(b == 5); + assert(e == 0); + assert(m == NULL); +} + +/* s2 null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s2_null_ptr_handler); +ATF_TC_BODY(s2_null_ptr_handler, tc) +{ + char a; + + a = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memmove_s(&a, 1, 0, 1) != 0); + assert(a == 0); + assert(e != 0); + assert(0 == strcmp(m, "memmove_s : s2 is NULL")); +} + +/* n > rmax, handler */ +ATF_TC_WITHOUT_HEAD(n_gt_rmax_handler); +ATF_TC_BODY(n_gt_rmax_handler, tc) +{ + char a, b; + + a = 3; + b = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memmove_s(&a, 1, &b, RSIZE_MAX + 1) != 0); + assert(a == 0); + assert(b == 5); + assert(e != 0); + assert(0 == strcmp(m, "memmove_s : n > RSIZE_MAX")); +} + +/* n < 0, handler */ +ATF_TC_WITHOUT_HEAD(n_lt_0_handler); +ATF_TC_BODY(n_lt_0_handler, tc) +{ + char a, b; + + a = 3; + b = 5; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(memmove_s(&a, 1, &b, -1) != 0); + assert(a == 0); + assert(b == 5); + assert(e != 0); + assert(0 == strcmp(m, "memmove_s : n > RSIZE_MAX")); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, s1_null_ptr); + ATF_TP_ADD_TC(tp, s1max_gt_rmax); + ATF_TP_ADD_TC(tp, s1max_lt_0); + ATF_TP_ADD_TC(tp, normal); + ATF_TP_ADD_TC(tp, s2_null_ptr); + ATF_TP_ADD_TC(tp, n_gt_rmax); + ATF_TP_ADD_TC(tp, n_lt_0); + ATF_TP_ADD_TC(tp, n_lt_s1max); + ATF_TP_ADD_TC(tp, n_gt_s1max); + ATF_TP_ADD_TC(tp, s1_null_ptr_handler); + ATF_TP_ADD_TC(tp, s1max_gt_rmax_handler); + ATF_TP_ADD_TC(tp, s1max_lt_0_handler); + ATF_TP_ADD_TC(tp, normal_handler); + ATF_TP_ADD_TC(tp, s2_null_ptr_handler); + ATF_TP_ADD_TC(tp, n_gt_rmax_handler); + ATF_TP_ADD_TC(tp, n_lt_0_handler); + return (atf_no_error()); +} Index: lib/libc/tests/string/strcat_s_test.c =================================================================== --- /dev/null +++ lib/libc/tests/string/strcat_s_test.c @@ -0,0 +1,529 @@ +/*- + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +static errno_t e; +static const char * restrict m; + +void +h(const char * restrict msg, void * restrict ptr __unused, errno_t error) +{ + e = error; + m = msg; +} + +/* s1 null ptr */ +ATF_TC_WITHOUT_HEAD(s1_null_ptr); +ATF_TC_BODY(s1_null_ptr, tc) +{ + char b[2] = { 5, 0 }; + + assert(strcat_s(0, 1, &b[0]) != 0); + assert(b[0] == 5); +} + +/* s1max > rmax */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rmax); +ATF_TC_BODY(s1max_gt_rmax, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + assert(strcat_s(&a[0], RSIZE_MAX + 1, &b[0]) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* s1max < 0 */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0); +ATF_TC_BODY(s1max_lt_0, tc) +{ + char a[2] = { 3, 0 }; + const char b[2] = { 5, 0 }; + + assert(strcat_s(&a[0], -1, &b[0]) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* normal */ +ATF_TC_WITHOUT_HEAD(normal); +ATF_TC_BODY(normal, tc) +{ + char a[4] = { 4, 0, 2, 1 }; + char b[2] = { 5, 0 }; + + assert(strcat_s(&a[0], 4, &b[0]) == 0); + assert(a[0] == 4); + assert(a[1] == 5); + assert(a[2] == 0); + assert(b[0] == 5); +} + +/* s2 null ptr */ +ATF_TC_WITHOUT_HEAD(s2_null_ptr); +ATF_TC_BODY(s2_null_ptr, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + + assert(strcat_s(&a[0], 4, 0) != 0); + assert(a[0] == 0); + assert(a[1] == 3); +} + +/* s1 full already, poor s1 */ +ATF_TC_WITHOUT_HEAD(s1_full_already_poor_s1); +ATF_TC_BODY(s1_full_already_poor_s1, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[2] = { 5, 0 }; + + assert(strcat_s(&a[0], 4, &b[0]) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); +} + +/* s1 full already, normal case */ +ATF_TC_WITHOUT_HEAD(s1_full_already_normal_case); +ATF_TC_BODY(s1_full_already_normal_case, tc) +{ + char a[4] = { 4, 3, 2, 0 }; + char b[2] = { 5, 0 }; + + assert(strcat_s(&a[0], 4, &b[0]) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); +} + +/* s1 full already, but nothing to cat */ +ATF_TC_WITHOUT_HEAD(s1_full_already_but_nothing_to_cat); +ATF_TC_BODY(s1_full_already_but_nothing_to_cat, tc) +{ + char a[4] = { 4, 3, 2, 0 }; + char b[2] = { 0, 1 }; + + assert(strcat_s(&a[0], 4, &b[0]) == 0); + assert(a[0] == 4); + assert(a[3] == 0); + assert(b[0] == 0); +} + +/* s1 will become full, not enough space for null terminator */ +ATF_TC_WITHOUT_HEAD(trunc_1); +ATF_TC_BODY(trunc_1, tc) +{ + char a[4] = { 4, 3, 0, 1 }; + char b[3] = { 5, 6, 0 }; + + assert(strcat_s(&a[0], 4, &b[0]) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); +} + +/* s1 will become full, simple case */ +ATF_TC_WITHOUT_HEAD(trunc_2); +ATF_TC_BODY(trunc_2, tc) +{ + char a[6] = { 4, 3, 0, 1, 2, 3 }; + char b[5] = { 5, 6, 7, 8, 0 }; + + assert(strcat_s(&a[0], 6, &b[0]) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); +} + +/* s1max == 0 */ +ATF_TC_WITHOUT_HEAD(s1max_eq_0); +ATF_TC_BODY(s1max_eq_0, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + assert(strcat_s(&a[0], 0, &b[0]) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* + * s1 will become full, + * not enough space for null terminator, + * overlapping s1 and s2 + */ +ATF_TC_WITHOUT_HEAD(complex_1); +ATF_TC_BODY(complex_1, tc) +{ + char a[4] = { 4, 3, 0, 1 }; + + assert(strcat_s(&a[0], 4, &a[0]) != 0); + assert(a[0] == 4); + assert(a[1] == 3); +} + +/* overlapping no zero fill */ +ATF_TC_WITHOUT_HEAD(overlapping_no_zero_fill); +ATF_TC_BODY(overlapping_no_zero_fill, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + assert(strcat_s(&a[0], 5, &a[0]) != 0); + assert(a[0] == 4); + assert(a[1] == 3); +} + +/* overlapping zero fill */ +ATF_TC_WITHOUT_HEAD(overlapping_zero_fill); +ATF_TC_BODY(overlapping_zero_fill, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + assert(strcat_s(&a[0], 5, &a[1]) != 0); + assert(a[0] == 0); + assert(a[1] == 3); +} + +/* overlapping, nothing to cat */ +ATF_TC_WITHOUT_HEAD(overlapping_nothing_to_cat); +ATF_TC_BODY(overlapping_nothing_to_cat, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + assert(strcat_s(&a[0], 5, &a[2]) == 0); + assert(a[0] == 4); + assert(a[2] == 0); +} + +/* s1 null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s1_null_ptr_handler); +ATF_TC_BODY(s1_null_ptr_handler, tc) +{ + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(0, 1, &b[0]) != 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcat_s : s1 is NULL")); +} + +/* s1max > rmax, handler */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rmax_handler); +ATF_TC_BODY(s1max_gt_rmax_handler, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], RSIZE_MAX + 1, &b[0]) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcat_s : s1max > RSIZE_MAX")); +} + +/* s1max < 0, handler */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0_handler); +ATF_TC_BODY(s1max_lt_0_handler, tc) +{ + char a[2] = { 3, 0 }; + const char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], -1, &b[0]) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcat_s : s1max > RSIZE_MAX")); +} + +/* normal, handler */ +ATF_TC_WITHOUT_HEAD(normal_handler); +ATF_TC_BODY(normal_handler, tc) +{ + char a[4] = { 4, 0, 2, 1 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], 4, &b[0]) == 0); + assert(a[0] == 4); + assert(a[1] == 5); + assert(a[2] == 0); + assert(b[0] == 5); + assert(e == 0); + assert(m == NULL); +} + +/* s2 null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s2_null_ptr_handler); +ATF_TC_BODY(s2_null_ptr_handler, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], 4, 0) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(e != 0); + assert(0 == strcmp(m, "strcat_s : s2 is NULL")); +} + +/* s1 full already, poor s1, handler */ +ATF_TC_WITHOUT_HEAD(s1_full_already_poor_s1_handler); +ATF_TC_BODY(s1_full_already_poor_s1_handler, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], 4, &b[0]) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcat_s : s1 is full")); +} + +/* s1 full already, normal case, handler */ +ATF_TC_WITHOUT_HEAD(s1_full_already_normal_case_handler); +ATF_TC_BODY(s1_full_already_normal_case_handler, tc) +{ + char a[4] = { 4, 3, 2, 0 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], 4, &b[0]) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcat_s : s1 will overflow")); +} + +/* s1 full already, but nothing to cat, handler */ +ATF_TC_WITHOUT_HEAD(s1_full_already_nothing_to_cat_handler); +ATF_TC_BODY(s1_full_already_nothing_to_cat_handler, tc) +{ + char a[4] = { 4, 3, 2, 0 }; + char b[2] = { 0, 1 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], 4, &b[0]) == 0); + assert(a[0] == 4); + assert(a[3] == 0); + assert(b[0] == 0); + assert(e == 0); + assert(m == NULL); +} + +/* s1 will become full, not enough space for null terminator, handler */ +ATF_TC_WITHOUT_HEAD(complex_2); +ATF_TC_BODY(complex_2, tc) +{ + char a[4] = { 4, 3, 0, 1 }; + char b[3] = { 5, 6, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], 4, &b[0]) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcat_s : s1 will overflow")); +} + +/* s1 will become full, simple case, handler */ +ATF_TC_WITHOUT_HEAD(s1_will_become_full_simple_handler); +ATF_TC_BODY(s1_will_become_full_simple_handler, tc) +{ + char a[6] = { 4, 3, 0, 1, 2, 3 }; + char b[5] = { 5, 6, 7, 8, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], 6, &b[0]) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcat_s : s1 will overflow")); +} + +/* s1max == 0, handler */ +ATF_TC_WITHOUT_HEAD(s1max_eq_0_handler); +ATF_TC_BODY(s1max_eq_0_handler, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], 0, &b[0]) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcat_s : s1max == 0")); +} + +/* + * s1 will become full, + * not enough space for null terminator, + * overlapping s1 and s2, + * handler + */ +ATF_TC_WITHOUT_HEAD(complex_3); +ATF_TC_BODY(complex_3, tc) +{ + char a[4] = { 4, 3, 0, 1 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], 4, &a[0]) != 0); + assert(a[0] == 4); + assert(a[1] == 3); + assert(e != 0); + assert(0 == strcmp(m, "strcat_s : s1 will overflow")); +} + +/* overlapping no zero fill, handler */ +ATF_TC_WITHOUT_HEAD(overlapping_no_zero_fill_handler); +ATF_TC_BODY(overlapping_no_zero_fill_handler, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], 5, &a[0]) != 0); + assert(a[0] == 4); + assert(a[1] == 3); + assert(e != 0); + assert(0 == strcmp(m, "strcat_s : memory overlaps")); +} + +/* overlapping zero fill, handler */ +ATF_TC_WITHOUT_HEAD(overlapping_zero_fill_handler); +ATF_TC_BODY(overlapping_zero_fill_handler, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], 5, &a[1]) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(e != 0); + assert(0 == strcmp(m, "strcat_s : memory overlaps")); +} + +/* overlapping, nothing to cat, handler */ +ATF_TC_WITHOUT_HEAD(overlapping_nothing_to_cat_handler); +ATF_TC_BODY(overlapping_nothing_to_cat_handler, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcat_s(&a[0], 5, &a[2]) == 0); + assert(a[0] == 4); + assert(a[2] == 0); + assert(e == 0); + assert(m == NULL); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, s1_null_ptr); + ATF_TP_ADD_TC(tp, s1max_gt_rmax); + ATF_TP_ADD_TC(tp, s1max_lt_0); + ATF_TP_ADD_TC(tp, normal); + ATF_TP_ADD_TC(tp, s2_null_ptr); + ATF_TP_ADD_TC(tp, s1_full_already_poor_s1); + ATF_TP_ADD_TC(tp, s1_full_already_normal_case); + ATF_TP_ADD_TC(tp, s1_full_already_but_nothing_to_cat); + ATF_TP_ADD_TC(tp, trunc_1); + ATF_TP_ADD_TC(tp, trunc_2); + ATF_TP_ADD_TC(tp, s1max_eq_0); + ATF_TP_ADD_TC(tp, complex_1); + ATF_TP_ADD_TC(tp, overlapping_no_zero_fill); + ATF_TP_ADD_TC(tp, overlapping_zero_fill); + ATF_TP_ADD_TC(tp, overlapping_nothing_to_cat); + ATF_TP_ADD_TC(tp, s1_null_ptr_handler); + ATF_TP_ADD_TC(tp, s1max_gt_rmax_handler); + ATF_TP_ADD_TC(tp, s1max_lt_0_handler); + ATF_TP_ADD_TC(tp, normal_handler); + ATF_TP_ADD_TC(tp, s2_null_ptr_handler); + ATF_TP_ADD_TC(tp, s1_full_already_poor_s1_handler); + ATF_TP_ADD_TC(tp, s1_full_already_normal_case_handler); + ATF_TP_ADD_TC(tp, s1_full_already_nothing_to_cat_handler); + ATF_TP_ADD_TC(tp, complex_2); + ATF_TP_ADD_TC(tp, s1_will_become_full_simple_handler); + ATF_TP_ADD_TC(tp, s1max_eq_0_handler); + ATF_TP_ADD_TC(tp, complex_3); + ATF_TP_ADD_TC(tp, overlapping_no_zero_fill_handler); + ATF_TP_ADD_TC(tp, overlapping_zero_fill_handler); + ATF_TP_ADD_TC(tp, overlapping_nothing_to_cat_handler); + return (atf_no_error()); +} Index: lib/libc/tests/string/strcpy_s_test.c =================================================================== --- /dev/null +++ lib/libc/tests/string/strcpy_s_test.c @@ -0,0 +1,382 @@ +/*- + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +static errno_t e; +static const char * restrict m; + +void +h(const char * restrict msg, void * restrict ptr __unused, errno_t error) +{ + e = error; + m = msg; +} + +/* s1 null ptr */ +ATF_TC_WITHOUT_HEAD(s1_null_ptr); +ATF_TC_BODY(s1_null_ptr, tc) +{ + char b[2] = { 5, 0 }; + + assert(strcpy_s(0, 1, &b[0]) != 0); + assert(b[0] = 5); +} + +/* s1max > rmax */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rmax); +ATF_TC_BODY(s1max_gt_rmax, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + assert(strcpy_s(&a[0], RSIZE_MAX + 1, &b[0]) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* s1max < 0 */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0); +ATF_TC_BODY(s1max_lt_0, tc) +{ + char a[2] = { 3, 0 }; + const char b[2] = { 5, 0 }; + + assert(strcpy_s(&a[0], -1, &b[0]) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* normal */ +ATF_TC_WITHOUT_HEAD(normal); +ATF_TC_BODY(normal, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[2] = { 5, 0 }; + + assert(strcpy_s(&a[0], 4, &b[0]) == 0); + assert(a[0] == 5); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* s2 null ptr */ +ATF_TC_WITHOUT_HEAD(s2_null_ptr); +ATF_TC_BODY(s2_null_ptr, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + + assert(strcpy_s(&a[0], 4, 0) != 0); + assert(a[0] == 0); + assert(a[1] == 3); +} + +/* n > s1max */ +ATF_TC_WITHOUT_HEAD(n_gt_s1max); +ATF_TC_BODY(n_gt_s1max, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[6] = { 5, 4, 3, 2, 1, 0 }; + + assert(strcpy_s(&a[0], 4, &b[0]) != 0); + assert(a[0] == 0); + assert(b[0] == 5); +} + +/* n == s1max */ +ATF_TC_WITHOUT_HEAD(n_eq_s1max); +ATF_TC_BODY(n_eq_s1max, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[4] = { 5, 4, 3, 0 }; + + assert(strcpy_s(&a[0], 4, &b[0]) == 0); + assert(a[0] == 5); + assert(a[1] == 4); + assert(a[2] == 3); + assert(a[3] == 0); + assert(b[0] == 5); +} + +/* overlap end */ +ATF_TC_WITHOUT_HEAD(overlap_end); +ATF_TC_BODY(overlap_end, tc) +{ + char a[10] = { 4, 3, 2, 1, 1, 2, 3, 4, 0 }; + + assert(strcpy_s(&a[0], 5, &a[4]) != 0); + assert(a[0] == 0); +} + +/* overlap middle */ +ATF_TC_WITHOUT_HEAD(overlap_middle); +ATF_TC_BODY(overlap_middle, tc) +{ + char a[8] = { 4, 3, 2, 1, 1, 2, 3, 0 }; + + assert(strcpy_s(&a[0], 8, &a[2]) != 0); + assert(a[0] == 0); +} + +/* overlap beginning */ +ATF_TC_WITHOUT_HEAD(overlap_beginning); +ATF_TC_BODY(overlap_beginning, tc) +{ + char a[7] = { 4, 0, 2, 1, 3, 1, 2 }; + + assert(strcpy_s(&a[0], 7, &a[0]) != 0); + assert(a[0] == 4); +} + +/* s1 null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s1_null_ptr_handler); +ATF_TC_BODY(s1_null_ptr_handler, tc) +{ + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcpy_s(0, 1, &b[0]) != 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcpy_s : s1 is NULL")); +} + +/* s1max > rmax, handler */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rmax_handler); +ATF_TC_BODY(s1max_gt_rmax_handler, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcpy_s(&a[0], RSIZE_MAX + 1, &b[0]) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcpy_s : s1max > RSIZE_MAX")); +} + +/* s1max < 0, handler */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0_handler); +ATF_TC_BODY(s1max_lt_0_handler, tc) +{ + char a[2] = { 3, 0 }; + const char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcpy_s(&a[0], -1, &b[0]) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcpy_s : s1max > RSIZE_MAX")); +} + +/* normal, handler */ +ATF_TC_WITHOUT_HEAD(normal_handler); +ATF_TC_BODY(normal_handler, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + const char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcpy_s(&a[0], 4, &b[0]) == 0); + assert(a[0] == 5); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e == 0); + assert(m == NULL); +} + +/* s2 null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s2_null_ptr_handler); +ATF_TC_BODY(s2_null_ptr_handler, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcpy_s(&a[0], 4, 0) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(e != 0); + assert(0 == strcmp(m, "strcpy_s : s2 is NULL")); +} + +/* n > s1max, handler */ +ATF_TC_WITHOUT_HEAD(n_gt_s1max_handler); +ATF_TC_BODY(n_gt_s1max_handler, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[6] = { 5, 4, 3, 2, 1, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcpy_s(&a[0], 4, &b[0]) != 0); + assert(a[0] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcpy_s : s2 will be truncated")); +} + +/* n == s1max, handler */ +ATF_TC_WITHOUT_HEAD(n_eq_s1max_handler); +ATF_TC_BODY(n_eq_s1max_handler, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + const char b[5] = { 5, 4, 3, 2, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcpy_s(&a[0], 4, &b[0]) != 0); + assert(a[0] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcpy_s : s2 will be truncated")); +} + +/* overlap end, handler */ +ATF_TC_WITHOUT_HEAD(overlap_end_handler); +ATF_TC_BODY(overlap_end_handler, tc) +{ + char a[10] = { 4, 3, 2, 1, 1, 2, 3, 4, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcpy_s(&a[0], 5, &a[4]) != 0); + assert(a[0] == 0); + assert(e != 0); + assert(0 == strcmp(m, "strcpy_s : memory overlaps")); +} + +/* overlap middle, handler */ +ATF_TC_WITHOUT_HEAD(overlap_middle_handler); +ATF_TC_BODY(overlap_middle_handler, tc) +{ + char a[8] = { 4, 3, 2, 1, 1, 2, 3, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcpy_s(&a[0], 8, &a[2]) != 0); + assert(a[0] == 0); + assert(e != 0); + assert(0 == strcmp(m, "strcpy_s : memory overlaps")); +} + +/* overlap beginning, handler */ +ATF_TC_WITHOUT_HEAD(overlap_beginning_handler); +ATF_TC_BODY(overlap_beginning_handler, tc) +{ + char a[7] = { 4, 0, 2, 1, 3, 1, 2 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcpy_s(&a[0], 7, &a[0]) != 0); + assert(a[0] == 4); + assert(e != 0); + assert(0 == strcmp(m, "strcpy_s : memory overlaps")); +} + +/* s1max == 0, handler */ +ATF_TC_WITHOUT_HEAD(s1max_eq_0_handler); +ATF_TC_BODY(s1max_eq_0_handler, tc) +{ + char a[2] = { 3, 0 }; + const char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strcpy_s(&a[0], 0, &b[0]) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strcpy_s : s1max == 0")); +} + +/* trival input */ +ATF_TC_WITHOUT_HEAD(trivial_input); +ATF_TC_BODY(trivial_input, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[1] = { 0 }; + + assert(strcpy_s(&a[0], 4, &b[0]) == 0); + assert(a[0] == 0); + assert(b[0] == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, s1_null_ptr); + ATF_TP_ADD_TC(tp, s1max_gt_rmax); + ATF_TP_ADD_TC(tp, s1max_lt_0); + ATF_TP_ADD_TC(tp, normal); + ATF_TP_ADD_TC(tp, s2_null_ptr); + ATF_TP_ADD_TC(tp, n_gt_s1max); + ATF_TP_ADD_TC(tp, n_eq_s1max); + ATF_TP_ADD_TC(tp, overlap_end); + ATF_TP_ADD_TC(tp, overlap_middle); + ATF_TP_ADD_TC(tp, overlap_beginning); + ATF_TP_ADD_TC(tp, s1_null_ptr_handler); + ATF_TP_ADD_TC(tp, s1max_gt_rmax_handler); + ATF_TP_ADD_TC(tp, s1max_lt_0_handler); + ATF_TP_ADD_TC(tp, normal_handler); + ATF_TP_ADD_TC(tp, s2_null_ptr_handler); + ATF_TP_ADD_TC(tp, n_gt_s1max_handler); + ATF_TP_ADD_TC(tp, n_eq_s1max_handler); + ATF_TP_ADD_TC(tp, overlap_end_handler); + ATF_TP_ADD_TC(tp, overlap_middle_handler); + ATF_TP_ADD_TC(tp, overlap_beginning_handler); + ATF_TP_ADD_TC(tp, s1max_eq_0_handler); + ATF_TP_ADD_TC(tp, trivial_input); + return (atf_no_error()); +} Index: lib/libc/tests/string/strerror_s_test.c =================================================================== --- /dev/null +++ lib/libc/tests/string/strerror_s_test.c @@ -0,0 +1,297 @@ +/*- + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include + +static errno_t e; +static const char * restrict m; + +void +h(const char * restrict msg, void * restrict ptr __unused, errno_t error) +{ + e = error; + m = msg; +} + +/* s null ptr */ +ATF_TC_WITHOUT_HEAD(s_null_ptr); +ATF_TC_BODY(s_null_ptr, tc) +{ + assert(strerror_s(0, 1, EINVAL) != 0); +} + +/* s null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s_null_ptr_handler); +ATF_TC_BODY(s_null_ptr_handler, tc) +{ + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strerror_s(0, 1, EINVAL) != 0); + assert(e != 0); + assert(0 == strcmp(m, "strerror_s : s is NULL")); +} + +/* maxsize > rmax */ +ATF_TC_WITHOUT_HEAD(maxsize_gt_rmax); +ATF_TC_BODY(maxsize_gt_rmax, tc) +{ + char a[2] = { 1, 2 }; + + assert(strerror_s(&a[0], RSIZE_MAX + 1, EINVAL) != 0); + assert(a[0] == 1); + assert(a[1] == 2); +} + +/* maxsize > rmax, handler */ +ATF_TC_WITHOUT_HEAD(maxsize_gt_rmax_handler); +ATF_TC_BODY(maxsize_gt_rmax_handler, tc) +{ + char a[2] = { 1, 2 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strerror_s(&a[0], RSIZE_MAX + 1, EINVAL) != 0); + assert(a[0] == 1); + assert(a[1] == 2); + assert(e != 0); + assert(0 == strcmp(m, "strerror_s : maxsize > RSIZE_MAX")); +} + +/* maxsize < 0 */ +ATF_TC_WITHOUT_HEAD(maxsize_lt_0); +ATF_TC_BODY(maxsize_lt_0, tc) +{ + char a[2] = { 1, 2 }; + + assert(strerror_s(&a[0], -1, EINVAL) != 0); + assert(a[0] == 1); + assert(a[1] == 2); +} + +/* maxsize < 0, handler */ +ATF_TC_WITHOUT_HEAD(maxsize_lt_0_handler); +ATF_TC_BODY(maxsize_lt_0_handler, tc) +{ + char a[2] = { 1, 2 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strerror_s(&a[0], -1, EINVAL) != 0); + assert(a[0] == 1); + assert(a[1] == 2); + assert(e != 0); + assert(0 == strcmp(m, "strerror_s : maxsize > RSIZE_MAX")); +} + +/* maxsize = 0 */ +ATF_TC_WITHOUT_HEAD(maxsize_eq_0); +ATF_TC_BODY(maxsize_eq_0, tc) +{ + char a[2] = { 1, 2 }; + + assert(strerror_s(&a[0], 0, EINVAL) != 0); + assert(a[0] == 1); + assert(a[1] == 2); +} + +/* maxsize = 0, handler */ +ATF_TC_WITHOUT_HEAD(maxsize_eq_0_handler); +ATF_TC_BODY(maxsize_eq_0_handler, tc) +{ + char a[2] = { 1, 2 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strerror_s(&a[0], 0, EINVAL) != 0); + assert(a[0] == 1); + assert(a[1] == 2); + assert(e != 0); + assert(0 == strcmp(m, "strerror_s : maxsize == 0")); +} + +/* short 1 */ +ATF_TC_WITHOUT_HEAD(short_1); +ATF_TC_BODY(short_1, tc) +{ + char a[5] = { 1, 2, 3, 4, 5 }; + + assert(strerror_s(&a[0], 1, EINVAL) != 0); + assert(a[0] == 0); + assert(a[1] == 2); +} + +/* short 2 */ +ATF_TC_WITHOUT_HEAD(short_2); +ATF_TC_BODY(short_2, tc) +{ + char a[5] = { 1, 2, 3, 4, 5 }; + + assert(strerror_s(&a[0], 2, EINVAL) != 0); + assert(a[0] == '.'); + assert(a[1] == 0); + assert(a[2] == 3); +} + +/* short 3 */ +ATF_TC_WITHOUT_HEAD(short_3); +ATF_TC_BODY(short_3, tc) +{ + char a[5] = { 1, 2, 3, 4, 5 }; + + assert(strerror_s(&a[0], 3, EINVAL) != 0); + assert(a[0] == '.'); + assert(a[1] == '.'); + assert(a[2] == 0); + assert(a[3] == 4); +} + +/* short 4 */ +ATF_TC_WITHOUT_HEAD(short_4); +ATF_TC_BODY(short_4, tc) +{ + char a[5] = { 1, 2, 3, 4, 5 }; + + assert(strerror_s(&a[0], 4, EINVAL) != 0); + assert(a[0] == '.'); + assert(a[1] == '.'); + assert(a[2] == '.'); + assert(a[3] == 0); + assert(a[4] == 5); +} + +/* normal */ +ATF_TC_WITHOUT_HEAD(normal); +ATF_TC_BODY(normal, tc) +{ + char *a; + size_t len; + + len = strerrorlen_s(EINVAL)+1; + a = (char *)calloc(len, 1); + a[len-1] = 'f'; + assert(strerror_s(a, len, EINVAL) == 0); + assert(a[0] != 0); + assert(a[len-1] == 0); +} + +/* normal, handler */ +ATF_TC_WITHOUT_HEAD(normal_handler); +ATF_TC_BODY(normal_handler, tc) +{ + char *a; + size_t len; + + len = strerrorlen_s(EINVAL)+1; + e = 0; + m = NULL; + set_constraint_handler_s(h); + a = (char *)calloc(len, 1); + a[len-1] = 'f'; + assert(strerror_s(a, len, EINVAL) == 0); + assert(a[0] != 0); + assert(a[len-1] == 0); + assert(e == 0); + assert(m == NULL); +} + +/* mid short */ +ATF_TC_WITHOUT_HEAD(mid_short); +ATF_TC_BODY(mid_short, tc) +{ + char *a; + size_t len; + + len = strerrorlen_s(EINVAL)+1; + if (len > 5) { + a = (char *)malloc(len); + memset(a, -1, len); + assert(strerror_s(a, len-1, EINVAL) != 0); + assert(a[0] != -1); + assert(a[0] != 0); + assert(a[len-1] == -1); + assert(a[len-2] == 0); + assert(a[len-3] == '.'); + assert(a[len-4] == '.'); + assert(a[len-5] == '.'); + } +} + +/* abusive normal, handler */ +ATF_TC_WITHOUT_HEAD(abusive_normal_handler); +ATF_TC_BODY(abusive_normal_handler, tc) +{ + int i; + char *a; + size_t len; + + for (i = -1234; i < 1235; i++) { + len = strerrorlen_s(i)+1; + e = 0; + m = NULL; + set_constraint_handler_s(h); + a = (char *)calloc(len, 1); + a[len-1] = 'f'; + assert(strerror_s(a, len, i) == 0); + assert(a[0] != 0); + assert(a[len-1] == 0); + assert(e == 0); + assert(m == NULL); + free(a); + } +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, s_null_ptr); + ATF_TP_ADD_TC(tp, s_null_ptr_handler); + ATF_TP_ADD_TC(tp, maxsize_gt_rmax); + ATF_TP_ADD_TC(tp, maxsize_gt_rmax_handler); + ATF_TP_ADD_TC(tp, maxsize_lt_0); + ATF_TP_ADD_TC(tp, maxsize_lt_0_handler); + ATF_TP_ADD_TC(tp, maxsize_eq_0); + ATF_TP_ADD_TC(tp, maxsize_eq_0_handler); + ATF_TP_ADD_TC(tp, short_1); + ATF_TP_ADD_TC(tp, short_2); + ATF_TP_ADD_TC(tp, short_3); + ATF_TP_ADD_TC(tp, short_4); + ATF_TP_ADD_TC(tp, normal); + ATF_TP_ADD_TC(tp, normal_handler); + ATF_TP_ADD_TC(tp, mid_short); + ATF_TP_ADD_TC(tp, abusive_normal_handler); + return (atf_no_error()); +} Index: lib/libc/tests/string/strncat_s_test.c =================================================================== --- /dev/null +++ lib/libc/tests/string/strncat_s_test.c @@ -0,0 +1,740 @@ +/*- + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +static errno_t e; +static const char * restrict m; + +void +h(const char * restrict msg, void * restrict ptr __unused, errno_t error) +{ + e = error; + m = msg; +} + +/* s1 null ptr */ +ATF_TC_WITHOUT_HEAD(s1_null_ptr); +ATF_TC_BODY(s1_null_ptr, tc) +{ + char b[2] = { 5, 0 }; + + assert(strncat_s(0, 1, &b[0], 2) != 0); + assert(b[0] == 5); +} + +/* s1max > rmax */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rmax); +ATF_TC_BODY(s1max_gt_rmax, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + assert(strncat_s(&a[0], RSIZE_MAX + 1, &b[0], 2) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* s1max < 0 */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0); +ATF_TC_BODY(s1max_lt_0, tc) +{ + char a[2] = { 3, 0 }; + const char b[2] = { 5, 0 }; + + assert(strncat_s(&a[0], -1, &b[0], 2) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* normal */ +ATF_TC_WITHOUT_HEAD(normal); +ATF_TC_BODY(normal, tc) +{ + char a[4] = { 4, 0, 2, 1 }; + char b[2] = { 5, 0 }; + + assert(strncat_s(&a[0], 4, &b[0], 2) == 0); + assert(a[0] == 4); + assert(a[1] == 5); + assert(a[2] == 0); + assert(b[0] == 5); +} + +/* s2 null ptr */ +ATF_TC_WITHOUT_HEAD(s2_null_ptr); +ATF_TC_BODY(s2_null_ptr, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + + assert(strncat_s(&a[0], 4, 0, 1) != 0); + assert(a[0] == 0); + assert(a[1] == 3); +} + +/* s1 full already, poor s1 */ +ATF_TC_WITHOUT_HEAD(s1_full_poor_s1); +ATF_TC_BODY(s1_full_poor_s1, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[2] = { 5, 0 }; + + assert(strncat_s(&a[0], 4, &b[0], 2) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); +} + +/* s1 full already, normal case */ +ATF_TC_WITHOUT_HEAD(s1_full_normal_case); +ATF_TC_BODY(s1_full_normal_case, tc) +{ + char a[4] = { 4, 3, 2, 0 }; + char b[2] = { 5, 0 }; + + assert(strncat_s(&a[0], 4, &b[0], 2) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); +} + +/* s1 full already, but nothing to cat */ +ATF_TC_WITHOUT_HEAD(s1_full_nothing_to_cat); +ATF_TC_BODY(s1_full_nothing_to_cat, tc) +{ + char a[4] = { 4, 3, 2, 0 }; + char b[2] = { 0, 1 }; + + assert(strncat_s(&a[0], 4, &b[0], 2) == 0); + assert(a[0] == 4); + assert(a[3] == 0); + assert(b[0] == 0); +} + +/* s1 will become full, not enough space for null terminator */ +ATF_TC_WITHOUT_HEAD(s1_full_no_space_for_null); +ATF_TC_BODY(s1_full_no_space_for_null, tc) +{ + char a[4] = { 4, 3, 0, 1 }; + char b[3] = { 5, 6, 0 }; + + assert(strncat_s(&a[0], 4, &b[0], 3) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); +} + +/* s1 will become full, simple case */ +ATF_TC_WITHOUT_HEAD(s1_becomes_full_simple); +ATF_TC_BODY(s1_becomes_full_simple, tc) +{ + char a[6] = { 4, 3, 0, 1, 2, 3 }; + char b[5] = { 5, 6, 7, 8, 0 }; + + assert(strncat_s(&a[0], 6, &b[0], 5) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); +} + +/* s1max == 0 */ +ATF_TC_WITHOUT_HEAD(s1max_eq_0); +ATF_TC_BODY(s1max_eq_0, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + assert(strncat_s(&a[0], 0, &b[0], 2) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* + * s1 will become full, + * not enough space for null terminator, + * overlapping s1 and s2 + */ +ATF_TC_WITHOUT_HEAD(complex_1); +ATF_TC_BODY(complex_1, tc) +{ + char a[4] = { 4, 3, 0, 1 }; + + assert(strncat_s(&a[0], 4, &a[0], 4) != 0); + assert(a[0] == 4); + assert(a[1] == 3); +} + +/* overlapping no zero fill */ +ATF_TC_WITHOUT_HEAD(overlapping_no_zero_fill); +ATF_TC_BODY(overlapping_no_zero_fill, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + assert(strncat_s(&a[0], 5, &a[0], 5) != 0); + assert(a[0] == 4); + assert(a[1] == 3); +} + +/* overlapping zero fill */ +ATF_TC_WITHOUT_HEAD(overlap_zero_fill); +ATF_TC_BODY(overlap_zero_fill, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + assert(strncat_s(&a[0], 5, &a[1], 4) != 0); + assert(a[0] == 0); + assert(a[1] == 3); +} + +/* overlapping, nothing to cat */ +ATF_TC_WITHOUT_HEAD(overlapping_nothing_to_cat); +ATF_TC_BODY(overlapping_nothing_to_cat, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + assert(strncat_s(&a[0], 5, &a[2], 3) == 0); + assert(a[0] == 4); + assert(a[2] == 0); +} + +/* s1 null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s1_null_ptr_handler); +ATF_TC_BODY(s1_null_ptr_handler, tc) +{ + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(0, 1, &b[0], 2) != 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1 is NULL")); +} + +/* s1max > rmax, handler */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rmax_handler); +ATF_TC_BODY(s1max_gt_rmax_handler, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], RSIZE_MAX + 1, &b[0], 2) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1max > RSIZE_MAX")); +} + +/* s1max < 0, handler */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0_handler); +ATF_TC_BODY(s1max_lt_0_handler, tc) +{ + char a[2] = { 3, 0 }; + const char b[2] = {5, 0}; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], -1, &b[0], 2) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1max > RSIZE_MAX")); +} + +/* normal, handler */ +ATF_TC_WITHOUT_HEAD(normal_handler); +ATF_TC_BODY(normal_handler, tc) +{ + char a[4] = { 4, 0, 2, 1 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 4, &b[0], 2) == 0); + assert(a[0] == 4); + assert(a[1] == 5); + assert(a[2] == 0); + assert(b[0] == 5); + assert(e == 0); + assert(m == NULL); +} + +/* s2 null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s2_null_ptr_handler); +ATF_TC_BODY(s2_null_ptr_handler, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 4, 0, 1) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s2 is NULL")); +} + +/* s1 full already, poor s1, handler */ +ATF_TC_WITHOUT_HEAD(s1_full_poor_s1_handler); +ATF_TC_BODY(s1_full_poor_s1_handler, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 4, &b[0], 2) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1 is full")); +} + +/* s1 full already, normal case, handler */ +ATF_TC_WITHOUT_HEAD(s1_full_normal_handler); +ATF_TC_BODY(s1_full_normal_handler, tc) +{ + char a[4] = { 4, 3, 2, 0 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 4, &b[0], 2) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1 will overflow")); +} + +/* s1 full already, but nothing to cat, handler */ +ATF_TC_WITHOUT_HEAD(s1_full_nothing_to_cat_handler); +ATF_TC_BODY(s1_full_nothing_to_cat_handler, tc) +{ + char a[4] = { 4, 3, 2, 0 }; + char b[2] = { 0, 1 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 4, &b[0], 2) == 0); + assert(a[0] == 4); + assert(a[3] == 0); + assert(b[0] == 0); + assert(e == 0); + assert(m == NULL); +} + +/* s1 will become full, not enough space for null terminator, handler */ +ATF_TC_WITHOUT_HEAD(complex_2); +ATF_TC_BODY(complex_2, tc) +{ + char a[4] = { 4, 3, 0, 1 }; + char b[3] = { 5, 6, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 4, &b[0], 3) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1 will overflow")); +} + +/* s1 will become full, simple case, handler */ +ATF_TC_WITHOUT_HEAD(s1_becomes_full_simple_handler); +ATF_TC_BODY(s1_becomes_full_simple_handler, tc) +{ + char a[6] = { 4, 3, 0, 1, 2, 3 }; + char b[5] = { 5, 6, 7, 8, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 6, &b[0], 5) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1 will overflow")); +} + +/* s1max == 0, handler */ +ATF_TC_WITHOUT_HEAD(s1max_eq_0_handler); +ATF_TC_BODY(s1max_eq_0_handler, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 0, &b[0], 2) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1max == 0")); +} + +/* + * s1 will become full, + * not enough space for null terminator, + * overlapping s1 and s2, + * handler + */ +ATF_TC_WITHOUT_HEAD(complex_3); +ATF_TC_BODY(complex_3, tc) +{ + char a[4] = { 4, 3, 0, 1 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 4, &a[0], 4) != 0); + assert(a[0] == 4); + assert(a[1] == 3); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1 will overflow")); +} + +/* overlapping no zero fill, handler */ +ATF_TC_WITHOUT_HEAD(overlapping_no_zero_fill_handler); +ATF_TC_BODY(overlapping_no_zero_fill_handler, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 5, &a[0], 5) != 0); + assert(a[0] == 4); + assert(a[1] == 3); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : memory overlaps")); +} + +/* overlapping zero fill, handler */ +ATF_TC_WITHOUT_HEAD(overlapping_zero_fill_handler); +ATF_TC_BODY(overlapping_zero_fill_handler, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 5, &a[1], 4) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : memory overlaps")); +} + +/* n > rmax */ +ATF_TC_WITHOUT_HEAD(n_gt_rmax); +ATF_TC_BODY(n_gt_rmax, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + assert(strncat_s(&a[0], 2, &b[0], RSIZE_MAX+1) != 0); + assert(a[0] == 0); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* n < 0 */ +ATF_TC_WITHOUT_HEAD(n_lt_0); +ATF_TC_BODY(n_lt_0, tc) +{ + char a[2] = { 3, 0 }; + const char b[2] = { 5, 0 }; + + assert(strncat_s(&a[0], 2, &b[0], -1) != 0); + assert(a[0] == 0); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* n > rmax, handler */ +ATF_TC_WITHOUT_HEAD(n_gt_rmax_handler); +ATF_TC_BODY(n_gt_rmax_handler, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 2, &b[0], RSIZE_MAX+1) != 0); + assert(a[0] == 0); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : n > RSIZE_MAX")); +} + +/* n < 0, handler */ +ATF_TC_WITHOUT_HEAD(n_lt_0_handler); +ATF_TC_BODY(n_lt_0_handler, tc) +{ + char a[2] = { 3, 0 }; + const char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 2, &b[0], -1) != 0); + assert(a[0] == 0); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : n > RSIZE_MAX")); +} + +/* overlapping, nothing to cat, handler */ +ATF_TC_WITHOUT_HEAD(overlapping_nothing_to_cat_handler); +ATF_TC_BODY(overlapping_nothing_to_cat_handler, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 5, &a[2], 1) == 0); + assert(a[0] == 4); + assert(a[2] == 0); + assert(e == 0); + assert(m == NULL); +} + +/* normal, n */ +ATF_TC_WITHOUT_HEAD(normal_n); +ATF_TC_BODY(normal_n, tc) +{ + char a[4] = { 4, 0, 2, 1 }; + char b[2] = { 5, 0 }; + + assert(strncat_s(&a[0], 4, &b[0], 1) == 0); + assert(a[0] == 4); + assert(a[1] == 5); + assert(a[2] == 0); + assert(b[0] == 5); +} + +/* s1 full already, normal case, n, handler */ +ATF_TC_WITHOUT_HEAD(s1_full_normal_n_handler); +ATF_TC_BODY(s1_full_normal_n_handler, tc) +{ + char a[4] = { 4, 3, 2, 0 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 4, &b[0], 1) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1 will overflow")); +} + +/* s1 will become full, n, simple case, handler */ +ATF_TC_WITHOUT_HEAD(s1_will_become_full_n_simple_handler); +ATF_TC_BODY(s1_will_become_full_n_simple_handler, tc) +{ + char a[6] = { 4, 3, 0, 1, 2, 3 }; + char b[5] = { 5, 6, 7, 8, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 6, &b[0], 4) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1 will overflow")); +} + +/* s1 full already, but nothing to cat, n, handler */ +ATF_TC_WITHOUT_HEAD(s1_full_nothing_to_cat_n_handler); +ATF_TC_BODY(s1_full_nothing_to_cat_n_handler, tc) +{ + char a[4] = { 4, 3, 2, 0 }; + char b[2] = { 0, 1 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 4, &b[0], 0) == 0); + assert(a[0] == 4); + assert(a[3] == 0); + assert(b[0] == 0); + assert(e == 0); + assert(m == NULL); +} + +/* s1 will become full, not enough space for null terminator, n, handler */ +ATF_TC_WITHOUT_HEAD(complex_4); +ATF_TC_BODY(complex_4, tc) +{ + char a[4] = { 4, 3, 0, 1 }; + char b[3] = { 5, 6, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 4, &b[0], 2) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1 will overflow")); +} + +/* s1 will become full, simple case, n, handler */ +ATF_TC_WITHOUT_HEAD(s1_will_become_full_simple_n_handler); +ATF_TC_BODY(s1_will_become_full_simple_n_handler, tc) +{ + char a[6] = { 4, 3, 0, 1, 2, 3 }; + char b[5] = { 5, 6, 7, 8, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 6, &b[0], 4) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : s1 will overflow")); +} + +/* overlapping no zero fill, n, handler */ +ATF_TC_WITHOUT_HEAD(overlapping_no_zero_fill_n_handler); +ATF_TC_BODY(overlapping_no_zero_fill_n_handler, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 5, &a[0], 2) != 0); + assert(a[0] == 4); + assert(a[1] == 3); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : memory overlaps")); +} + +/* overlapping zero fill, n, handler */ +ATF_TC_WITHOUT_HEAD(overlapping_zero_fill_n_handler); +ATF_TC_BODY(overlapping_zero_fill_n_handler, tc) +{ + char a[5] = { 4, 3, 0, 1, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncat_s(&a[0], 5, &a[1], 1) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(e != 0); + assert(0 == strcmp(m, "strncat_s : memory overlaps")); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, s1_null_ptr); + ATF_TP_ADD_TC(tp, s1max_gt_rmax); + ATF_TP_ADD_TC(tp, s1max_lt_0); + ATF_TP_ADD_TC(tp, normal); + ATF_TP_ADD_TC(tp, s2_null_ptr); + ATF_TP_ADD_TC(tp, s1_full_poor_s1); + ATF_TP_ADD_TC(tp, s1_full_normal_case); + ATF_TP_ADD_TC(tp, s1_full_nothing_to_cat); + ATF_TP_ADD_TC(tp, s1_full_no_space_for_null); + ATF_TP_ADD_TC(tp, s1_becomes_full_simple); + ATF_TP_ADD_TC(tp, s1max_eq_0); + ATF_TP_ADD_TC(tp, complex_1); + ATF_TP_ADD_TC(tp, overlapping_no_zero_fill); + ATF_TP_ADD_TC(tp, overlap_zero_fill); + ATF_TP_ADD_TC(tp, overlapping_nothing_to_cat); + ATF_TP_ADD_TC(tp, s1_null_ptr_handler); + ATF_TP_ADD_TC(tp, s1max_gt_rmax_handler); + ATF_TP_ADD_TC(tp, s1max_lt_0_handler); + ATF_TP_ADD_TC(tp, normal_handler); + ATF_TP_ADD_TC(tp, s2_null_ptr_handler); + ATF_TP_ADD_TC(tp, s1_full_poor_s1_handler); + ATF_TP_ADD_TC(tp, s1_full_normal_handler); + ATF_TP_ADD_TC(tp, s1_full_nothing_to_cat_handler); + ATF_TP_ADD_TC(tp, complex_2); + ATF_TP_ADD_TC(tp, s1_becomes_full_simple_handler); + ATF_TP_ADD_TC(tp, s1max_eq_0_handler); + ATF_TP_ADD_TC(tp, complex_3); + ATF_TP_ADD_TC(tp, overlapping_no_zero_fill_handler); + ATF_TP_ADD_TC(tp, overlapping_zero_fill_handler); + ATF_TP_ADD_TC(tp, overlapping_nothing_to_cat_handler); + ATF_TP_ADD_TC(tp, n_gt_rmax); + ATF_TP_ADD_TC(tp, n_lt_0); + ATF_TP_ADD_TC(tp, n_gt_rmax_handler); + ATF_TP_ADD_TC(tp, n_lt_0_handler); + ATF_TP_ADD_TC(tp, normal_n); + ATF_TP_ADD_TC(tp, s1_full_normal_n_handler); + ATF_TP_ADD_TC(tp, s1_will_become_full_n_simple_handler); + ATF_TP_ADD_TC(tp, s1_full_nothing_to_cat_n_handler); + ATF_TP_ADD_TC(tp, complex_4); + ATF_TP_ADD_TC(tp, s1_will_become_full_simple_n_handler); + ATF_TP_ADD_TC(tp, overlapping_no_zero_fill_n_handler); + ATF_TP_ADD_TC(tp, overlapping_zero_fill_n_handler); + return (atf_no_error()); +} + Index: lib/libc/tests/string/strncpy_s_test.c =================================================================== --- /dev/null +++ lib/libc/tests/string/strncpy_s_test.c @@ -0,0 +1,439 @@ +/*- + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +static errno_t e; +static const char * restrict m; + +void +h(const char * restrict msg, void * restrict ptr __unused, errno_t error) +{ + e = error; + m = msg; +} + +/* s1 null ptr */ +ATF_TC_WITHOUT_HEAD(s1_null_ptr); +ATF_TC_BODY(s1_null_ptr, tc) +{ + char b[2] = { 5, 0 }; + + assert(strncpy_s(0, 1, &b[0], 2) != 0); + assert(b[0] == 5); +} + +/* s1max > rmax */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rmax); +ATF_TC_BODY(s1max_gt_rmax, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + assert(strncpy_s(&a[0], RSIZE_MAX + 1, &b[0], 2) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* s1max < 0 */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0); +ATF_TC_BODY(s1max_lt_0, tc) +{ + char a[2] = { 3, 0 }; + const char b[2] = { 5, 0 }; + + assert(strncpy_s(&a[0], -1, &b[0], 2) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* normal */ +ATF_TC_WITHOUT_HEAD(normal); +ATF_TC_BODY(normal, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[2] = { 5, 0 }; + + assert(strncpy_s(&a[0], 4, &b[0], 2) == 0); + assert(a[0] == 5); + assert(a[1] == 0); + assert(b[0] == 5); +} + +/* s2 null ptr */ +ATF_TC_WITHOUT_HEAD(s2_null_ptr); +ATF_TC_BODY(s2_null_ptr, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + + assert(strncpy_s(&a[0], 4, 0, 0) != 0); + assert(a[0] == 0); + assert(a[1] == 3); +} + +/* n > s1max */ +ATF_TC_WITHOUT_HEAD(n_gt_s1max); +ATF_TC_BODY(n_gt_s1max, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[6] = { 5, 4, 3, 2, 1, 0 }; + + assert(strncpy_s(&a[0], 4, &b[0], 6) != 0); + assert(a[0] == 0); + assert(b[0] == 5); +} + +/* n == s1max */ +ATF_TC_WITHOUT_HEAD(n_eq_s1max); +ATF_TC_BODY(n_eq_s1max, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[4] = { 5, 4, 3, 0 }; + + assert(strncpy_s(&a[0], 4, &b[0], 4) == 0); + assert(a[0] == 5); + assert(a[1] == 4); + assert(a[2] == 3); + assert(a[3] == 0); + assert(b[0] == 5); +} + +/* n == s1max, inferred */ +ATF_TC_WITHOUT_HEAD(n_eq_s1max_inferred); +ATF_TC_BODY(n_eq_s1max_inferred, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[6] = { 5, 4, 3, 0, 2, 3 }; + + assert(strncpy_s(&a[0], 4, &b[0], 6) == 0); + assert(a[0] == 5); + assert(a[1] == 4); + assert(a[2] == 3); + assert(a[3] == 0); + assert(b[0] == 5); +} + +/* overlap end */ +ATF_TC_WITHOUT_HEAD(overlap_end); +ATF_TC_BODY(overlap_end, tc) +{ + char a[10] = { 4, 3, 2, 1, 1, 2, 3, 4, 0 }; + + assert(strncpy_s(&a[0], 5, &a[4], 6) != 0); + assert(a[0] == 0); +} + +/* overlap middle */ +ATF_TC_WITHOUT_HEAD(overlap_middle); +ATF_TC_BODY(overlap_middle, tc) +{ + char a[8] = { 4, 3, 2, 1, 1, 2, 3, 0 }; + + assert(strncpy_s(&a[0], 8, &a[2], 6) != 0); + assert(a[0] == 0); +} + +/* overlap beginning */ +ATF_TC_WITHOUT_HEAD(overlap_beginning); +ATF_TC_BODY(overlap_beginning, tc) +{ + char a[7] = { 4, 0, 2, 1, 3, 1, 2 }; + + assert(strncpy_s(&a[0], 7, &a[0], 7) != 0); + assert(a[0] == 4); +} + +/* s1 null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s1_null_ptr_handler); +ATF_TC_BODY(s1_null_ptr_handler, tc) +{ + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncpy_s(0, 1, &b[0], 2) != 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncpy_s : s1 is NULL")); +} + +/* s1max > rmax, handler */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rmax_handler); +ATF_TC_BODY(s1max_gt_rmax_handler, tc) +{ + char a[2] = { 3, 0 }; + char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncpy_s(&a[0], RSIZE_MAX + 1, &b[0], 2) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncpy_s : s1max > RSIZE_MAX")); +} + +/* s1max < 0, handler */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0_handler); +ATF_TC_BODY(s1max_lt_0_handler, tc) +{ + char a[2] = { 3, 0 }; + const char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncpy_s(&a[0], -1, &b[0], 2) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncpy_s : s1max > RSIZE_MAX")); +} + +/* normal, handler */ +ATF_TC_WITHOUT_HEAD(normal_handler); +ATF_TC_BODY(normal_handler, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + const char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncpy_s(&a[0], 4, &b[0], 2) == 0); + assert(a[0] == 5); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e == 0); + assert(m == NULL); +} + +/* s2 null ptr, handler */ +ATF_TC_WITHOUT_HEAD(s2_null_ptr_handler); +ATF_TC_BODY(s2_null_ptr_handler, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncpy_s(&a[0], 4, 0, 0) != 0); + assert(a[0] == 0); + assert(a[1] == 3); + assert(e != 0); + assert(0 == strcmp(m, "strncpy_s : s2 is NULL")); +} + +/* n > s1max, handler */ +ATF_TC_WITHOUT_HEAD(n_gt_s1max_handler); +ATF_TC_BODY(n_gt_s1max_handler, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[6] = { 5, 4, 3, 2, 1, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncpy_s(&a[0], 4, &b[0], 6) != 0); + assert(a[0] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncpy_s : s2 will be truncated")); +} + +/* n == s1max, handler */ +ATF_TC_WITHOUT_HEAD(n_eq_s1max_handler); +ATF_TC_BODY(n_eq_s1max_handler, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + const char b[5] = { 5, 4, 3, 2, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncpy_s(&a[0], 4, &b[0], 4) != 0); + assert(a[0] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncpy_s : s2 will be truncated")); +} + +/* overlap end, handler */ +ATF_TC_WITHOUT_HEAD(overlap_end_handler); +ATF_TC_BODY(overlap_end_handler, tc) +{ + char a[10] = { 4, 3, 2, 1, 1, 2, 3, 4, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncpy_s(&a[0], 5, &a[4], 6) != 0); + assert(a[0] == 0); + assert(e != 0); + assert(0 == strcmp(m, "strncpy_s : memory overlaps")); +} + +/* overlap middle, handler */ +ATF_TC_WITHOUT_HEAD(overlap_middle_handler); +ATF_TC_BODY(overlap_middle_handler, tc) +{ + char a[8] = { 4, 3, 2, 1, 1, 2, 3, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncpy_s(&a[0], 8, &a[2], 6) != 0); + assert(a[0] == 0); + assert(e != 0); + assert(0 == strcmp(m, "strncpy_s : memory overlaps")); +} + +/* overlap beginning, handler */ +ATF_TC_WITHOUT_HEAD(overlap_beginning_handler); +ATF_TC_BODY(overlap_beginning_handler, tc) +{ + char a[7] = { 4, 0, 2, 1, 3, 1, 2 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncpy_s(&a[0], 7, &a[0], 7) != 0); + assert(a[0] == 4); + assert(e != 0); + assert(0 == strcmp(m, "strncpy_s : memory overlaps")); +} + +/* s1max == 0, handler */ +ATF_TC_WITHOUT_HEAD(s1max_eq_0_handler); +ATF_TC_BODY(s1max_eq_0_handler, tc) +{ + char a[2] = { 3, 0 }; + const char b[2] = { 5, 0 }; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(strncpy_s(&a[0], 0, &b[0], 2) != 0); + assert(a[0] == 3); + assert(a[1] == 0); + assert(b[0] == 5); + assert(e != 0); + assert(0 == strcmp(m, "strncpy_s : s1max == 0")); +} + +/* trivial input */ +ATF_TC_WITHOUT_HEAD(trivial_input); +ATF_TC_BODY(trivial_input, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[1] = { 0 }; + + assert(strncpy_s(&a[0], 4, &b[0], 1) == 0); + assert(a[0] == 0); + assert(b[0] == 0); +} + +/* trivial input, inferred */ +ATF_TC_WITHOUT_HEAD(trivial_input_inferred); +ATF_TC_BODY(trivial_input_inferred, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[5] = { 0, 1, 2, 3, 4 }; + + assert(strncpy_s(&a[0], 4, &b[0], 5) == 0); + assert(a[0] == 0); + assert(b[0] == 0); +} + +/* null terminate */ +ATF_TC_WITHOUT_HEAD(null_terminate); +ATF_TC_BODY(null_terminate, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[2] = { 1, 2 }; + + assert(strncpy_s(&a[0], 4, &b[0], 2) == 0); + assert(a[0] == 1); + assert(a[1] == 2); + assert(a[2] == 0); + assert(b[0] == 1); +} + +/* do nothing */ +ATF_TC_WITHOUT_HEAD(do_nothing); +ATF_TC_BODY(do_nothing, tc) +{ + char a[4] = { 4, 3, 2, 1 }; + char b[2] = { 1, 2 }; + + assert(strncpy_s(&a[0], 4, &b[0], 0) == 0); + assert(a[0] == 0); + assert(b[0] == 1); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, s1_null_ptr); + ATF_TP_ADD_TC(tp, s1max_gt_rmax); + ATF_TP_ADD_TC(tp, s1max_lt_0); + ATF_TP_ADD_TC(tp, normal); + ATF_TP_ADD_TC(tp, s2_null_ptr); + ATF_TP_ADD_TC(tp, n_gt_s1max); + ATF_TP_ADD_TC(tp, n_eq_s1max); + ATF_TP_ADD_TC(tp, n_eq_s1max_inferred); + ATF_TP_ADD_TC(tp, overlap_end); + ATF_TP_ADD_TC(tp, overlap_middle); + ATF_TP_ADD_TC(tp, overlap_beginning); + ATF_TP_ADD_TC(tp, s1_null_ptr_handler); + ATF_TP_ADD_TC(tp, s1max_gt_rmax_handler); + ATF_TP_ADD_TC(tp, s1max_lt_0_handler); + ATF_TP_ADD_TC(tp, normal_handler); + ATF_TP_ADD_TC(tp, s2_null_ptr_handler); + ATF_TP_ADD_TC(tp, n_gt_s1max_handler); + ATF_TP_ADD_TC(tp, n_eq_s1max_handler); + ATF_TP_ADD_TC(tp, overlap_end_handler); + ATF_TP_ADD_TC(tp, overlap_middle_handler); + ATF_TP_ADD_TC(tp, overlap_beginning_handler); + ATF_TP_ADD_TC(tp, s1max_eq_0_handler); + ATF_TP_ADD_TC(tp, trivial_input); + ATF_TP_ADD_TC(tp, trivial_input_inferred); + ATF_TP_ADD_TC(tp, null_terminate); + ATF_TP_ADD_TC(tp, do_nothing); + return (atf_no_error()); +} Index: lib/libc/tests/string/strnlen_s_test.c =================================================================== --- /dev/null +++ lib/libc/tests/string/strnlen_s_test.c @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +/* s null ptr */ +ATF_TC_WITHOUT_HEAD(s_null_ptr); +ATF_TC_BODY(s_null_ptr, tc) +{ + assert(strnlen_s(0, 1) == 0); +} + +/* 0 maxsize */ +ATF_TC_WITHOUT_HEAD(zero_maxsize); +ATF_TC_BODY(zero_maxsize, tc) +{ + char s[2] = { 48, 0 }; + + assert(strnlen_s(&s[0], 0) == 0); +} + +/* short maxsize */ +ATF_TC_WITHOUT_HEAD(short_maxsize); +ATF_TC_BODY(short_maxsize, tc) +{ + char s[4] = { 48, 48, 48, 0 }; + + assert(strnlen_s(&s[0], 2) == 2); +} + +/* long maxsize */ +ATF_TC_WITHOUT_HEAD(long_maxsize); +ATF_TC_BODY(long_maxsize, tc) +{ + char s[6] = { 48, 48, 48, 0, 48, 48 }; + + assert(strnlen_s(&s[0], 6) == 3); +} + +/* correct maxsize */ +ATF_TC_WITHOUT_HEAD(correct_maxsize); +ATF_TC_BODY(correct_maxsize, tc) +{ + char s[6] = { 48, 48, 48, 0, 48, 48 }; + + assert(strnlen_s(&s[0], 3) == 3); +} + +/* correct maxsize with null */ +ATF_TC_WITHOUT_HEAD(correct_maxsize_with_null); +ATF_TC_BODY(correct_maxsize_with_null, tc) +{ + char s[6] = { 48, 48, 48, 0, 48, 48 }; + + assert(strnlen_s(&s[0], 4) == 3); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, s_null_ptr); + ATF_TP_ADD_TC(tp, zero_maxsize); + ATF_TP_ADD_TC(tp, short_maxsize); + ATF_TP_ADD_TC(tp, long_maxsize); + ATF_TP_ADD_TC(tp, correct_maxsize); + ATF_TP_ADD_TC(tp, correct_maxsize_with_null); + return (atf_no_error()); +} Index: lib/libc/tests/string/strtok_s_test.c =================================================================== --- /dev/null +++ lib/libc/tests/string/strtok_s_test.c @@ -0,0 +1,419 @@ +/*- + * Copyright (c) 2017 Juniper Networks. 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 REGENTS 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 REGENTS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +static errno_t e; +static const char * restrict m; + +void +h(const char * restrict msg, void * restrict ptr __unused, errno_t error) +{ + e = error; + m = msg; +} + +/* s1 & *ptr null */ +ATF_TC_WITHOUT_HEAD(s1_and_ptr_null); +ATF_TC_BODY(s1_and_ptr_null, tc) +{ + char *ptr; + rsize_t s1max; + + ptr = NULL; + s1max = 1; + assert(NULL == strtok_s(0, &s1max, "", &ptr)); +} + +/* s1 & *ptr null, handler */ +ATF_TC_WITHOUT_HEAD(s1_and_ptr_null_handler); +ATF_TC_BODY(s1_and_ptr_null_handler, tc) +{ + char *ptr; + rsize_t s1max; + + ptr = NULL; + s1max = 1; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(NULL == strtok_s(0, &s1max, "", &ptr)); + assert(e != 0); + assert(0 == strcmp(m, "strtok_s : *ptr is NULL")); +} + +/* s1max null */ +ATF_TC_WITHOUT_HEAD(s1max_null); +ATF_TC_BODY(s1max_null, tc) +{ + char *ptr; + + ptr = NULL; + assert(NULL == strtok_s("", NULL, "", &ptr)); +} + +/* s1max null, handler */ +ATF_TC_WITHOUT_HEAD(s1max_null_handler); +ATF_TC_BODY(s1max_null_handler, tc) +{ + char *ptr; + + ptr = NULL; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(NULL == strtok_s("", NULL, "", &ptr)); + assert(e != 0); + assert(0 == strcmp(m, "strtok_s : s1max is NULL")); +} + +/* s2 null */ +ATF_TC_WITHOUT_HEAD(s2_null); +ATF_TC_BODY(s2_null, tc) +{ + char *ptr; + rsize_t s1max; + + ptr = NULL; + s1max = 1; + assert(NULL == strtok_s("", &s1max, NULL, &ptr)); +} + +/* s2 null, handler */ +ATF_TC_WITHOUT_HEAD(s2_null_handler); +ATF_TC_BODY(s2_null_handler, tc) +{ + char *ptr; + rsize_t s1max; + + ptr = NULL; + s1max = 1; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(NULL == strtok_s("", &s1max, NULL, &ptr)); + assert(e != 0); + assert(0 == strcmp(m, "strtok_s : s2 is NULL")); +} + +/* ptr null */ +ATF_TC_WITHOUT_HEAD(ptr_null); +ATF_TC_BODY(ptr_null, tc) +{ + rsize_t s1max; + + s1max = 1; + assert(NULL == strtok_s("", &s1max, "", NULL)); +} + +/* ptr null, handler */ +ATF_TC_WITHOUT_HEAD(ptr_null_handler); +ATF_TC_BODY(ptr_null_handler, tc) +{ + rsize_t s1max; + + s1max = 1; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(NULL == strtok_s("", &s1max, "", NULL)); + assert(e != 0); + assert(0 == strcmp(m, "strtok_s : ptr is NULL")); +} + +/* s1max > RSIZE_MAX */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rsize_max); +ATF_TC_BODY(s1max_gt_rsize_max, tc) +{ + char *ptr; + rsize_t s1max; + + s1max = RSIZE_MAX + 1; + assert(NULL == strtok_s("", &s1max, "", &ptr)); +} + +/* s1max > RSIZE_MAX, handler */ +ATF_TC_WITHOUT_HEAD(s1max_gt_rsize_max_handler); +ATF_TC_BODY(s1max_gt_rsize_max_handler, tc) +{ + char *ptr; + rsize_t s1max; + + s1max = RSIZE_MAX + 1; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(NULL == strtok_s("", &s1max, "", &ptr)); + assert(e != 0); + assert(0 == strcmp(m, "strtok_s : *s1max > RSIZE_MAX")); +} + +/* s1max < 0 */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0); +ATF_TC_BODY(s1max_lt_0, tc) +{ + char *ptr; + rsize_t s1max; + + s1max = -1; + assert(NULL == strtok_s("", &s1max, "", &ptr)); +} + +/* s1max < 0, handler */ +ATF_TC_WITHOUT_HEAD(s1max_lt_0_handler); +ATF_TC_BODY(s1max_lt_0_handler, tc) +{ + char *ptr; + rsize_t s1max; + + s1max = -1; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(NULL == strtok_s("", &s1max, "", &ptr)); + assert(e != 0); + assert(0 == strcmp(m, "strtok_s : *s1max > RSIZE_MAX")); +} + + +/* s2 len 0 */ +ATF_TC_WITHOUT_HEAD(s2_len_eq_0); +ATF_TC_BODY(s2_len_eq_0, tc) +{ + char *ptr; + rsize_t s1max; + + s1max = 4; + assert(NULL == strtok_s("abcd", &s1max, "", &ptr)); +} + +/* s2 len 0, handler */ +ATF_TC_WITHOUT_HEAD(s2_len_eq_0_handler); +ATF_TC_BODY(s2_len_eq_0_handler, tc) +{ + char *ptr; + rsize_t s1max; + + s1max = 4; + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(NULL == strtok_s("abcd", &s1max, "", &ptr)); + assert(e == 0); + assert(m == NULL); +} + +/* first, failure */ +ATF_TC_WITHOUT_HEAD(first_failure); +ATF_TC_BODY(first_failure, tc) +{ + char *str = " + - + - "; + char *dlim = " +-"; + char *ptr; + rsize_t s1max; + + s1max = strlen(str); + assert(NULL == strtok_s(str, &s1max, dlim, &ptr)); + assert(s1max == 0); + assert(ptr == NULL); +} + +/* next, failure */ +ATF_TC_WITHOUT_HEAD(next_failure); +ATF_TC_BODY(next_failure, tc) +{ + char *str = " + - + - "; + char *dlim = "abc"; + char *ptr = str; + rsize_t s1max; + + s1max = strlen(str); + assert(NULL == strtok_s(NULL, &s1max, dlim, &ptr)); + assert(s1max == 0); + assert(ptr == NULL); +} + +/* first, success */ +ATF_TC_WITHOUT_HEAD(first_success); +ATF_TC_BODY(first_success, tc) +{ + char *str = " A - + - "; + char *dlim = " +-"; + char *ptr; + char *tok; + rsize_t s1max; + + s1max = strlen(str); + tok = strtok_s(str, &s1max, dlim, &ptr); + assert(tok == &str[1]); + assert(tok == ptr); + assert(s1max == strlen(tok)); + assert(str[0] == ' '); + assert(str[2] == ' '); +} + +/* first, success 2 */ +ATF_TC_WITHOUT_HEAD(first_success_2); +ATF_TC_BODY(first_success_2, tc) +{ + char *str = "A - + - "; + char *dlim = " +-"; + char *ptr; + char *tok; + rsize_t s1max; + + s1max = strlen(str); + tok = strtok_s(str, &s1max, dlim, &ptr); + assert(tok == &str[0]); + assert(tok == ptr); + assert(s1max == strlen(tok)); + assert(str[1] == ' '); +} + +/* first, success, stop early */ +ATF_TC_WITHOUT_HEAD(first_success_stop_early); +ATF_TC_BODY(first_success_stop_early, tc) +{ + char *str = " A - + - "; + char *dlim = " +-"; + rsize_t s1max; + char *ptr; + char *tok; + + s1max = strlen(str) - 2; + tok = strtok_s(str, &s1max, dlim, &ptr); + assert(tok == &str[1]); + assert(tok == ptr); + assert(s1max == strlen(tok) - 2); + assert(str[0] == ' '); + assert(str[2] == ' '); +} + +/* next, success */ +ATF_TC_WITHOUT_HEAD(next_success); +ATF_TC_BODY(next_success, tc) +{ + char *str; + char *dlim = " +-"; + rsize_t s1max; + char *ptr; + char *tok; + + str = strdup("ABC+DEF"); + ptr = str; + s1max = strlen(str); + tok = strtok_s(NULL, &s1max, dlim, &ptr); + assert(tok == &str[0]); + assert(str[0] == 'A'); + assert(str[1] == 'B'); + assert(str[2] == 'C'); + assert(str[3] == 0); + assert(str[4] == 'D'); + assert(ptr == &str[4]); + assert(s1max == 3); +} + +/* next, success, short */ +ATF_TC_WITHOUT_HEAD(next_success_short); +ATF_TC_BODY(next_success_short, tc) +{ + char *str; + char *dlim = " +-"; + rsize_t s1max; + char *ptr; + char *tok; + + str = strdup("ABC+DEF"); + ptr = str; + s1max = strlen(str) -1; + tok = strtok_s(NULL, &s1max, dlim, &ptr); + assert(tok == &str[0]); + assert(str[0] == 'A'); + assert(str[1] == 'B'); + assert(str[2] == 'C'); + assert(str[3] == 0); + assert(str[4] == 'D'); + assert(ptr == &str[4]); + assert(s1max == 2); +} + +/* next, success, short, last */ +ATF_TC_WITHOUT_HEAD(next_success_short_last); +ATF_TC_BODY(next_success_short_last, tc) +{ + char *str; + char *dlim = " +-"; + rsize_t s1max; + char *ptr; + char *tok; + + str = strdup("ABC+DEF"); + ptr = str; + s1max = strlen(str) -3; + tok = strtok_s(NULL, &s1max, dlim, &ptr); + assert(tok == &str[0]); + assert(str[0] == 'A'); + assert(str[1] == 'B'); + assert(str[2] == 'C'); + assert(str[3] == 0); + assert(str[4] == 'D'); + assert(ptr == NULL); + assert(s1max == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, s1_and_ptr_null); + ATF_TP_ADD_TC(tp, s1_and_ptr_null_handler); + ATF_TP_ADD_TC(tp, s1max_null); + ATF_TP_ADD_TC(tp, s1max_null_handler); + ATF_TP_ADD_TC(tp, s2_null); + ATF_TP_ADD_TC(tp, s2_null_handler); + ATF_TP_ADD_TC(tp, ptr_null); + ATF_TP_ADD_TC(tp, ptr_null_handler); + ATF_TP_ADD_TC(tp, s1max_gt_rsize_max); + ATF_TP_ADD_TC(tp, s1max_gt_rsize_max_handler); + ATF_TP_ADD_TC(tp, s1max_lt_0); + ATF_TP_ADD_TC(tp, s1max_lt_0_handler); + ATF_TP_ADD_TC(tp, s2_len_eq_0); + ATF_TP_ADD_TC(tp, s2_len_eq_0_handler); + ATF_TP_ADD_TC(tp, first_failure); + ATF_TP_ADD_TC(tp, next_failure); + ATF_TP_ADD_TC(tp, first_success); + ATF_TP_ADD_TC(tp, first_success_2); + ATF_TP_ADD_TC(tp, first_success_stop_early); + ATF_TP_ADD_TC(tp, next_success); + ATF_TP_ADD_TC(tp, next_success_short); + ATF_TP_ADD_TC(tp, next_success_short_last); + return (atf_no_error()); +}