diff --git a/newlib/libc/include/errno.h b/newlib/libc/include/errno.h index d52446d122..5e1081fa31 100644 --- a/newlib/libc/include/errno.h +++ b/newlib/libc/include/errno.h @@ -43,4 +43,9 @@ typedef int error_t; #include +#include +#ifdef __STDC_WANT_LIB_EXT1__ +typedef __errno_t errno_t; +#endif + #endif /* !__ERRNO_H__ */ diff --git a/newlib/libc/include/stdint.h b/newlib/libc/include/stdint.h index d7e9bf3666..aa22757e03 100644 --- a/newlib/libc/include/stdint.h +++ b/newlib/libc/include/stdint.h @@ -457,6 +457,17 @@ typedef __uint_least64_t uint_least64_t; #endif #endif -_END_STD_C +#if __STDC_WANT_LIB_EXT1__ == 1 +#include -#endif /* _STDINT_H */ + // could be defined by the user +#ifndef RSIZE_MAX +#define RSIZE_MAX SIZE_MAX +#endif + + typedef __rsize_t rsize_t; +#endif + + _END_STD_C + +#endif /* _STDINT_H */ \ No newline at end of file diff --git a/newlib/libc/include/stdlib.h b/newlib/libc/include/stdlib.h index 7468be3a93..51288b2fa7 100644 --- a/newlib/libc/include/stdlib.h +++ b/newlib/libc/include/stdlib.h @@ -408,10 +408,24 @@ char *__ldtoa (long double, int, int, int *, int *, char **); void __eprintf (const char *, const char *, unsigned int, const char *); #endif +#if __STDC_WANT_LIB_EXT1__ == 1 +#include + +typedef void (*constraint_handler_t)(const char *restrict msg, + void *restrict ptr, __errno_t error); + +extern constraint_handler_t __cur_handler; + +extern constraint_handler_t +set_constraint_handler_s(constraint_handler_t handler); +extern void abort_handler_s(const char *restrict msg, void *restrict ptr, + __errno_t error); +#endif + _END_STD_C #if __SSP_FORTIFY_LEVEL > 0 #include #endif -#endif /* _STDLIB_H_ */ +#endif /* _STDLIB_H_ */ \ No newline at end of file diff --git a/newlib/libc/include/string.h b/newlib/libc/include/string.h index d459f06bae..105b53e964 100644 --- a/newlib/libc/include/string.h +++ b/newlib/libc/include/string.h @@ -201,6 +201,26 @@ int timingsafe_bcmp (const void *, const void *, size_t); int timingsafe_memcmp (const void *, const void *, size_t); #endif +#if __STDC_WANT_LIB_EXT1__ == 1 +#include + +typedef __rsize_t rsize_t; + +extern __errno_t memcpy_s(void *__restrict, rsize_t, const void *__restrict, + rsize_t); +extern __errno_t memset_s(void *, rsize_t, int, rsize_t); +extern __errno_t memmove_s(void *, rsize_t, const void *, rsize_t); +extern __errno_t strcpy_s(char *__restrict, rsize_t, const char *__restrict); +extern __errno_t strcat_s(char *__restrict, rsize_t, const char *__restrict); +extern __errno_t strncpy_s(char *__restrict, rsize_t, const char *__restrict, + rsize_t); +extern __errno_t strncat_s(char *__restrict, rsize_t, const char *__restrict, + rsize_t); +extern size_t strnlen_s(const char *, size_t); +extern __errno_t strerror_s(char *, rsize_t, __errno_t); /* C11 */ +extern size_t strerrorlen_s(__errno_t); +#endif + #include _END_STD_C @@ -209,4 +229,4 @@ _END_STD_C #include #endif -#endif /* _STRING_H_ */ +#endif /* _STRING_H_ */ \ No newline at end of file diff --git a/newlib/libc/include/sys/_types.h b/newlib/libc/include/sys/_types.h index c38b7d1e60..d91b11fa1c 100644 --- a/newlib/libc/include/sys/_types.h +++ b/newlib/libc/include/sys/_types.h @@ -258,4 +258,21 @@ typedef unsigned short __nlink_t; typedef long __suseconds_t; /* microseconds (signed) */ typedef unsigned long __useconds_t; /* microseconds (unsigned) */ +#ifdef __STDC_WANT_LIB_EXT1__ +#if (__STDC_WANT_LIB_EXT1__ != 0) && (__STDC_WANT_LIB_EXT1__ != 1) +#error Please define __STDC_WANT_LIB_EXT__ as 0 or 1 +#endif + +#if __STDC_WANT_LIB_EXT1__ == 1 + +#ifndef __RSIZE_T +#define __RSIZE_T +typedef size_t __rsize_t; +#endif + +typedef int __errno_t; + +#endif +#endif + #endif /* _SYS__TYPES_H */ diff --git a/newlib/libc/include/sys/errno.h b/newlib/libc/include/sys/errno.h index 7b0d8d33a9..6556a35962 100644 --- a/newlib/libc/include/sys/errno.h +++ b/newlib/libc/include/sys/errno.h @@ -35,6 +35,7 @@ SUCH DAMAGE. #include #include +#include _BEGIN_STD_C diff --git a/newlib/libc/stdlib/CMakeLists.txt b/newlib/libc/stdlib/CMakeLists.txt index 523243ba5f..8df4955c05 100644 --- a/newlib/libc/stdlib/CMakeLists.txt +++ b/newlib/libc/stdlib/CMakeLists.txt @@ -115,6 +115,7 @@ picolibc_sources( pico-exit.c pico-onexit.c pico-cxa-atexit.c + set_constraint_handler_s.c ) picolibc_sources_flags("-fno-builtin-malloc;-fno-builtin-free" diff --git a/newlib/libc/stdlib/meson.build b/newlib/libc/stdlib/meson.build index 2c31fd2c9b..fffe4c8398 100644 --- a/newlib/libc/stdlib/meson.build +++ b/newlib/libc/stdlib/meson.build @@ -161,6 +161,7 @@ srcs_stdlib = [ 'wctob.c', 'wctomb.c', 'wctomb_r.c', + 'set_constraint_handler_s.c', ] srcs_stdlib_stdio = [ diff --git a/newlib/libc/stdlib/set_constraint_handler_s.c b/newlib/libc/stdlib/set_constraint_handler_s.c new file mode 100644 index 0000000000..7071cb7c50 --- /dev/null +++ b/newlib/libc/stdlib/set_constraint_handler_s.c @@ -0,0 +1,61 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __STDC_WANT_LIB_EXT1__ 1 +#include + +constraint_handler_t __cur_handler = abort_handler_s; + +void +abort_handler_s(const char *restrict msg, void *restrict ptr, __errno_t error) +{ + (void)msg; + (void)ptr; + (void)error; + abort(); +} + +constraint_handler_t +set_constraint_handler_s(constraint_handler_t handler) +{ + constraint_handler_t h = __cur_handler; + + if (handler == (constraint_handler_t)NULL) { + __cur_handler = abort_handler_s; // null restores to default handler + } else { + __cur_handler = handler; + } + + return h; +} diff --git a/newlib/libc/string/CMakeLists.txt b/newlib/libc/string/CMakeLists.txt index d31976e928..48ce38aa5c 100644 --- a/newlib/libc/string/CMakeLists.txt +++ b/newlib/libc/string/CMakeLists.txt @@ -135,4 +135,14 @@ picolibc_sources( wmempcpy.c wmemset.c xpg_strerror_r.c + memcpy_s.c + memmove_s.c + memset_s.c + strcat_s.c + strcpy_s.c + strerror_s.c + strerrorlen_s.c + strncat_s.c + strncpy_s.c + strnlen_s.c ) diff --git a/newlib/libc/string/memcpy_s.c b/newlib/libc/string/memcpy_s.c new file mode 100644 index 0000000000..1e04491e96 --- /dev/null +++ b/newlib/libc/string/memcpy_s.c @@ -0,0 +1,99 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +__errno_t +memcpy_s(void *restrict s1, rsize_t s1max, const void *restrict s2, rsize_t n) +{ + const char *msg = ""; + constraint_handler_t handler = NULL; + + if (s1 == NULL) { + msg = "memcpy_s: dest is NULL"; + goto handle_error; + } + + if (s1max > RSIZE_MAX) { + msg = "memcpy_s: buffer size exceeds RSIZE_MAX"; + goto handle_error; + } + + if (s2 == NULL) { + msg = "memcpy_s: source is NULL"; + goto handle_error; + } + + if (n > RSIZE_MAX) { + msg = "memcpy_s: copy count exceeds RSIZE_MAX"; + goto handle_error; + } + + if (n > s1max) { + msg = "memcpy_s: copy count exceeds buffer size"; + goto handle_error; + } + + const char *s1cp = (const char *)s1; + const char *s2cp = (const char *)s2; + const char *s1cp_limit = &s1cp[n]; + const char *s2cp_limit = &s2cp[n]; + + if (((s1cp_limit <= s2cp) || (s2cp_limit <= s1cp)) == false) { + msg = "memcpy_s: overlapping copy"; + goto handle_error; + } + + // Normal return path + (void)memcpy(s1, s2, n); + return 0; + +handle_error: + handler = set_constraint_handler_s(NULL); + (void)set_constraint_handler_s(handler); + + if (s1 != NULL) { + (void)memset(s1, (int32_t)'\0', s1max); + } + + if (handler != NULL) { + handler(msg, NULL, -1); + } + + return -1; +} diff --git a/newlib/libc/string/memmove_s.c b/newlib/libc/string/memmove_s.c new file mode 100644 index 0000000000..60699ee553 --- /dev/null +++ b/newlib/libc/string/memmove_s.c @@ -0,0 +1,91 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +__errno_t +memmove_s(void *s1, rsize_t s1max, const void *s2, rsize_t n) +{ + const char *msg = ""; + constraint_handler_t handler = NULL; + + if (s1 == NULL) { + msg = "memmove_s: dest is NULL"; + goto handle_error; + } + + if (s1max > RSIZE_MAX) { + msg = "memmove_s: buffer size exceeds RSIZE_MAX"; + goto handle_error; + } + + if (s2 == NULL) { + msg = "memmove_s: source is NULL"; + goto handle_error; + } + + if (n > RSIZE_MAX) { + msg = "memmove_s: copy count exceeds RSIZE_MAX"; + goto handle_error; + } + + if (n > s1max) { + msg = "memmove_s: copy count exceeds buffer size"; + goto handle_error; + } + + /* overlapping memory is allowed for memmove_s so no checks for that */ + + // Normal return path + (void)memmove(s1, s2, n); + return 0; + +handle_error: + handler = set_constraint_handler_s(NULL); + (void)set_constraint_handler_s(handler); + + if (s1 != NULL) { + (void)memset(s1, (int32_t)'\0', s1max); + } + + if (handler != NULL) { + handler(msg, NULL, -1); + } + + return -1; +} diff --git a/newlib/libc/string/memset_s.c b/newlib/libc/string/memset_s.c new file mode 100644 index 0000000000..79947f19f2 --- /dev/null +++ b/newlib/libc/string/memset_s.c @@ -0,0 +1,84 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +__errno_t +memset_s(void *s, rsize_t smax, int c, rsize_t n) +{ + const char *msg = ""; + constraint_handler_t handler = NULL; + + if (s == NULL) { + msg = "memset_s: dest is NULL"; + goto handle_error; + } + + if (smax > RSIZE_MAX) { + msg = "memset_s: buffer size exceeds RSIZE_MAX"; + goto handle_error; + } + + if (n > RSIZE_MAX) { + msg = "memset_s: count exceeds RSIZE_MAX"; + goto handle_error; + } + + if (n > smax) { + msg = "memset_s: count exceeds buffer size"; + goto handle_error; + } + + // Normal return path + (void)memset(s, c, n); + return 0; + +handle_error: + handler = set_constraint_handler_s(NULL); + (void)set_constraint_handler_s(handler); + + if (s != NULL) { + (void)memset(s, c, smax); + } + + if (handler != NULL) { + handler(msg, NULL, -1); + } + + return -1; +} diff --git a/newlib/libc/string/meson.build b/newlib/libc/string/meson.build index 9aac49ea23..e7e9f264ce 100644 --- a/newlib/libc/string/meson.build +++ b/newlib/libc/string/meson.build @@ -134,11 +134,22 @@ srcs_string = [ 'wmempcpy.c', 'wmemset.c', 'xpg_strerror_r.c', + 'memcpy_s.c', + 'memmove_s.c', + 'memset_s.c', + 'strcat_s.c', + 'strcpy_s.c', + 'strerror_s.c', + 'strerrorlen_s.c', + 'strncat_s.c', + 'strncpy_s.c', + 'strnlen_s.c', ] hdrs_string = [ 'local.h', 'str-two-way.h', + 'string_private.h', ] srcs_strcmp = [ diff --git a/newlib/libc/string/strcat_s.c b/newlib/libc/string/strcat_s.c new file mode 100644 index 0000000000..ce74e27f6a --- /dev/null +++ b/newlib/libc/string/strcat_s.c @@ -0,0 +1,147 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +__errno_t +strcat_s(char *restrict s1, rsize_t s1max, const char *restrict s2) +{ + const char *msg = ""; + size_t s1_len = 0; + bool write_null = true; + constraint_handler_t handler = NULL; + + if (s1 == NULL) { + msg = "strcat_s: dest is NULL"; + write_null = false; + goto handle_error; + } + + if (s1max == 0 || s1max > RSIZE_MAX) { + msg = "strcat_s: dest buffer size is 0 or exceeds RSIZE_MAX"; + write_null = false; + goto handle_error; + } + + if (s2 == NULL) { + msg = "strcat_s: source is NULL"; + goto handle_error; + } + + /* It is a constraint violation if s1max is not large enough to contain + * the concatenation s2: no truncation permitted. + * It is also a constraint violation if the string pointed to by s2 + * overlaps s1 in any way. + * The C11 Rationale says we are permitted to proceed with the copy and + * detect dest buffer overrun and overlapping memory blocks as a byproduct + * of performing the copy operation. This is to avoid calling strlen on + * s2 to detect these violations prior to attempting the copy. + */ + // compute chars available in s1 + s1_len = strnlen_s(s1, s1max); + if (s1_len == s1max) { + msg = "strcat_s: string 1 length exceeds buffer size"; + goto handle_error; + } + + const char *overlap_point; + bool check_s1_for_overlap; + unsigned m = s1max - s1_len; + char *s1cp = s1 + s1_len; + const char *s2cp = s2; + + if (s1 <= s2) { + // if we ever reach s2 when storing to s1 we have overlap + overlap_point = s2; + check_s1_for_overlap = true; + // make sure source does not lie within initial dest string. + if (s2 <= s1cp) { + msg = "strcat_s: overlapping copy"; + goto handle_error; + } + } else { + // if we ever reach s1 when reading from s2 we have overlap + overlap_point = s1; + check_s1_for_overlap = false; + // issue with checking initial dest string does not apply in this + // case, overlap will be detected only by hitting overlap_point. + } + + unsigned written = 0; + char c = '.'; + while (written < m) { + if (check_s1_for_overlap) { + if (s1cp == overlap_point) { + msg = "strcat_s: overlapping copy"; + goto handle_error; + } + } else if (s2cp == overlap_point) { + msg = "strcat_s: overlapping copy"; + goto handle_error; + } + + c = *s2cp++; + *s1cp++ = c; + written++; + if (c == '\0') { + break; + } + } + + if (c != '\0') { + msg = "strcat_s: dest buffer size insufficent to append string"; + goto handle_error; + } + + // Normal return path + return 0; + +handle_error: + handler = set_constraint_handler_s(NULL); + set_constraint_handler_s(handler); + + if (write_null && s1 != NULL) { + *s1 = '\0'; + } + + if (handler != NULL) { + handler(msg, NULL, -1); + } + + return -1; +} diff --git a/newlib/libc/string/strcpy_s.c b/newlib/libc/string/strcpy_s.c new file mode 100644 index 0000000000..d0c850804e --- /dev/null +++ b/newlib/libc/string/strcpy_s.c @@ -0,0 +1,130 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +__errno_t +strcpy_s(char *restrict s1, rsize_t s1max, const char *restrict s2) +{ + const char *msg = ""; + bool write_null = true; + constraint_handler_t handler = NULL; + + if (s1 == NULL) { + msg = "strcpy_s: dest is NULL"; + write_null = false; + goto handle_error; + } + + if (s1max == 0 || s1max > RSIZE_MAX) { + msg = "strcpy_s: dest buffer size is 0 or exceeds RSIZE_MAX"; + write_null = false; + goto handle_error; + } + + if (s2 == NULL) { + msg = "strcpy_s: source is NULL"; + goto handle_error; + } + + /* It is a constraint violation if s1max is not large enough to contain + * s2: no truncation permitted. + * It is also a constraint violation if the string pointed to by s2 + * overlaps s1 in any way. + * The C11 Rationale says we are permitted to proceed with the copy and + * detect dest buffer overrun and overlapping memory blocks as a byproduct + * of performing the copy operation. This is to avoid calling strlen on + * s2 to detect these violations prior to attempting the copy. + */ + const char *overlap_point; + bool check_s1_for_overlap; + char *s1cp = s1; + const char *s2cp = s2; + if (s1 < s2) { + // if we ever reach s2 when storing to s1 we have overlap + overlap_point = s2; + check_s1_for_overlap = true; + } else { + // if we ever reach s1 when reading from s2 we have overlap + overlap_point = s1; + check_s1_for_overlap = false; + } + + unsigned written = 0; + char c = '.'; + while (written < s1max) { + if (check_s1_for_overlap) { + if (s1cp == overlap_point) { + msg = "strcpy_s: overlapping copy"; + goto handle_error; + } + } else if (s2cp == overlap_point) { + msg = "strcpy_s: overlapping copy"; + goto handle_error; + } + + c = *s2cp++; + *s1cp++ = c; + written++; + if (c == '\0') { + break; + } + } + + if (c != '\0') { + msg = "strcpy_s: dest buffer size insufficent to copy string"; + goto handle_error; + } + + // Normal return path + return 0; + +handle_error: + handler = set_constraint_handler_s(NULL); + set_constraint_handler_s(handler); + + if (write_null && s1 != NULL) { + *s1 = '\0'; + } + + if (handler != NULL) { + handler(msg, NULL, -1); + } + + return -1; +} diff --git a/newlib/libc/string/strerror.c b/newlib/libc/string/strerror.c index 5788505b1b..9c3e38191d 100644 --- a/newlib/libc/string/strerror.c +++ b/newlib/libc/string/strerror.c @@ -400,6 +400,7 @@ QUICKREF #define _DEFAULT_SOURCE #include #include +#include "string_private.h" #include "local.h" extern char *_user_strerror (int, int, int *) _ATTRIBUTE((__weak__)); diff --git a/newlib/libc/string/strerror_s.c b/newlib/libc/string/strerror_s.c new file mode 100644 index 0000000000..f20f091f03 --- /dev/null +++ b/newlib/libc/string/strerror_s.c @@ -0,0 +1,91 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include +#include +#include "string_private.h" + +/* C11 version; required by LLVM's C++11 library */ +__errno_t +strerror_s(char *buf, rsize_t buflen, __errno_t errnum) +{ + int32_t result = 0; + const char *msg = ""; + constraint_handler_t handler = NULL; + + if (buf == NULL) { + msg = "strerror_s: dest is NULL"; + goto handle_error; + } + + if ((buflen == 0u) || (buflen > RSIZE_MAX)) { + msg = "strerror_s: dest buffer size is 0 or exceeds RSIZE_MAX"; + goto handle_error; + } + + const char *cp = _strerror_r(errnum, 0, NULL); + uint32_t len = strnlen_s(cp, MAX_ERROR_MSG); + + if (len < buflen) { + (void)strncpy(buf, cp, MAX_ERROR_MSG); + } else { + /* Standard allows truncation of error message with '...' to + indicate truncation. */ + (void)memcpy(buf, cp, (buflen - 1u)); + buf[(buflen - 1u)] = '\0'; + + if (buflen > 3u) { + (void)strncpy(&buf[(buflen - 4u)], "...", 4u); + } + + result = ERANGE; + } + + // Normal return path + return result; + +handle_error: + handler = set_constraint_handler_s(NULL); + (void)set_constraint_handler_s(handler); + + if (handler != NULL) { + handler(msg, NULL, -1); + } + + return -1; +} diff --git a/newlib/libc/string/strerrorlen_s.c b/newlib/libc/string/strerrorlen_s.c new file mode 100644 index 0000000000..b22215ccaf --- /dev/null +++ b/newlib/libc/string/strerrorlen_s.c @@ -0,0 +1,43 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include "string_private.h" + +size_t +strerrorlen_s(__errno_t errnum) +{ + return strnlen_s(_strerror_r(errnum, 0, NULL), MAX_ERROR_MSG); +} diff --git a/newlib/libc/string/string_private.h b/newlib/libc/string/string_private.h new file mode 100644 index 0000000000..4aaca7f8f8 --- /dev/null +++ b/newlib/libc/string/string_private.h @@ -0,0 +1,42 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + */ +#ifndef STRING_PRIVATE_H_ +#define STRING_PRIVATE_H_ + +#define MAX_ERROR_MSG 100 + +char *_strerror_r(int errnum, int internal, int *errptr); + +#endif //STRING_PRIVATE_H_ diff --git a/newlib/libc/string/strncat_s.c b/newlib/libc/string/strncat_s.c new file mode 100644 index 0000000000..5797a592b6 --- /dev/null +++ b/newlib/libc/string/strncat_s.c @@ -0,0 +1,174 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +__errno_t +strncat_s(char *restrict s1, rsize_t s1max, const char *restrict s2, rsize_t n) +{ + const char *msg = ""; + size_t s1_len = 0; + bool write_null = true; + constraint_handler_t handler = NULL; + + s1_len = strnlen_s(s1, s1max); + + if (s1 == NULL) { + msg = "strncat_s: dest is NULL"; + write_null = false; + goto handle_error; + } else if ((s1max == 0u) || (s1max > RSIZE_MAX)) { + msg = "strncat_s: dest buffer size is 0 or exceeds RSIZE_MAX"; + write_null = false; + goto handle_error; + } else if (s2 == NULL) { + msg = "strncat_s: source is NULL"; + goto handle_error; + } else if (n > RSIZE_MAX) { + msg = "strncat_s: copy count exceeds RSIZE_MAX"; + goto handle_error; + } + + /* It is a constraint violation if s1max is not large enough to contain + * the concatenation of s2. + * It is also a constraint violation if the string pointed to by s2 + * overlaps s1 in any way. + * The C11 Rationale says we are permitted to proceed with the copy and + * detect dest buffer overrun and overlapping memory blocks as a byproduct + * of performing the copy operation. This is to avoid calling strlen on + * s2 to detect these violations prior to attempting the copy. + */ + // compute chars available in s1 + + else if (s1_len == s1max) { + msg = "strncat_s: string 1 length exceeds buffer size"; + goto handle_error; + } else { + // compute chars available in s1 + uint32_t m = (s1max - s1_len); + uint32_t i = 0; + char *s1cp = s1; + + for (i = 0u; i < s1_len; i++) { + s1cp++; + } + + // Question; at this point should we just return + // strncpy_s(s1cp, m, s2, n) ? + // perhaps not since overlap check needs to be over entire s1 vs. s2? + + const char *overlap_point; + bool check_s1_for_overlap; + const char *s2cp = s2; + + if (s1 <= s2) { + // if we ever reach s2 when storing to s1 we have overlap + overlap_point = s2; + check_s1_for_overlap = true; + // make sure source does not lie within initial dest string. + if (s2 <= s1cp) { + msg = "strncat_s: overlapping copy"; + goto handle_error; + } + } else { + // if we ever reach s1 when reading from s2 we have overlap + overlap_point = s1; + check_s1_for_overlap = false; + } + + uint32_t written = 0; + char c = '.'; + + while ((written < m) && (written < n)) { + if (check_s1_for_overlap == true) { + if (s1cp == overlap_point) { + msg = "strncat_s: overlapping copy"; + goto handle_error; + } + } else if (s2cp == overlap_point) { + msg = "strncat_s: overlapping copy"; + goto handle_error; + } else { + /* Normal case*/ + } + + c = *s2cp; + s2cp++; + *s1cp = c; + s1cp++; + written++; + + if (c == '\0') { + break; + } + } + + if ((c != '\0') && (written == n) && (written < m)) { + // we copied n chars from s2 and there is room for null char in s1 + if ((check_s1_for_overlap == true) && (s1cp == overlap_point)) { + msg = "strncat_s: overlapping copy"; + goto handle_error; + } else { + c = '\0'; + *s1cp = '\0'; + } + } + + if (c != '\0') { + msg = "strncat_s: dest buffer size insufficent to copy string"; + goto handle_error; + } + } + + // Normal return path + return 0; + +handle_error: + handler = set_constraint_handler_s(NULL); + (void)set_constraint_handler_s(handler); + + if (write_null && s1 != NULL) { + *s1 = '\0'; + } + + if (handler != NULL) { + handler(msg, NULL, -1); + } + + return -1; +} diff --git a/newlib/libc/string/strncpy_s.c b/newlib/libc/string/strncpy_s.c new file mode 100644 index 0000000000..71bc08dff3 --- /dev/null +++ b/newlib/libc/string/strncpy_s.c @@ -0,0 +1,152 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +__errno_t +strncpy_s(char *restrict s1, rsize_t s1max, const char *restrict s2, rsize_t n) +{ + const char *msg = ""; + bool write_null = true; + constraint_handler_t handler = NULL; + + if (s1 == NULL) { + msg = "strncpy_s: dest is NULL"; + write_null = false; + goto handle_error; + } else if ((s1max == 0u) || (s1max > RSIZE_MAX)) { + msg = "strncpy_s: dest buffer size is 0 or exceeds RSIZE_MAX"; + write_null = false; + goto handle_error; + } + + else if (s2 == NULL) { + msg = "strncpy_s: source is NULL"; + goto handle_error; + } else if (n > RSIZE_MAX) { + msg = "strncpy_s: copy count exceeds RSIZE_MAX"; + goto handle_error; + } + + /* It is a constraint violation if s1max is not large enough to contain + * a copy of s2 (with n as upper bound on chars copied). + * It is also a constraint violation if the string pointed to by s2 + * overlaps s1 in any way. + * The C11 Rationale says we are permitted to proceed with the copy and + * detect dest buffer overrun and overlapping memory blocks as a byproduct + * of performing the copy operation. This is to avoid calling strlen on + * s2 to detect these violations prior to attempting the copy. + */ + + else { + const char *overlap_point; + bool check_s1_for_overlap; + char *s1cp = s1; + const char *s2cp = s2; + + if (s1 < s2) { + // if we ever reach s2 when storing to s1 we have overlap + overlap_point = s2; + check_s1_for_overlap = true; + } else { + // if we ever reach s1 when reading from s2 we have overlap + overlap_point = s1; + check_s1_for_overlap = false; + } + + uint32_t written = 0; + char c = '.'; + + while ((written < s1max) && (written < n)) { + if (check_s1_for_overlap == true) { + if (s1cp == overlap_point) { + msg = "strncpy_s: overlapping copy"; + goto handle_error; + } + } else if (s2cp == overlap_point) { + msg = "strncpy_s: overlapping copy"; + goto handle_error; + } else { + /* Normal case*/ + } + + c = *s2cp; + s2cp++; + *s1cp = c; + s1cp++; + written++; + + if (c == '\0') { + break; + } + } + + if ((c != '\0') && (written == n) && (written < s1max)) { + // we copied n chars from s2 and there is room for null char in s1 + if ((check_s1_for_overlap == true) && (s1cp == overlap_point)) { + msg = "strncpy_s: overlapping copy"; + goto handle_error; + } else { + c = '\0'; + *s1cp = '\0'; + } + } + + if (c != '\0') { + msg = "strncpy_s: dest buffer size insufficent to copy string"; + goto handle_error; + } + } + + // Normal return path + return 0; + +handle_error: + handler = set_constraint_handler_s(NULL); + (void)set_constraint_handler_s(handler); + + if (write_null && s1 != NULL) { + *s1 = '\0'; + } + + if (handler != NULL) { + handler(msg, NULL, -1); + } + + return -1; +} diff --git a/newlib/libc/string/strnlen_s.c b/newlib/libc/string/strnlen_s.c new file mode 100644 index 0000000000..a162cc4625 --- /dev/null +++ b/newlib/libc/string/strnlen_s.c @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __STDC_WANT_LIB_EXT1__ 1 +#include + +size_t +strnlen_s(const char *s, size_t maxsize) +{ + const void *s_end; + size_t rtn = 0; + + if (s == NULL) { + rtn = 0; + } else { + s_end = memchr((const void *)s, (int)'\0', maxsize); + + if (s_end == NULL) { + rtn = maxsize; + } else { + int s_size; + s_size = s_end - (const void *)s; + rtn = (size_t)s_size; + } + } + + return rtn; +} diff --git a/newlib/libc/tinystdio/CMakeLists.txt b/newlib/libc/tinystdio/CMakeLists.txt index 71f6318d16..97077ac6c5 100644 --- a/newlib/libc/tinystdio/CMakeLists.txt +++ b/newlib/libc/tinystdio/CMakeLists.txt @@ -166,6 +166,7 @@ picolibc_sources( vwscanf.c wprintf.c wscanf.c + sprintf_s.c ) picolibc_sources( diff --git a/newlib/libc/tinystdio/meson.build b/newlib/libc/tinystdio/meson.build index 8c5c8b40de..0f45fe0ec2 100644 --- a/newlib/libc/tinystdio/meson.build +++ b/newlib/libc/tinystdio/meson.build @@ -169,6 +169,7 @@ srcs_tinystdio = [ 'vwscanf.c', 'wprintf.c', 'wscanf.c', + 'sprintf_s.c', ] # exact float/string conversion code diff --git a/newlib/libc/tinystdio/sprintf_s.c b/newlib/libc/tinystdio/sprintf_s.c new file mode 100644 index 0000000000..9c8434186d --- /dev/null +++ b/newlib/libc/tinystdio/sprintf_s.c @@ -0,0 +1,152 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __STDC_WANT_LIB_EXT1__ 1 +#include "stdio_private.h" +#include +#include +#include +#include +#include + +int +sprintf_s(char *restrict s, rsize_t bufsize, const char *restrict fmt, ...) +{ + bool write_null = true; + const char *msg = ""; + va_list args; + int rc; + constraint_handler_t handler = NULL; + + if (s == NULL) { + write_null = false; + msg = "sprintf_s: dest buffer is null"; + goto handle_error; + } else if (bufsize == 0 || bufsize > RSIZE_MAX) { + write_null = false; + msg = "sprintf_s: invalid buffer size"; + goto handle_error; + } else if (fmt == NULL) { + msg = "sprintf_s: null format string"; + goto handle_error; + } else if (strstr(fmt, " %n") != NULL) { + msg = "sprintf_s: format string contains percent-n"; + goto handle_error; + } else { + va_start(args, fmt); + + va_list args_copy; + va_copy(args_copy, args); + + const char *check_ptr = fmt; + uint8_t null_str = 0; + while (*check_ptr && null_str == 0) { + if (check_ptr[0] == '%') { + switch (check_ptr[1]) { + case 's': { + char *str_arg = va_arg(args_copy, char *); + if (str_arg == NULL) { + msg = "sprintf_s: null string argument"; + va_end(args_copy); + va_end(args); + null_str = 1; + goto handle_error; + } + break; + } + case 'd': + case 'i': + case 'u': + case 'o': + case 'x': + case 'X': + case 'c': + case 'h': + case 'l': + case 'L': + case 'z': + case 't': + va_arg(args_copy, int); + break; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'a': + case 'A': + va_arg(args_copy, double); + break; + case 'p': + va_arg(args_copy, void *); + break; + default: + break; + } + } + check_ptr++; + } + + rc = vsnprintf(s, bufsize, fmt, args); + va_end(args_copy); + va_end(args); + } + + if (rc < 0 || rc >= (int)bufsize) { + msg = "sprintf_s: dest buffer overflow"; + goto handle_error; + } else { + s[rc] = 0; + } + + // Normal return path + return rc; + +handle_error: + handler = set_constraint_handler_s(NULL); + (void)set_constraint_handler_s(handler); + + if (handler != NULL) { + handler(msg, NULL, -1); + } + + rc = 0; /* standard stipulates this */ + + if (write_null && s != NULL) { + s[0] = '\0'; /* again, standard requires this */ + } + + return rc; +} \ No newline at end of file diff --git a/newlib/libc/tinystdio/stdio.h b/newlib/libc/tinystdio/stdio.h index 0b2c92e2db..4171191bd0 100644 --- a/newlib/libc/tinystdio/stdio.h +++ b/newlib/libc/tinystdio/stdio.h @@ -375,6 +375,15 @@ int putchar_unlocked (int); #define putchar_unlocked(c, f) fgetc(c, stdin) #endif +#if __STDC_WANT_LIB_EXT1__ == 1 +#include + +typedef __rsize_t rsize_t; + +extern int sprintf_s(char *__restrict __s, rsize_t __bufsize, + const char *__restrict __format, ...); +#endif + /* * The format of tmpnam names is TXXXXXX, which works with mktemp */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index da55c79760..3fc61f4594 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -61,6 +61,17 @@ set(tests test-sprintf-percent-n malloc_stress posix-io + test-memcpy_s + test-memset_s + test-memmove_s + test-strcat_s + test-strcpy_s + test-strerror_s + test-strerrorlen_s + test-strncat_s + test-strncpy_s + test-strnlen_s + test-sprintf_s ) set(tests_fail diff --git a/test/meson.build b/test/meson.build index 8ddd9666a2..b8c0ecb9c1 100644 --- a/test/meson.build +++ b/test/meson.build @@ -583,6 +583,71 @@ foreach target : targets timeout: 60, env: test_env) + plain_tests = ['rand', 'regex', 'ungetc', 'fenv', + 'malloc', 'tls', + 'ffs', 'setjmp', 'atexit', 'on_exit', + 'math-funcs', 'timegm', 'time-tests', + 'test-strtod', 'test-strchr', + 'test-memset', 'test-put', + 'test-efcvt', 'test-atomic', + 'test-raise', + 'test-fma', + 'test-funopen', + ] + + if have_attr_ctor_dtor + plain_tests += 'constructor' + endif + + if have_complex + plain_tests += 'complex-funcs' + endif + + if newlib_nano_malloc or tests_enable_full_malloc_stress + plain_tests += 'malloc_stress' + endif + + if tinystdio + plain_tests += 't_fmemopen' + endif + + if (posix_io or not tinystdio) and tests_enable_posix_io + plain_tests += ['posix-io'] + + # legacy stdio doesn't work on semihosting, so just skip it + if tinystdio + plain_tests += ['test-fopen', + 'test-mktemp', + 'test-tmpnam', + 'test-fread-fwrite', + 'test-ungetc-ftell', + 'test-fgetc', + 'test-fgets-eof', + ] + endif + endif + + if tests_enable_stack_protector + plain_tests += 'stack-smash' + endif + + plain_tests += ['test-memcpy_s', + 'test-memset_s', + 'test-memmove_s', + 'test-strcat_s', + 'test-strcpy_s', + 'test-strerror_s', + 'test-strerrorlen_s', + 'test-strncat_s', + 'test-strncpy_s', + 'test-strnlen_s', + ] + + if tinystdio + plain_tests += 'test-sprintf_s' + endif + + foreach t1 : plain_tests t1_src = t1 + '.c' if target == '' diff --git a/test/test-memcpy_s.c b/test/test-memcpy_s.c new file mode 100644 index 0000000000..1c97e49e8b --- /dev/null +++ b/test/test-memcpy_s.c @@ -0,0 +1,155 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +#define MAX_ERROR_MSG 100 + +void custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error); +int test_handler_called(int handler_called, char *expected_msg, int test_id); + +char handler_msg[MAX_ERROR_MSG] = ""; + +void +custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error) +{ + (void)ptr; + (void)error; + strcpy(handler_msg, msg); +} + +#define TEST_RES(cond, msg, handler_res, test_id) \ + if ((!(cond)) || (handler_res == 1)) { \ + printf("Test %d Failed: %s\n", test_id, msg); \ + return 1; \ + } else { \ + printf("Test %d Passed: %s\n", test_id, msg); \ + } + +int +test_handler_called(int handler_called, char *expected_msg, int test_id) +{ + int ret = 0; + if (handler_called == 0) { + (void)expected_msg; + if (handler_msg[0] != '\0') { + printf( + "ERROR: Custom constraint handler called without error detiction!\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } + } else { + if (handler_msg[0] == '\0') { + (void)expected_msg; + printf("ERROR: Custom constraint handler not called\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + if (strcmp(expected_msg, handler_msg) != 0) { + printf( + "ERROR: Custom constraint handler called with incorrect msg: %s\n", + handler_msg); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + (void)expected_msg; + printf( + "Custom constraint handler called with correct msg: %s\n", + handler_msg); + handler_msg[0] = '\0'; + ret = 0; + } + } + } + return ret; +} + +int +main(void) +{ + char src[] = "Hello, world!"; + char dest[50]; + int test_id = 0; + int handler_res = 0; + __errno_t res; + + set_constraint_handler_s(custom_constraint_handler); + + // Test case 1: Normal copy + test_id++; + res = memcpy_s(dest, sizeof(dest), src, strlen(src) + 1); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Normal Copy", handler_res, test_id); + TEST_RES(strcmp(dest, "Hello, world!") == 0, "Normal Copy Contents", + handler_res, test_id); + + // Test case 2: Copy with insufficient destination size + test_id++; + res = memcpy_s(dest, 5, src, strlen(src) + 1); + handler_res = test_handler_called( + 1, "memcpy_s: copy count exceeds buffer size", test_id); + TEST_RES(res != 0, "Copy with insufficient destination size", handler_res, + test_id); + + // Test case 3: Copy with Null destination + test_id++; + res = memcpy_s(NULL, sizeof(dest), src, strlen(src) + 1); + handler_res = test_handler_called(1, "memcpy_s: dest is NULL", test_id); + TEST_RES(res != 0, "Copy with Null destination", handler_res, test_id); + + // Test case 4: Copy with Null source + test_id++; + res = memcpy_s(dest, sizeof(dest), NULL, strlen(src) + 1); + handler_res = test_handler_called(1, "memcpy_s: source is NULL", test_id); + TEST_RES(res != 0, "Copy with Null source", handler_res, test_id); + + // Test case 5: Copy with zero length + test_id++; + strcpy(dest, ""); + res = memcpy_s(dest, sizeof(dest), src, 0); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Copy with zero length", handler_res, test_id); + TEST_RES(dest[0] == '\0', "Copy with zero length Contents", handler_res, + test_id); + + printf("All memcpy_s tests passed!\n"); + return 0; +} \ No newline at end of file diff --git a/test/test-memmove_s.c b/test/test-memmove_s.c new file mode 100644 index 0000000000..e4278f8f87 --- /dev/null +++ b/test/test-memmove_s.c @@ -0,0 +1,154 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +#define MAX_ERROR_MSG 100 + +void custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error); +int test_handler_called(int handler_called, char *expected_msg, int test_id); + +char handler_msg[MAX_ERROR_MSG] = ""; + +void +custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error) +{ + (void)ptr; + (void)error; + strcpy(handler_msg, msg); +} + +#define TEST_RES(cond, msg, handler_res, test_id) \ + if ((!(cond)) || (handler_res == 1)) { \ + printf("Test %d Failed: %s\n", test_id, msg); \ + return 1; \ + } else { \ + printf("Test %d Passed: %s\n", test_id, msg); \ + } + +int +test_handler_called(int handler_called, char *expected_msg, int test_id) +{ + int ret = 0; + if (handler_called == 0) { + (void)expected_msg; + if (handler_msg[0] != '\0') { + printf( + "ERROR: Custom constraint handler called without error detiction!\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } + } else { + if (handler_msg[0] == '\0') { + (void)expected_msg; + printf("ERROR: Custom constraint handler not called\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + if (strcmp(expected_msg, handler_msg) != 0) { + printf( + "ERROR: Custom constraint handler called with incorrect msg: %s\n", + handler_msg); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + (void)expected_msg; + printf( + "Custom constraint handler called with correct msg: %s\n", + handler_msg); + handler_msg[0] = '\0'; + ret = 0; + } + } + } + return ret; +} + +int +main(void) +{ + char buf[50] = "Hello, world!"; + int test_id = 0; + int handler_res = 0; + __errno_t res; + + set_constraint_handler_s(custom_constraint_handler); + + // Test case 1: Normal move + test_id++; + res = memmove_s(buf + 7, sizeof(buf) - 7, buf, strlen(buf) + 1); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Normal move", handler_res, test_id); + TEST_RES(strcmp(buf, "Hello, Hello, world!") == 0, "Normal move Contents", + handler_res, test_id); + + // Test case 2: Move with insufficient destination size + test_id++; + res = memmove_s(buf + 7, 5, buf, strlen(buf) + 1); + handler_res = test_handler_called( + 1, "memmove_s: copy count exceeds buffer size", test_id); + TEST_RES(res != 0, "Move with insufficient destination size", handler_res, + test_id); + + // Test case 3: Move with Null destination + test_id++; + res = memmove_s(NULL, sizeof(buf), buf, strlen(buf) + 1); + handler_res = test_handler_called(1, "memmove_s: dest is NULL", test_id); + TEST_RES(res != 0, "Move with Null destination", handler_res, test_id); + + // Test case 4: Move with Null source + test_id++; + res = memmove_s(buf, sizeof(buf), NULL, strlen(buf) + 1); + handler_res = test_handler_called(1, "memmove_s: source is NULL", test_id); + TEST_RES(res != 0, "Move with Null source", handler_res, test_id); + + // Test case 5: Move with zero length + test_id++; + strcpy(buf, ""); + res = memmove_s(buf, sizeof(buf), buf, 0); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Move with zero length", handler_res, test_id); + TEST_RES(buf[0] == '\0', "Move with zero length Contents", handler_res, + test_id); + + printf("All memmove_s tests passed!\n"); + return 0; +} \ No newline at end of file diff --git a/test/test-memset_s.c b/test/test-memset_s.c new file mode 100644 index 0000000000..20431c26ac --- /dev/null +++ b/test/test-memset_s.c @@ -0,0 +1,146 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +#define MAX_ERROR_MSG 100 + +void custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error); +int test_handler_called(int handler_called, char *expected_msg, int test_id); + +char handler_msg[MAX_ERROR_MSG] = ""; + +void +custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error) +{ + (void)ptr; + (void)error; + strcpy(handler_msg, msg); +} + +#define TEST_RES(cond, msg, handler_res, test_id) \ + if ((!(cond)) || (handler_res == 1)) { \ + printf("Test %d Failed: %s\n", test_id, msg); \ + return 1; \ + } else { \ + printf("Test %d Passed: %s\n", test_id, msg); \ + } + +int +test_handler_called(int handler_called, char *expected_msg, int test_id) +{ + int ret = 0; + if (handler_called == 0) { + (void)expected_msg; + if (handler_msg[0] != '\0') { + printf( + "ERROR: Custom constraint handler called without error detiction!\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } + } else { + if (handler_msg[0] == '\0') { + (void)expected_msg; + printf("ERROR: Custom constraint handler not called\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + if (strcmp(expected_msg, handler_msg) != 0) { + printf( + "ERROR: Custom constraint handler called with incorrect msg: %s\n", + handler_msg); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + (void)expected_msg; + printf( + "Custom constraint handler called with correct msg: %s\n", + handler_msg); + handler_msg[0] = '\0'; + ret = 0; + } + } + } + return ret; +} + +int +main(void) +{ + char buf[50] = "Hello, world!"; + int test_id = 0; + int handler_res = 0; + __errno_t res; + + set_constraint_handler_s(custom_constraint_handler); + + // Test case 1: Normal Set + test_id++; + res = memset_s(buf, sizeof(buf), 'A', strlen("Hello, world!")); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Normal Set", handler_res, test_id); + TEST_RES(strcmp(buf, "AAAAAAAAAAAAA") == 0, "Normal Set Contents", + handler_res, test_id); + + // Test case 2: Zero-length Set + test_id++; + res = memset_s(buf, sizeof(buf), 'B', 0); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Zero-length Set", handler_res, test_id); + TEST_RES(strcmp(buf, "AAAAAAAAAAAAA") == 0, "Zero-length Set Contents", + handler_res, test_id); + + // Test case 3: Null pointers + test_id++; + res = memset_s(NULL, sizeof(buf), 'C', strlen("Hello, world!")); + handler_res = test_handler_called(1, "memset_s: dest is NULL", test_id); + TEST_RES(res != 0, "NULL Destination Pointer", handler_res, test_id); + + // Test case 4: Set with zero buffer size + test_id++; + res = memset_s(buf, 0, 'D', strlen("Hello, world!")); + handler_res = + test_handler_called(1, "memset_s: count exceeds buffer size", test_id); + TEST_RES(res != 0, "Set with zero buffer size", handler_res, test_id); + + printf("All memset_s tests passed!\n"); + return 0; +} \ No newline at end of file diff --git a/test/test-sprintf_s.c b/test/test-sprintf_s.c new file mode 100644 index 0000000000..c97cb0d4c1 --- /dev/null +++ b/test/test-sprintf_s.c @@ -0,0 +1,156 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +#define MAX_ERROR_MSG 100 + +void custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error); +int test_handler_called(int handler_called, char *expected_msg, int test_id); + +char handler_msg[MAX_ERROR_MSG] = ""; + +void +custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error) +{ + (void)ptr; + (void)error; + strcpy(handler_msg, msg); +} + +#define TEST_RES(cond, msg, handler_res, test_id) \ + if ((!(cond)) || (handler_res == 1)) { \ + printf("Test %d Failed: %s\n", test_id, msg); \ + return 1; \ + } else { \ + printf("Test %d Passed: %s\n", test_id, msg); \ + } + +int +test_handler_called(int handler_called, char *expected_msg, int test_id) +{ + int ret = 0; + if (handler_called == 0) { + (void)expected_msg; + if (handler_msg[0] != '\0') { + printf( + "ERROR: Custom constraint handler called without error detiction!\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } + } else { + if (handler_msg[0] == '\0') { + (void)expected_msg; + printf("ERROR: Custom constraint handler not called\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + if (strcmp(expected_msg, handler_msg) != 0) { + printf( + "ERROR: Custom constraint handler called with incorrect msg: %s\n", + handler_msg); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + (void)expected_msg; + printf( + "Custom constraint handler called with correct msg: %s\n", + handler_msg); + handler_msg[0] = '\0'; + ret = 0; + } + } + } + return ret; +} + +int +main(void) +{ + char buf[50]; + int test_id = 0; + int handler_res = 0; + __errno_t res; + + set_constraint_handler_s(custom_constraint_handler); + + // Test case 1: Normal formatting + test_id++; + res = sprintf_s(buf, sizeof(buf), "Hello, %s!", "world"); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == (int)strlen("Hello, world!"), "Normal formatting", + handler_res, test_id); + TEST_RES(strcmp(buf, "Hello, world!") == 0, "Normal formatting Contents", + handler_res, test_id); + + // Test case 2: Formatting with buffer overflow + test_id++; + res = sprintf_s(buf, 10, "Hello, %s!", "world"); + handler_res = + test_handler_called(1, "sprintf_s: dest buffer overflow", test_id); + TEST_RES(res == 0, "Formatting with buffer overflow", handler_res, test_id); + + // Test case 3: Formatting with Null buffer + test_id++; + res = sprintf_s(NULL, sizeof(buf), "Hello, %s!", "world"); + handler_res = + test_handler_called(1, "sprintf_s: dest buffer is null", test_id); + TEST_RES(res == 0, "Formatting with Null buffer", handler_res, test_id); + + // Test case 4: Formatting with Null format string + test_id++; + res = sprintf_s(buf, sizeof(buf), NULL, "world"); + handler_res = + test_handler_called(1, "sprintf_s: null format string", test_id); + TEST_RES(res == 0, "Formatting with Null format string", handler_res, + test_id); + + // Test case 5: Empty format string + test_id++; + res = sprintf_s(buf, sizeof(buf), "", "world"); + TEST_RES(res == 0, "Empty format string", handler_res, test_id); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(strcmp(buf, "") == 0, "Empty format string Contents", handler_res, + test_id); + + printf("All sprintf_s tests passed!\n"); + return 0; +} \ No newline at end of file diff --git a/test/test-strcat_s.c b/test/test-strcat_s.c new file mode 100644 index 0000000000..40b4e23605 --- /dev/null +++ b/test/test-strcat_s.c @@ -0,0 +1,165 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +#define MAX_ERROR_MSG 100 + +void custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error); +int test_handler_called(int handler_called, char *expected_msg, int test_id); + +char handler_msg[MAX_ERROR_MSG] = ""; + +void +custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error) +{ + (void)ptr; + (void)error; + strcpy(handler_msg, msg); +} + +#define TEST_RES(cond, msg, handler_res, test_id) \ + if ((!(cond)) || (handler_res == 1)) { \ + printf("Test %d Failed: %s\n", test_id, msg); \ + return 1; \ + } else { \ + printf("Test %d Passed: %s\n", test_id, msg); \ + } + +int +test_handler_called(int handler_called, char *expected_msg, int test_id) +{ + int ret = 0; + if (handler_called == 0) { + (void)expected_msg; + if (handler_msg[0] != '\0') { + printf( + "ERROR: Custom constraint handler called without error detiction!\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } + } else { + if (handler_msg[0] == '\0') { + (void)expected_msg; + printf("ERROR: Custom constraint handler not called\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + if (strcmp(expected_msg, handler_msg) != 0) { + printf( + "ERROR: Custom constraint handler called with incorrect msg: %s\n", + handler_msg); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + (void)expected_msg; + printf( + "Custom constraint handler called with correct msg: %s\n", + handler_msg); + handler_msg[0] = '\0'; + ret = 0; + } + } + } + return ret; +} + +int +main(void) +{ + char dest[50] = "Hello"; + char src[] = ", world!"; + int test_id = 0; + int handler_res = 0; + __errno_t res; + + set_constraint_handler_s(custom_constraint_handler); + + // Test case 1: Normal Concatenation + test_id++; + res = strcat_s(dest, sizeof(dest), src); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Normal Concatenation", handler_res, test_id); + TEST_RES(strcmp(dest, "Hello, world!") == 0, + "Normal Concatenation Contents", handler_res, test_id); + + // Test case 2: Concatenation with insufficient buffer + test_id++; + res = strcat_s(dest, 10, src); + handler_res = test_handler_called( + 1, "strcat_s: string 1 length exceeds buffer size", test_id); + TEST_RES(res != 0, "Concatenation with insufficient buffer", handler_res, + test_id); + + // Test case 3: Null pointers + test_id++; + res = strcat_s(NULL, sizeof(dest), src); + handler_res = test_handler_called(1, "strcat_s: dest is NULL", test_id); + TEST_RES(res != 0, "NULL Destination Pointer", handler_res, test_id); + res = strcat_s(dest, sizeof(dest), NULL); + handler_res = test_handler_called(1, "strcat_s: source is NULL", test_id); + TEST_RES(res != 0, "NULL Source Pointer", handler_res, test_id); + + // Test case 4: Concatenation of empty source string + test_id++; + strcpy(dest, "Hello"); + res = strcat_s(dest, sizeof(dest), ""); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Concatenation of empty source string", handler_res, + test_id); + TEST_RES(strcmp(dest, "Hello") == 0, + "Concatenation of empty source string Contents", handler_res, + test_id); + + // Test case 5: Concatenation with empty destination string + test_id++; + char dest2[50]; + res = strcat_s(dest2, sizeof(dest2), ", World!"); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Concatenation of non-empty source to empty destination", + handler_res, test_id); + TEST_RES(strcmp(dest2, ", World!") == 0, + "Concatenation of non-empty source to empty destination Contents", + handler_res, test_id); + + printf("All strcat_s tests passed!\n"); + return 0; +} \ No newline at end of file diff --git a/test/test-strcpy_s.c b/test/test-strcpy_s.c new file mode 100644 index 0000000000..6ec89429da --- /dev/null +++ b/test/test-strcpy_s.c @@ -0,0 +1,159 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +#define MAX_ERROR_MSG 100 + +void custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error); +int test_handler_called(int handler_called, char *expected_msg, int test_id); + +char handler_msg[MAX_ERROR_MSG] = ""; + +void +custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error) +{ + (void)ptr; + (void)error; + strcpy(handler_msg, msg); +} + +#define TEST_RES(cond, msg, handler_res, test_id) \ + if ((!(cond)) || (handler_res == 1)) { \ + printf("Test %d Failed: %s\n", test_id, msg); \ + return 1; \ + } else { \ + printf("Test %d Passed: %s\n", test_id, msg); \ + } + +int +test_handler_called(int handler_called, char *expected_msg, int test_id) +{ + int ret = 0; + if (handler_called == 0) { + (void)expected_msg; + if (handler_msg[0] != '\0') { + printf( + "ERROR: Custom constraint handler called without error detiction!\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } + } else { + if (handler_msg[0] == '\0') { + (void)expected_msg; + printf("ERROR: Custom constraint handler not called\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + if (strcmp(expected_msg, handler_msg) != 0) { + printf( + "ERROR: Custom constraint handler called with incorrect msg: %s\n", + handler_msg); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + (void)expected_msg; + printf( + "Custom constraint handler called with correct msg: %s\n", + handler_msg); + handler_msg[0] = '\0'; + ret = 0; + } + } + } + return ret; +} + +int +main(void) +{ + char dest[50]; + const char *src = "Hello, world!"; + int test_id = 0; + int handler_res = 0; + __errno_t res; + + set_constraint_handler_s(custom_constraint_handler); + + // Test case 1: Normal copy + test_id++; + res = strcpy_s(dest, sizeof(dest), src); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Normal Copy", handler_res, test_id); + TEST_RES(strcmp(dest, "Hello, world!") == 0, "Normal Copy Contents", + handler_res, test_id); + + // Test case 2: Copy with insufficient buffer + test_id++; + res = strcpy_s(dest, 5, src); + handler_res = test_handler_called( + 1, "strcpy_s: dest buffer size insufficent to copy string", test_id); + TEST_RES(res != 0, "Copy with insufficient buffer", handler_res, test_id); + + // Test case 3: Null pointers + test_id++; + res = strcpy_s(NULL, sizeof(dest), src); + handler_res = test_handler_called(1, "strcpy_s: dest is NULL", test_id); + TEST_RES(res != 0, "NULL Destination Pointer", handler_res, test_id); + res = strcpy_s(dest, sizeof(dest), NULL); + handler_res = test_handler_called(1, "strcpy_s: source is NULL", test_id); + TEST_RES(res != 0, "NULL Source Pointer", handler_res, test_id); + + // Test case 4: Copy of empty string + test_id++; + res = strcpy_s(dest, sizeof(dest), ""); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Copy of empty string", handler_res, test_id); + TEST_RES(strcmp(dest, "") == 0, "Copy of empty string Contents", + handler_res, test_id); + + // Test case 5: Copy to empty buffer + test_id++; + char buf2[50]; + res = strcpy_s(buf2, sizeof(buf2), "world"); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Copy to empty buffer", handler_res, test_id); + TEST_RES(strcmp(buf2, "world") == 0, "Copy to empty buffer Contents", + handler_res, test_id); + + printf("All strcpy_s tests passed!\n"); + return 0; +} \ No newline at end of file diff --git a/test/test-strerror_s.c b/test/test-strerror_s.c new file mode 100644 index 0000000000..e45dc3260f --- /dev/null +++ b/test/test-strerror_s.c @@ -0,0 +1,150 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +#define MAX_ERROR_MSG 100 + +void custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error); +int test_handler_called(int handler_called, char *expected_msg, int test_id); + +char handler_msg[MAX_ERROR_MSG] = ""; + +void +custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error) +{ + (void)ptr; + (void)error; + strcpy(handler_msg, msg); +} + +#define TEST_RES(cond, msg, handler_res, test_id) \ + if ((!(cond)) || (handler_res == 1)) { \ + printf("Test %d Failed: %s\n", test_id, msg); \ + return 1; \ + } else { \ + printf("Test %d Passed: %s\n", test_id, msg); \ + } + +int +test_handler_called(int handler_called, char *expected_msg, int test_id) +{ + int ret = 0; + if (handler_called == 0) { + (void)expected_msg; + if (handler_msg[0] != '\0') { + printf( + "ERROR: Custom constraint handler called without error detiction!\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } + } else { + if (handler_msg[0] == '\0') { + (void)expected_msg; + printf("ERROR: Custom constraint handler not called\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + if (strcmp(expected_msg, handler_msg) != 0) { + printf( + "ERROR: Custom constraint handler called with incorrect msg: %s\n", + handler_msg); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + (void)expected_msg; + printf( + "Custom constraint handler called with correct msg: %s\n", + handler_msg); + handler_msg[0] = '\0'; + ret = 0; + } + } + } + return ret; +} + +int +main(void) +{ + char buf[100]; + int test_id = 0; + int handler_res = 0; + __errno_t res; + + set_constraint_handler_s(custom_constraint_handler); + + // Test case 1: Normal error message + test_id++; + res = strerror_s(buf, sizeof(buf), EINVAL); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Normal error message", handler_res, test_id); + TEST_RES(strcmp(buf, "Invalid argument") == 0, + "Normal error message Contents", handler_res, test_id); + + // Test case 2: Buffer too small + test_id++; + res = strerror_s(buf, 10, EINVAL); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == ERANGE, "Buffer too small", handler_res, test_id); + + // Test case 3: Null Destination Pointer + test_id++; + res = strerror_s(NULL, sizeof(buf), EINVAL); + handler_res = test_handler_called(1, "strerror_s: dest is NULL", test_id); + TEST_RES(res != 0, "Null Destination Pointer", handler_res, test_id); + + // Test case 4: Zero-length Buffer + test_id++; + res = strerror_s(buf, 0, EINVAL); + handler_res = test_handler_called( + 1, "strerror_s: dest buffer size is 0 or exceeds RSIZE_MAX", test_id); + TEST_RES(res != 0, "Zero-length Buffer", handler_res, test_id); + + // Test case 5: Unknown error code + test_id++; + res = strerror_s(buf, sizeof(buf), 12345); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Unknown error code", handler_res, test_id); + + printf("All strerror_s tests passed!\n"); + return 0; +} \ No newline at end of file diff --git a/test/test-strerrorlen_s.c b/test/test-strerrorlen_s.c new file mode 100644 index 0000000000..37fab17a21 --- /dev/null +++ b/test/test-strerrorlen_s.c @@ -0,0 +1,129 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +#define MAX_ERROR_MSG 100 + +void custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error); +int test_handler_called(int handler_called, char *expected_msg, int test_id); + +char handler_msg[MAX_ERROR_MSG] = ""; + +void +custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error) +{ + (void)ptr; + (void)error; + strcpy(handler_msg, msg); +} + +#define TEST_RES(cond, msg, handler_res, test_id) \ + if ((!(cond)) || (handler_res == 1)) { \ + printf("Test %d Failed: %s\n", test_id, msg); \ + return 1; \ + } else { \ + printf("Test %d Passed: %s\n", test_id, msg); \ + } + +int +test_handler_called(int handler_called, char *expected_msg, int test_id) +{ + int ret = 0; + if (handler_called == 0) { + (void)expected_msg; + if (handler_msg[0] != '\0') { + printf( + "ERROR: Custom constraint handler called without error detiction!\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } + } else { + if (handler_msg[0] == '\0') { + (void)expected_msg; + printf("ERROR: Custom constraint handler not called\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + if (strcmp(expected_msg, handler_msg) != 0) { + printf( + "ERROR: Custom constraint handler called with incorrect msg: %s\n", + handler_msg); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + (void)expected_msg; + printf( + "Custom constraint handler called with correct msg: %s\n", + handler_msg); + handler_msg[0] = '\0'; + ret = 0; + } + } + } + return ret; +} + +int +main(void) +{ + size_t length; + int test_id = 0; + int handler_res = 0; + + set_constraint_handler_s(custom_constraint_handler); + + // Test case 1: Normal error code + test_id++; + length = strerrorlen_s(EINVAL); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(length == strlen("Invalid argument"), "Normal error code length", + handler_res, test_id); + + // Test case 2: Unknown error code + test_id++; + length = strerrorlen_s(12345); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(length == 0, "Unknown error code length", handler_res, test_id); + + printf("All strerrorlen_s tests passed!\n"); + return 0; +} \ No newline at end of file diff --git a/test/test-strncat_s.c b/test/test-strncat_s.c new file mode 100644 index 0000000000..ca8c75d485 --- /dev/null +++ b/test/test-strncat_s.c @@ -0,0 +1,178 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +#define MAX_ERROR_MSG 100 + +void custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error); +int test_handler_called(int handler_called, char *expected_msg, int test_id); + +char handler_msg[MAX_ERROR_MSG] = ""; + +void +custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error) +{ + (void)ptr; + (void)error; + strcpy(handler_msg, msg); +} + +#define TEST_RES(cond, msg, handler_res, test_id) \ + if ((!(cond)) || (handler_res == 1)) { \ + printf("Test %d Failed: %s\n", test_id, msg); \ + return 1; \ + } else { \ + printf("Test %d Passed: %s\n", test_id, msg); \ + } + +int +test_handler_called(int handler_called, char *expected_msg, int test_id) +{ + int ret = 0; + if (handler_called == 0) { + (void)expected_msg; + if (handler_msg[0] != '\0') { + printf( + "ERROR: Custom constraint handler called without error detiction!\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } + } else { + if (handler_msg[0] == '\0') { + (void)expected_msg; + printf("ERROR: Custom constraint handler not called\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + if (strcmp(expected_msg, handler_msg) != 0) { + printf( + "ERROR: Custom constraint handler called with incorrect msg: %s\n", + handler_msg); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + (void)expected_msg; + printf( + "Custom constraint handler called with correct msg: %s\n", + handler_msg); + handler_msg[0] = '\0'; + ret = 0; + } + } + } + return ret; +} + +int +main(void) +{ + char dest[50] = "Hello"; + const char *src = ", world!"; + int test_id = 0; + int handler_res = 0; + __errno_t res; + + set_constraint_handler_s(custom_constraint_handler); + + // Test case 1: Normal Concatenation + test_id++; + strcpy(dest, "Hello"); + res = strncat_s(dest, sizeof(dest), src, 8); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Normal Concatenation", handler_res, test_id); + TEST_RES(strcmp(dest, "Hello, world!") == 0, + "Normal Concatenation Contents", handler_res, test_id); + + // Test case 2: Concatenation with insufficient buffer + test_id++; + strcpy(dest, "Hello"); + res = strncat_s(dest, 10, src, 8); + handler_res = test_handler_called( + 1, "strncat_s: dest buffer size insufficent to copy string", test_id); + TEST_RES(res != 0, "Concatenation with insufficient buffer", handler_res, + test_id); + + // Test case 3: Null pointers + test_id++; + res = strncat_s(NULL, sizeof(dest), src, 8); + handler_res = test_handler_called(1, "strncat_s: dest is NULL", test_id); + TEST_RES(res != 0, "NULL Destination Pointer", handler_res, test_id); + res = strncat_s(dest, sizeof(dest), NULL, 8); + handler_res = test_handler_called(1, "strncat_s: source is NULL", test_id); + TEST_RES(res != 0, "NULL Source Pointer", handler_res, test_id); + + // Test case 4: Concatenation of empty source string + test_id++; + strcpy(dest, "Hello"); + res = strncat_s(dest, sizeof(dest), "", 0); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Concatenation of empty source string", handler_res, + test_id); + TEST_RES(strcmp(dest, "Hello") == 0, + "Concatenation of empty source string Contents", handler_res, + test_id); + + // Test case 5: Concatenation with empty destination string + test_id++; + char buf2[50]; + res = strncat_s(buf2, sizeof(buf2), src, 8); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Concatenation of non-empty source to empty destination", + handler_res, test_id); + TEST_RES(strcmp(buf2, ", world!") == 0, + "Concatenation of non-empty source to empty destination Contents", + handler_res, test_id); + + // Test case 6: Concatenation with Zero Characters + test_id++; + strcpy(dest, "Hello"); + res = strncat_s(dest, sizeof(dest), src, 0); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Concatenation with Zero Characters", handler_res, + test_id); + TEST_RES(strcmp(dest, "Hello") == 0, + "Concatenation with Zero Characters Contents", handler_res, + test_id); + + printf("All strncat_s tests passed!\n"); + return 0; +} \ No newline at end of file diff --git a/test/test-strncpy_s.c b/test/test-strncpy_s.c new file mode 100644 index 0000000000..23d9b01a3e --- /dev/null +++ b/test/test-strncpy_s.c @@ -0,0 +1,158 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +#define MAX_ERROR_MSG 100 + +void custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error); +int test_handler_called(int handler_called, char *expected_msg, int test_id); + +char handler_msg[MAX_ERROR_MSG] = ""; + +void +custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error) +{ + (void)ptr; + (void)error; + strcpy(handler_msg, msg); +} + +#define TEST_RES(cond, msg, handler_res, test_id) \ + if ((!(cond)) || (handler_res == 1)) { \ + printf("Test %d Failed: %s\n", test_id, msg); \ + return 1; \ + } else { \ + printf("Test %d Passed: %s\n", test_id, msg); \ + } + +int +test_handler_called(int handler_called, char *expected_msg, int test_id) +{ + int ret = 0; + if (handler_called == 0) { + (void)expected_msg; + if (handler_msg[0] != '\0') { + printf( + "ERROR: Custom constraint handler called without error detiction!\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } + } else { + if (handler_msg[0] == '\0') { + (void)expected_msg; + printf("ERROR: Custom constraint handler not called\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + if (strcmp(expected_msg, handler_msg) != 0) { + printf( + "ERROR: Custom constraint handler called with incorrect msg: %s\n", + handler_msg); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + (void)expected_msg; + printf( + "Custom constraint handler called with correct msg: %s\n", + handler_msg); + handler_msg[0] = '\0'; + ret = 0; + } + } + } + return ret; +} + +int +main(void) +{ + char dest[50]; + const char *src = "Hello, world!"; + int test_id = 0; + int handler_res = 0; + __errno_t res; + + set_constraint_handler_s(custom_constraint_handler); + + // Test case 1: Normal copy + test_id++; + res = strncpy_s(dest, sizeof(dest), src, 13); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Normal Copy", handler_res, test_id); + TEST_RES(strcmp(dest, "Hello, world!") == 0, "Normal Copy Contents", + handler_res, test_id); + + // Test case 2: Copy with insufficient buffer + test_id++; + res = strncpy_s(dest, 5, src, 13); + handler_res = test_handler_called( + 1, "strncpy_s: dest buffer size insufficent to copy string", test_id); + TEST_RES(res != 0, "Copy with insufficient buffer", handler_res, test_id); + + // Test case 3: Null pointers + test_id++; + res = strncpy_s(NULL, sizeof(dest), src, 13); + handler_res = test_handler_called(1, "strncpy_s: dest is NULL", test_id); + TEST_RES(res != 0, "NULL Destination Pointer", handler_res, test_id); + res = strncpy_s(dest, sizeof(dest), NULL, 13); + handler_res = test_handler_called(1, "strncpy_s: source is NULL", test_id); + TEST_RES(res != 0, "NULL Source Pointer", handler_res, test_id); + + // Test case 4: Copy of empty string + test_id++; + res = strncpy_s(dest, sizeof(dest), "", 0); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Copy of empty string", handler_res, test_id); + TEST_RES(strcmp(dest, "") == 0, "Copy of empty string Contents", + handler_res, test_id); + + // Test case 5: Copy with zero Characters + test_id++; + res = strncpy_s(dest, sizeof(dest), "Hello, world!", 0); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(res == 0, "Copy with zero Characters", handler_res, test_id); + TEST_RES(strcmp(dest, "") == 0, "Copy with zero Characters Contents", + handler_res, test_id); + + printf("All strncpy_s tests passed!\n"); + return 0; +} \ No newline at end of file diff --git a/test/test-strnlen_s.c b/test/test-strnlen_s.c new file mode 100644 index 0000000000..150ddbc9c9 --- /dev/null +++ b/test/test-strnlen_s.c @@ -0,0 +1,154 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright © 2024, Synopsys Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +#include + +#define MAX_ERROR_MSG 100 + +void custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error); +int test_handler_called(int handler_called, char *expected_msg, int test_id); + +char handler_msg[MAX_ERROR_MSG] = ""; + +void +custom_constraint_handler(const char *restrict msg, void *restrict ptr, + __errno_t error) +{ + (void)ptr; + (void)error; + strcpy(handler_msg, msg); +} + +#define TEST_RES(cond, msg, handler_res, test_id) \ + if ((!(cond)) || (handler_res == 1)) { \ + printf("Test %d Failed: %s\n", test_id, msg); \ + return 1; \ + } else { \ + printf("Test %d Passed: %s\n", test_id, msg); \ + } + +int +test_handler_called(int handler_called, char *expected_msg, int test_id) +{ + int ret = 0; + if (handler_called == 0) { + (void)expected_msg; + if (handler_msg[0] != '\0') { + printf( + "ERROR: Custom constraint handler called without error detiction!\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } + } else { + if (handler_msg[0] == '\0') { + (void)expected_msg; + printf("ERROR: Custom constraint handler not called\n"); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + if (strcmp(expected_msg, handler_msg) != 0) { + printf( + "ERROR: Custom constraint handler called with incorrect msg: %s\n", + handler_msg); + printf("Test %d Failed: Error msg is incorrect\n", test_id); + ret = 1; + } else { + (void)expected_msg; + printf( + "Custom constraint handler called with correct msg: %s\n", + handler_msg); + handler_msg[0] = '\0'; + ret = 0; + } + } + } + return ret; +} + +int +main(void) +{ + size_t length; + int test_id = 0; + int handler_res = 0; + + set_constraint_handler_s(custom_constraint_handler); + + // Test case 1: Normal length + test_id++; + length = strnlen_s("Hello, world!", 50); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(length == 13, "Normal length", handler_res, test_id); + + // Test case 2: Length with exact buffer size + test_id++; + length = strnlen_s("Hello, world!", 13); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(length == 13, "Length with exact buffer size", handler_res, + test_id); + + // Test case 3: Length with insufficient buffer + test_id++; + length = strnlen_s("Hello, world!", 5); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(length == 5, "Length with insufficient buffer", handler_res, + test_id); + + // Test case 4: Length of empty string + test_id++; + length = strnlen_s("", 50); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(length == 0, "Length of empty string", handler_res, test_id); + + // Test case 5: Length with Null string + test_id++; + length = strnlen_s(NULL, 50); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(length == 0, "Length with Null string", handler_res, test_id); + + // Test case 6: Length with zero buffer size + test_id++; + length = strnlen_s("Hello, world!", 0); + handler_res = test_handler_called(0, "", test_id); + TEST_RES(length == 0, "Length with zero buffer size", handler_res, test_id); + + printf("All strnlen_s tests passed!\n"); + return 0; +} \ No newline at end of file