From 709e6b4497c7be9c5301e3c7ef8fe9e6f0f5db8d Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Fri, 10 Feb 2023 22:34:37 +0100 Subject: [PATCH] Add stpecpy() strncat(3), strlcpy(3), and many other functions are often misused for catenating strings, when they should never be used for that. strlcat(3) is good. However, there's no equivalent to strlcat(3) similar to snprintf(3). Let's add stpecpy(), which is similar to strlcat(3), but it is also the only function compatible with stpeprintf(), which makes it more useful than strlcat(3). Signed-off-by: Alejandro Colomar --- configure.ac | 2 +- lib/stpecpy.h | 92 +++++++++++++++++++++++++++++++++++++++++++++ libmisc/Makefile.am | 1 + libmisc/stpecpy.c | 20 ++++++++++ 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 lib/stpecpy.h create mode 100644 libmisc/stpecpy.c diff --git a/configure.ac b/configure.ac index ecf9fb27..f4c29ca4 100644 --- a/configure.ac +++ b/configure.ac @@ -50,7 +50,7 @@ AC_CHECK_FUNCS(arc4random_buf futimes \ initgroups lckpwdf lutimes mempcpy \ setgroups updwtmp updwtmpx innetgr \ getspnam_r \ - memset_explicit explicit_bzero stpeprintf) + memset_explicit explicit_bzero stpecpy stpeprintf) AC_SYS_LARGEFILE dnl Checks for typedefs, structures, and compiler characteristics. diff --git a/lib/stpecpy.h b/lib/stpecpy.h new file mode 100644 index 00000000..e2c2f479 --- /dev/null +++ b/lib/stpecpy.h @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2022 - 2023, Alejandro Colomar + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#ifndef SHADOW_INCLUDE_LIB_STPECPY_H_ +#define SHADOW_INCLUDE_LIB_STPECPY_H_ + + +#include + +#if !defined(HAVE_STPECPY) + +#include +#include +#include + +#include "defines.h" + + +inline char *stpecpy(char *dst, char *end, const char *restrict src); + + +/* + * SYNOPSIS + * char *_Nullable stpecpy(char *_Nullable dst, char end[0], + * const char *restrict src); + * + * ARGUMENTS + * dst Destination buffer where to copy a string. + * + * end Pointer to one after the last element of the buffer + * pointed to by `dst`. Usually, it should be calculated + * as `dst + NITEMS(dst)`. + * + * src Source string to be copied into dst. + * + * DESCRIPTION + * This function copies the string pointed to by src, into a string + * at the buffer pointed to by dst. If the destination buffer, + * limited by a pointer to its end --one after its last element--, + * isn't large enough to hold the copy, the resulting string is + * truncated. + * + * This function can be chained with calls to [v]stpeprintf(). + * + * RETURN VALUE + * dst + strlen(dst) + * • On success, this function returns a pointer to the + * terminating NUL byte. + * + * end + * • If this call truncated the resulting string. + * • If `dst == end` (a previous chained call to these + * functions truncated). + * NULL + * • If `dst == NULL` (a previous chained call to + * [v]stpeprintf() failed). + * + * ERRORS + * This function doesn't set errno. + */ + + +inline char * +stpecpy(char *dst, char *end, const char *restrict src) +{ + bool trunc; + char *p; + size_t dsize, dlen, slen; + + if (dst == end) + return end; + if (dst == NULL) + return NULL; + + dsize = end - dst; + slen = strnlen(src, dsize); + trunc = (slen == dsize); + dlen = slen - trunc; + + p = mempcpy(dst, src, dlen); + *p = '\0'; + + return p + trunc; +} + + +#endif // !HAVE_STPECPY +#endif // include guard diff --git a/libmisc/Makefile.am b/libmisc/Makefile.am index 870da0b8..655fd4bf 100644 --- a/libmisc/Makefile.am +++ b/libmisc/Makefile.am @@ -62,6 +62,7 @@ libmisc_la_SOURCES = \ setugid.c \ setupenv.c \ shell.c \ + stpecpy.c \ stpeprintf.c \ strtoday.c \ sub.c \ diff --git a/libmisc/stpecpy.c b/libmisc/stpecpy.c new file mode 100644 index 00000000..faa02d69 --- /dev/null +++ b/libmisc/stpecpy.c @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2022 - 2023, Alejandro Colomar + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#include + +#if !defined(HAVE_STPECPY) + +#ident "$Id$" + +#include "stpecpy.h" + + +extern inline char *stpecpy(char *dst, char *end, const char *restrict src); + + +#endif // !HAVE_STPECPY