[v2,1/3] Implement strlcpy and strlcat [BZ #178]
Checks
Context |
Check |
Description |
dj/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
Commit Message
These functions are about to be added to POSIX, under Austin Group
issue 986.
The fortified strlcat implementation does not raise SIGABRT if the
destination buffer does not contain a null terminator, it just
inheritis the non-failing regular strlcat behavior.
---
NEWS | 3 +
debug/Makefile | 2 +
debug/Versions | 4 +
debug/strlcat_chk.c | 31 +++++++
debug/strlcpy_chk.c | 31 +++++++
debug/tst-fortify.c | 31 +++++++
include/string.h | 4 +
string/Makefile | 4 +
string/Versions | 4 +
string/bits/string_fortified.h | 36 ++++++++
string/string.h | 13 +++
string/strlcat.c | 59 +++++++++++++
string/strlcpy.c | 46 ++++++++++
string/tst-strlcat.c | 84 +++++++++++++++++++
string/tst-strlcpy.c | 68 +++++++++++++++
sysdeps/mach/hurd/i386/libc.abilist | 4 +
sysdeps/unix/sysv/linux/aarch64/libc.abilist | 4 +
sysdeps/unix/sysv/linux/alpha/libc.abilist | 4 +
sysdeps/unix/sysv/linux/arc/libc.abilist | 4 +
sysdeps/unix/sysv/linux/arm/be/libc.abilist | 4 +
sysdeps/unix/sysv/linux/arm/le/libc.abilist | 4 +
sysdeps/unix/sysv/linux/csky/libc.abilist | 4 +
sysdeps/unix/sysv/linux/hppa/libc.abilist | 4 +
sysdeps/unix/sysv/linux/i386/libc.abilist | 4 +
sysdeps/unix/sysv/linux/ia64/libc.abilist | 4 +
.../sysv/linux/loongarch/lp64/libc.abilist | 4 +
.../sysv/linux/m68k/coldfire/libc.abilist | 4 +
.../unix/sysv/linux/m68k/m680x0/libc.abilist | 4 +
.../sysv/linux/microblaze/be/libc.abilist | 4 +
.../sysv/linux/microblaze/le/libc.abilist | 4 +
.../sysv/linux/mips/mips32/fpu/libc.abilist | 4 +
.../sysv/linux/mips/mips32/nofpu/libc.abilist | 4 +
.../sysv/linux/mips/mips64/n32/libc.abilist | 4 +
.../sysv/linux/mips/mips64/n64/libc.abilist | 4 +
sysdeps/unix/sysv/linux/nios2/libc.abilist | 4 +
sysdeps/unix/sysv/linux/or1k/libc.abilist | 4 +
.../linux/powerpc/powerpc32/fpu/libc.abilist | 4 +
.../powerpc/powerpc32/nofpu/libc.abilist | 4 +
.../linux/powerpc/powerpc64/be/libc.abilist | 4 +
.../linux/powerpc/powerpc64/le/libc.abilist | 4 +
.../unix/sysv/linux/riscv/rv32/libc.abilist | 4 +
.../unix/sysv/linux/riscv/rv64/libc.abilist | 4 +
.../unix/sysv/linux/s390/s390-32/libc.abilist | 4 +
.../unix/sysv/linux/s390/s390-64/libc.abilist | 4 +
sysdeps/unix/sysv/linux/sh/be/libc.abilist | 4 +
sysdeps/unix/sysv/linux/sh/le/libc.abilist | 4 +
.../sysv/linux/sparc/sparc32/libc.abilist | 4 +
.../sysv/linux/sparc/sparc64/libc.abilist | 4 +
.../unix/sysv/linux/x86_64/64/libc.abilist | 4 +
.../unix/sysv/linux/x86_64/x32/libc.abilist | 4 +
50 files changed, 560 insertions(+)
create mode 100644 debug/strlcat_chk.c
create mode 100644 debug/strlcpy_chk.c
create mode 100644 string/strlcat.c
create mode 100644 string/strlcpy.c
create mode 100644 string/tst-strlcat.c
create mode 100644 string/tst-strlcpy.c
Comments
On 2023-04-20 08:28, Florian Weimer via Libc-alpha wrote:
> These functions are about to be added to POSIX, under Austin Group
> issue 986.
>
> The fortified strlcat implementation does not raise SIGABRT if the
> destination buffer does not contain a null terminator, it just
> inheritis the non-failing regular strlcat behavior.
s/inheritis/inherits/ but you can edit it before you push, it doesn't
need a respin.
Overall LGTM. There is a minor question below, but it's not necessary
to work on it in this patch, it could be a follow-up.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
> ---
> NEWS | 3 +
> debug/Makefile | 2 +
> debug/Versions | 4 +
> debug/strlcat_chk.c | 31 +++++++
> debug/strlcpy_chk.c | 31 +++++++
> debug/tst-fortify.c | 31 +++++++
> include/string.h | 4 +
> string/Makefile | 4 +
> string/Versions | 4 +
> string/bits/string_fortified.h | 36 ++++++++
> string/string.h | 13 +++
> string/strlcat.c | 59 +++++++++++++
> string/strlcpy.c | 46 ++++++++++
> string/tst-strlcat.c | 84 +++++++++++++++++++
> string/tst-strlcpy.c | 68 +++++++++++++++
> sysdeps/mach/hurd/i386/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/aarch64/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/alpha/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/arc/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/arm/be/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/arm/le/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/csky/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/hppa/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/i386/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/ia64/libc.abilist | 4 +
> .../sysv/linux/loongarch/lp64/libc.abilist | 4 +
> .../sysv/linux/m68k/coldfire/libc.abilist | 4 +
> .../unix/sysv/linux/m68k/m680x0/libc.abilist | 4 +
> .../sysv/linux/microblaze/be/libc.abilist | 4 +
> .../sysv/linux/microblaze/le/libc.abilist | 4 +
> .../sysv/linux/mips/mips32/fpu/libc.abilist | 4 +
> .../sysv/linux/mips/mips32/nofpu/libc.abilist | 4 +
> .../sysv/linux/mips/mips64/n32/libc.abilist | 4 +
> .../sysv/linux/mips/mips64/n64/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/nios2/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/or1k/libc.abilist | 4 +
> .../linux/powerpc/powerpc32/fpu/libc.abilist | 4 +
> .../powerpc/powerpc32/nofpu/libc.abilist | 4 +
> .../linux/powerpc/powerpc64/be/libc.abilist | 4 +
> .../linux/powerpc/powerpc64/le/libc.abilist | 4 +
> .../unix/sysv/linux/riscv/rv32/libc.abilist | 4 +
> .../unix/sysv/linux/riscv/rv64/libc.abilist | 4 +
> .../unix/sysv/linux/s390/s390-32/libc.abilist | 4 +
> .../unix/sysv/linux/s390/s390-64/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/sh/be/libc.abilist | 4 +
> sysdeps/unix/sysv/linux/sh/le/libc.abilist | 4 +
> .../sysv/linux/sparc/sparc32/libc.abilist | 4 +
> .../sysv/linux/sparc/sparc64/libc.abilist | 4 +
> .../unix/sysv/linux/x86_64/64/libc.abilist | 4 +
> .../unix/sysv/linux/x86_64/x32/libc.abilist | 4 +
> 50 files changed, 560 insertions(+)
> create mode 100644 debug/strlcat_chk.c
> create mode 100644 debug/strlcpy_chk.c
> create mode 100644 string/strlcat.c
> create mode 100644 string/strlcpy.c
> create mode 100644 string/tst-strlcat.c
> create mode 100644 string/tst-strlcpy.c
>
> diff --git a/NEWS b/NEWS
> index 83d082afad..b21c4c10aa 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -21,6 +21,9 @@ Major new features:
>
> * PRIb* and PRIB* macros from C2X have been added to <inttypes.h>.
>
> +* The strlcpy and strlcat functions have been added. They are derived
> + from OpenBSD, and are expected to be added to a future POSIX version.
> +
OK.
> Deprecated and removed features, and other changes affecting compatibility:
>
> * In the Linux kernel for the hppa/parisc architecture some of the
> diff --git a/debug/Makefile b/debug/Makefile
> index a8b4036cdc..f5f27f793c 100644
> --- a/debug/Makefile
> +++ b/debug/Makefile
> @@ -83,6 +83,8 @@ routines = \
> stpncpy_chk \
> strcat_chk \
> strcpy_chk \
> + strlcat_chk \
> + strlcpy_chk \
> strncat_chk \
> strncpy_chk \
> swprintf_chk \
> diff --git a/debug/Versions b/debug/Versions
> index a6628db356..94dfa5f428 100644
> --- a/debug/Versions
> +++ b/debug/Versions
> @@ -58,6 +58,10 @@ libc {
> GLIBC_2.25 {
> __explicit_bzero_chk;
> }
> + GLIBC_2.38 {
> + __strlcat_chk;
> + __strlcpy_chk;
> + }
> GLIBC_PRIVATE {
> __fortify_fail;
> }
OK.
> diff --git a/debug/strlcat_chk.c b/debug/strlcat_chk.c
> new file mode 100644
> index 0000000000..888a62fad5
> --- /dev/null
> +++ b/debug/strlcat_chk.c
> @@ -0,0 +1,31 @@
> +/* Fortified version of strlcat.
> + Copyright (C) 2023 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <string.h>
> +
> +/* Check that the user-supplied size does not exceed the
> + compiler-determined size, and then forward to strlcat. */
> +size_t
> +__strlcat_chk (char *__restrict s1, const char *__restrict s2,
> + size_t n, size_t s1len)
> +{
> + if (__glibc_unlikely (s1len < n))
> + __chk_fail ();
> +
> + return __strlcat (s1, s2, n);
> +}
Hmm, I had not noticed the __restrict before, but since overlapping
strings are undefined, this is OK.
> diff --git a/debug/strlcpy_chk.c b/debug/strlcpy_chk.c
> new file mode 100644
> index 0000000000..768a3af686
> --- /dev/null
> +++ b/debug/strlcpy_chk.c
> @@ -0,0 +1,31 @@
> +/* Fortified version of strlcpy.
> + Copyright (C) 2023 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <string.h>
> +
> +/* Check that the user-supplied size does not exceed the
> + compiler-determined size, and then forward to strlcpy. */
> +size_t
> +__strlcpy_chk (char *__restrict s1, const char *__restrict s2,
> + size_t n, size_t s1len)
> +{
> + if (__glibc_unlikely (s1len < n))
> + __chk_fail ();
> +
> + return __strlcpy (s1, s2, n);
> +}
OK.
> diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
> index 7850a4e558..f74a5e04dc 100644
> --- a/debug/tst-fortify.c
> +++ b/debug/tst-fortify.c
> @@ -535,6 +535,20 @@ do_test (void)
> strncpy (a.buf1 + (O + 6), "X", l0 + 4);
> CHK_FAIL_END
>
> + CHK_FAIL_START
> + strlcpy (a.buf1 + (O + 6), "X", 4);
> + CHK_FAIL_END
> +
> + CHK_FAIL_START
> + strlcpy (a.buf1 + (O + 6), "X", l0 + 4);
> + CHK_FAIL_END
> +
> + {
> + char *volatile buf2 = buf;
> + if (strlcpy (buf2, "a", sizeof (buf) + 1) != 1)
> + FAIL ();
> + }
> +
> # if !defined __cplusplus || defined __va_arg_pack
> CHK_FAIL_START
> sprintf (a.buf1 + (O + 7), "%d", num1);
> @@ -558,6 +572,23 @@ do_test (void)
> CHK_FAIL_START
> strncat (a.buf1, "ZYXWV", l0 + 3);
> CHK_FAIL_END
> +
> + memset (a.buf1, 0, sizeof (a.buf1));
> + CHK_FAIL_START
> + strlcat (a.buf1 + (O + 6), "X", 4);
> + CHK_FAIL_END
> +
> + memset (a.buf1, 0, sizeof (a.buf1));
> + CHK_FAIL_START
> + strlcat (a.buf1 + (O + 6), "X", l0 + 4);
> + CHK_FAIL_END
> +
> + {
> + buf[0] = '\0';
> + char *volatile buf2 = buf;
> + if (strlcat (buf2, "a", sizeof (buf) + 1) != 1)
> + FAIL ();
> + }
> #endif
>
>
OK.
> diff --git a/include/string.h b/include/string.h
> index 673cfd7272..0c78ad2539 100644
> --- a/include/string.h
> +++ b/include/string.h
> @@ -88,6 +88,10 @@ libc_hidden_proto (__stpcpy)
> # define __stpcpy(dest, src) __builtin_stpcpy (dest, src)
> #endif
> libc_hidden_proto (__stpncpy)
> +extern __typeof (strlcpy) __strlcpy;
> +libc_hidden_proto (__strlcpy)
> +extern __typeof (strlcat) __strlcat;
> +libc_hidden_proto (__strlcat)
> libc_hidden_proto (__rawmemchr)
> libc_hidden_proto (__strcasecmp)
> libc_hidden_proto (__strcasecmp_l)
> diff --git a/string/Makefile b/string/Makefile
> index c84b49aaa5..c746ee1792 100644
> --- a/string/Makefile
> +++ b/string/Makefile
> @@ -92,6 +92,8 @@ routines := \
> strerrorname_np \
> strfry \
> string-inlines \
> + strlcat \
> + strlcpy \
> strlen \
> strncase \
> strncase_l \
> @@ -175,6 +177,8 @@ tests := \
> tst-inlcall \
> tst-memmove-overflow \
> tst-strfry \
> + tst-strlcat \
> + tst-strlcpy \
> tst-strlen \
> tst-strtok \
> tst-strtok_r \
OK.
> diff --git a/string/Versions b/string/Versions
> index 864c4cf7a4..c56e372a3c 100644
> --- a/string/Versions
> +++ b/string/Versions
> @@ -92,4 +92,8 @@ libc {
> GLIBC_2.35 {
> __memcmpeq;
> }
> + GLIBC_2.38 {
> + strlcat;
> + strlcpy;
> + }
> }
OK.
> diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h
> index 9900df6104..23ef064168 100644
> --- a/string/bits/string_fortified.h
> +++ b/string/bits/string_fortified.h
> @@ -139,4 +139,40 @@ __NTH (strncat (char *__restrict __dest, const char *__restrict __src,
> __glibc_objsize (__dest));
> }
>
> +#ifdef __USE_MISC
> +extern size_t __strlcpy_chk (char *__dest, const char *__src, size_t __n,
> + size_t __destlen) __THROW;
> +extern size_t __REDIRECT_NTH (__strlcpy_alias,
> + (char *__dest, const char *__src, size_t __n),
> + strlcpy);
> +
> +__fortify_function size_t
> +__NTH (strlcpy (char *__restrict __dest, const char *__restrict __src,
> + size_t __n))
> +{
> + if (__glibc_objsize (__dest) != (size_t) -1
> + && (!__builtin_constant_p (__n > __glibc_objsize (__dest))
> + || __n > __glibc_objsize (__dest)))
> + return __strlcpy_chk (__dest, __src, __n, __glibc_objsize (__dest));
> + return __strlcpy_alias (__dest, __src, __n);
> +}
> +
> +extern size_t __strlcat_chk (char *__dest, const char *__src, size_t __n,
> + size_t __destlen) __THROW;
> +extern size_t __REDIRECT_NTH (__strlcat_alias,
> + (char *__dest, const char *__src, size_t __n),
> + strlcat);
> +
> +__fortify_function size_t
> +__NTH (strlcat (char *__restrict __dest, const char *__restrict __src,
> + size_t __n))
> +{
> + if (__glibc_objsize (__dest) != (size_t) -1
> + && (!__builtin_constant_p (__n > __glibc_objsize (__dest))
> + || __n > __glibc_objsize (__dest)))
> + return __strlcat_chk (__dest, __src, __n, __glibc_objsize (__dest));
> + return __strlcat_alias (__dest, __src, __n);
> +}
> +#endif /* __USE_MISC */
> +
> #endif /* bits/string_fortified.h */
OK.
> diff --git a/string/string.h b/string/string.h
> index 4927879ecf..c0773d11d8 100644
> --- a/string/string.h
> +++ b/string/string.h
> @@ -501,6 +501,19 @@ extern char *stpncpy (char *__restrict __dest,
> __THROW __nonnull ((1, 2));
> #endif
>
> +#ifdef __USE_MISC
> +/* Copy at most N - 1 characters from SRC to DEST. */
> +extern size_t strlcpy (char *__restrict __dest,
> + const char *__restrict __src, size_t __n)
> + __THROW __nonnull ((1, 2)) __attr_access ((__write_only__, 1, 3));
> +
> +/* Append SRC to DEST, possibly with truncation to keep the total size
> + below N. */
> +extern size_t strlcat (char *__restrict __dest,
> + const char *__restrict __src, size_t __n)
> + __THROW __nonnull ((1, 2)) __attr_access ((__read_write__, 1, 3));
> +#endif
> +
> #ifdef __USE_GNU
> /* Compare S1 and S2 as strings holding name & indices/version numbers. */
> extern int strverscmp (const char *__s1, const char *__s2)
OK.
> diff --git a/string/strlcat.c b/string/strlcat.c
> new file mode 100644
> index 0000000000..dce4c255d1
> --- /dev/null
> +++ b/string/strlcat.c
> @@ -0,0 +1,59 @@
> +/* Append a null-terminated string to another string, with length checking.
> + Copyright (C) 2023 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <stdint.h>
> +#include <string.h>
> +
> +size_t
> +__strlcat (char *__restrict dest, const char *__restrict src, size_t size)
> +{
> + size_t src_length = strlen (src);
> +
> + /* Our implementation strlcat supports dest == NULL if size == 0
> + (for consistency with snprintf and strlcpy), but strnlen does
> + not, so we have to cover this case explicitly. */
> + if (size == 0)
> + return src_length;
> +
> + size_t dest_length = __strnlen (dest, size);
Does __strnlen result in an ifunc call? If not then we're probably
missing out on some speedup. Not a blocker though, something to think
about as an add-on fix.
> + if (dest_length != size)
> + {
> + /* Copy at most the remaining number of characters in the
> + destination buffer. Leave for the NUL terminator. */
> + size_t to_copy = size - dest_length - 1;
> + /* But not more than what is available in the source string. */
> + if (to_copy > src_length)
> + to_copy = src_length;
> +
> + char *target = dest + dest_length;
> + memcpy (target, src, to_copy);
> + target[to_copy] = '\0';
> + }
> +
> + /* If the sum wraps around, we have more than SIZE_MAX + 2 bytes in
> + the two input strings (including both null terminators). If each
> + byte in the address space can be assigned a unique size_t value
> + (which the static_assert checks), then by the pigeonhole
> + principle, the two input strings must overlap, which is
> + undefined. */
> + _Static_assert (sizeof (uintptr_t) == sizeof (size_t),
> + "theoretical maximum object size covers address space");
> + return dest_length + src_length;
> +}
> +libc_hidden_def (__strlcat)
> +weak_alias (__strlcat, strlcat)
> diff --git a/string/strlcpy.c b/string/strlcpy.c
> new file mode 100644
> index 0000000000..7a0df3ebb6
> --- /dev/null
> +++ b/string/strlcpy.c
> @@ -0,0 +1,46 @@
> +/* Copy a null-terminated string to a fixed-size buffer, with length checking.
> + Copyright (C) 2023 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <string.h>
> +
> +size_t
> +__strlcpy (char *__restrict dest, const char *__restrict src, size_t size)
> +{
> + size_t src_length = strlen (src);
> +
> + if (__glibc_unlikely (src_length >= size))
> + {
> + if (size > 0)
> + {
> + /* Copy the leading portion of the string. The last
> + character is subsequently overwritten with the NUL
> + terminator, but the destination size is usually a
> + multiple of a small power of two, so writing it twice
> + should be more efficient than copying an odd number of
> + bytes. */
> + memcpy (dest, src, size);
> + dest[size - 1] = '\0';
> + }
> + }
> + else
> + /* Copy the string and its terminating NUL character. */
> + memcpy (dest, src, src_length + 1);
> + return src_length;
> +}
> +libc_hidden_def (__strlcpy)
> +weak_alias (__strlcpy, strlcpy)
OK.
> diff --git a/string/tst-strlcat.c b/string/tst-strlcat.c
> new file mode 100644
> index 0000000000..f8c716373e
> --- /dev/null
> +++ b/string/tst-strlcat.c
> @@ -0,0 +1,84 @@
> +/* Test the strlcat function.
> + Copyright (C) 2023 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <string.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <support/check.h>
> +
> +static int
> +do_test (void)
> +{
> + struct {
> + char buf1[16];
> + char buf2[16];
> + } s;
> +
> + /* Nothing is written to the destination if its size is 0. */
> + memset (&s, '@', sizeof (s));
> + TEST_COMPARE (strlcat (s.buf1, "", 0), 0);
> + TEST_COMPARE_BLOB (&s, sizeof (s), "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
> + TEST_COMPARE (strlcat (s.buf1, "Hello!", 0), 6);
> + TEST_COMPARE_BLOB (&s, sizeof (s), "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
> +
> + /* No bytes are are modified in the target buffer if the source
> + string is short enough. */
> + memset (&s, '@', sizeof (s));
> + strcpy (s.buf1, "He");
> + TEST_COMPARE (strlcat (s.buf1, "llo!", sizeof (s.buf1)), 6);
> + TEST_COMPARE_BLOB (&s, sizeof (s), "Hello!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
> +
> + /* A source string which fits exactly into the destination buffer is
> + not truncated. */
> + memset (&s, '@', sizeof (s));
> + strcpy (s.buf1, "H");
> + TEST_COMPARE (strlcat (s.buf1, "ello, world!!!", sizeof (s.buf1)), 15);
> + TEST_COMPARE_BLOB (&s, sizeof (s),
> + "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
> +
> + /* A source string one character longer than the destination buffer
> + is truncated by one character. The total length is returned. */
> + memset (&s, '@', sizeof (s));
> + strcpy (s.buf1, "Hello");
> + TEST_COMPARE (strlcat (s.buf1, ", world!!!!", sizeof (s.buf1)), 16);
> + TEST_COMPARE_BLOB (&s, sizeof (s),
> + "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
> +
> + /* An even longer source string is truncated as well, and the total
> + length is returned. */
> + memset (&s, '@', sizeof (s));
> + strcpy (s.buf1, "Hello,");
> + TEST_COMPARE (strlcat (s.buf1, " world!!!!!!!!", sizeof (s.buf1)), 20);
> + TEST_COMPARE_BLOB (&s, sizeof (s),
> + "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
> +
> + /* A destination string which is not NUL-terminated does not result
> + in any changes to the buffer. */
> + memset (&s, '@', sizeof (s));
> + memset (s.buf1, '$', sizeof (s.buf1));
> + TEST_COMPARE (strlcat (s.buf1, "", sizeof (s.buf1)), 16);
> + TEST_COMPARE_BLOB (&s, sizeof (s), "$$$$$$$$$$$$$$$$@@@@@@@@@@@@@@@@", 32);
> + TEST_COMPARE (strlcat (s.buf1, "Hello!", sizeof (s.buf1)), 22);
> + TEST_COMPARE_BLOB (&s, sizeof (s), "$$$$$$$$$$$$$$$$@@@@@@@@@@@@@@@@", 32);
> + TEST_COMPARE (strlcat (s.buf1, "Hello, world!!!!!!!!", sizeof (s.buf1)), 36);
> + TEST_COMPARE_BLOB (&s, sizeof (s), "$$$$$$$$$$$$$$$$@@@@@@@@@@@@@@@@", 32);
> +
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/string/tst-strlcpy.c b/string/tst-strlcpy.c
> new file mode 100644
> index 0000000000..0063c43f5c
> --- /dev/null
> +++ b/string/tst-strlcpy.c
> @@ -0,0 +1,68 @@
> +/* Test the strlcpy function.
> + Copyright (C) 2023 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <string.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <support/check.h>
> +
> +static int
> +do_test (void)
> +{
> + struct {
> + char buf1[16];
> + char buf2[16];
> + } s;
> +
> + /* Nothing is written to the destination if its size is 0. */
> + memset (&s, '@', sizeof (s));
> + TEST_COMPARE (strlcpy (s.buf1, "Hello!", 0), 6);
> + TEST_COMPARE_BLOB (&s, sizeof (s), "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
> +
> + /* No bytes are are modified in the target buffer if the source
> + string is short enough. */
> + memset (&s, '@', sizeof (s));
> + TEST_COMPARE (strlcpy (s.buf1, "Hello!", sizeof (s.buf1)), 6);
> + TEST_COMPARE_BLOB (&s, sizeof (s), "Hello!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
> +
> + /* A source string which fits exactly into the destination buffer is
> + not truncated. */
> + memset (&s, '@', sizeof (s));
> + TEST_COMPARE (strlcpy (s.buf1, "Hello, world!!!", sizeof (s.buf1)), 15);
> + TEST_COMPARE_BLOB (&s, sizeof (s),
> + "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
> +
> + /* A source string one character longer than the destination buffer
> + is truncated by one character. The untruncated source length is
> + returned. */
> + memset (&s, '@', sizeof (s));
> + TEST_COMPARE (strlcpy (s.buf1, "Hello, world!!!!", sizeof (s.buf1)), 16);
> + TEST_COMPARE_BLOB (&s, sizeof (s),
> + "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
> +
> + /* An even longer source string is truncated as well, and the
> + original length is returned. */
> + memset (&s, '@', sizeof (s));
> + TEST_COMPARE (strlcpy (s.buf1, "Hello, world!!!!!!!!", sizeof (s.buf1)), 20);
> + TEST_COMPARE_BLOB (&s, sizeof (s),
> + "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
> +
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
> index 6925222ff3..9b4c5f4719 100644
> --- a/sysdeps/mach/hurd/i386/libc.abilist
> +++ b/sysdeps/mach/hurd/i386/libc.abilist
> @@ -2326,6 +2326,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index 0e2d9c3045..cf51b88932 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2665,3 +2665,7 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index f1bec1978d..4b25f343b8 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2774,6 +2774,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
> GLIBC_2.38 __nldbl___isoc23_vswscanf F
> GLIBC_2.38 __nldbl___isoc23_vwscanf F
> GLIBC_2.38 __nldbl___isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
> index aa874b88d0..5a58cc0477 100644
> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
> @@ -2426,3 +2426,7 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> index afbd57da6f..99ce948c5c 100644
> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> @@ -546,6 +546,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 _Exit F
> GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
> GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> index e7364cd3fe..c00bf72ebc 100644
> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> @@ -543,6 +543,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 _Exit F
> GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
> GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 913fa59215..71130f2c6b 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2702,3 +2702,7 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 43af3a9811..5a651c03df 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2651,6 +2651,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index af72f8fab0..12b91ef632 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2835,6 +2835,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index 48cbb0fa50..f223c5e08d 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -2600,6 +2600,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> index c15884bb0b..b91ed6e704 100644
> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> @@ -2186,3 +2186,7 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 3738db81df..0d91d7f1ae 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -547,6 +547,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 _Exit F
> GLIBC_2.4 _IO_2_1_stderr_ D 0x98
> GLIBC_2.4 _IO_2_1_stdin_ D 0x98
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index ed13627752..e87b22747a 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2778,6 +2778,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> index 8357738621..f7623d6d72 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> @@ -2751,3 +2751,7 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> index 58c5da583d..298aa99b42 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> @@ -2748,3 +2748,7 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index d3741945cd..f83bdc50cd 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2743,6 +2743,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 5319fdc204..611ece2ac4 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2741,6 +2741,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 1743ea6eb9..0af286fda1 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2749,6 +2749,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 9b1f53c6ac..8285f2196e 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2651,6 +2651,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index ae1c6ca1b5..c7144d7cd8 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2790,3 +2790,7 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> index a7c572c947..bb43247795 100644
> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> @@ -2172,3 +2172,7 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 074fa031a7..7cc5660830 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -2817,6 +2817,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
> GLIBC_2.38 __nldbl___isoc23_vswscanf F
> GLIBC_2.38 __nldbl___isoc23_vwscanf F
> GLIBC_2.38 __nldbl___isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index dfcb4bd2d5..dd290af782 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -2850,6 +2850,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
> GLIBC_2.38 __nldbl___isoc23_vswscanf F
> GLIBC_2.38 __nldbl___isoc23_vwscanf F
> GLIBC_2.38 __nldbl___isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index 63bbccf3f9..f2b001402c 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2571,6 +2571,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
> GLIBC_2.38 __nldbl___isoc23_vswscanf F
> GLIBC_2.38 __nldbl___isoc23_vwscanf F
> GLIBC_2.38 __nldbl___isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index ab85fd61ef..9cc431666e 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2885,3 +2885,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
> GLIBC_2.38 __nldbl___isoc23_vswscanf F
> GLIBC_2.38 __nldbl___isoc23_vwscanf F
> GLIBC_2.38 __nldbl___isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> index b716f5c763..b9b725f913 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> @@ -2428,3 +2428,7 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index 774e777b65..e0f4863856 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2628,3 +2628,7 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 8625135c48..8db68fcea7 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -2815,6 +2815,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
> GLIBC_2.38 __nldbl___isoc23_vswscanf F
> GLIBC_2.38 __nldbl___isoc23_vwscanf F
> GLIBC_2.38 __nldbl___isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index d00c7eb262..ec9747b7ea 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2608,6 +2608,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
> GLIBC_2.38 __nldbl___isoc23_vswscanf F
> GLIBC_2.38 __nldbl___isoc23_vwscanf F
> GLIBC_2.38 __nldbl___isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> index b63037241d..9576b818d8 100644
> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> @@ -2658,6 +2658,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> index d80055617d..b67b1b2bb5 100644
> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> @@ -2655,6 +2655,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index 5be55c11d2..b251fc9c69 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -2810,6 +2810,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
> GLIBC_2.38 __nldbl___isoc23_vswscanf F
> GLIBC_2.38 __nldbl___isoc23_vwscanf F
> GLIBC_2.38 __nldbl___isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 475fdaae15..5ef9bbec34 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2623,6 +2623,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index 6cfb928bc8..9ad800b62e 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2574,6 +2574,10 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index c735097172..6a3a66c5d4 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2680,3 +2680,7 @@ GLIBC_2.38 __isoc23_wcstoull F
> GLIBC_2.38 __isoc23_wcstoull_l F
> GLIBC_2.38 __isoc23_wcstoumax F
> GLIBC_2.38 __isoc23_wscanf F
> +GLIBC_2.38 __strlcat_chk F
> +GLIBC_2.38 __strlcpy_chk F
> +GLIBC_2.38 strlcat F
> +GLIBC_2.38 strlcpy F
* Siddhesh Poyarekar:
>> +size_t
>> +__strlcat (char *__restrict dest, const char *__restrict src, size_t size)
>> +{
>> + size_t src_length = strlen (src);
>> +
>> + /* Our implementation strlcat supports dest == NULL if size == 0
>> + (for consistency with snprintf and strlcpy), but strnlen does
>> + not, so we have to cover this case explicitly. */
>> + if (size == 0)
>> + return src_length;
>> +
>> + size_t dest_length = __strnlen (dest, size);
>
> Does __strnlen result in an ifunc call? If not then we're probably
> missing out on some speedup. Not a blocker though, something to think
> about as an add-on fix.
This is architecture-dependent, I think. Some architectures prefer
direct calls over IFUNC dispatch.
Targets with IFUNCs will likely get IFUNCs for strlcat and strlcpy as
well.
Thanks,
Florian
@@ -21,6 +21,9 @@ Major new features:
* PRIb* and PRIB* macros from C2X have been added to <inttypes.h>.
+* The strlcpy and strlcat functions have been added. They are derived
+ from OpenBSD, and are expected to be added to a future POSIX version.
+
Deprecated and removed features, and other changes affecting compatibility:
* In the Linux kernel for the hppa/parisc architecture some of the
@@ -83,6 +83,8 @@ routines = \
stpncpy_chk \
strcat_chk \
strcpy_chk \
+ strlcat_chk \
+ strlcpy_chk \
strncat_chk \
strncpy_chk \
swprintf_chk \
@@ -58,6 +58,10 @@ libc {
GLIBC_2.25 {
__explicit_bzero_chk;
}
+ GLIBC_2.38 {
+ __strlcat_chk;
+ __strlcpy_chk;
+ }
GLIBC_PRIVATE {
__fortify_fail;
}
new file mode 100644
@@ -0,0 +1,31 @@
+/* Fortified version of strlcat.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <string.h>
+
+/* Check that the user-supplied size does not exceed the
+ compiler-determined size, and then forward to strlcat. */
+size_t
+__strlcat_chk (char *__restrict s1, const char *__restrict s2,
+ size_t n, size_t s1len)
+{
+ if (__glibc_unlikely (s1len < n))
+ __chk_fail ();
+
+ return __strlcat (s1, s2, n);
+}
new file mode 100644
@@ -0,0 +1,31 @@
+/* Fortified version of strlcpy.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <string.h>
+
+/* Check that the user-supplied size does not exceed the
+ compiler-determined size, and then forward to strlcpy. */
+size_t
+__strlcpy_chk (char *__restrict s1, const char *__restrict s2,
+ size_t n, size_t s1len)
+{
+ if (__glibc_unlikely (s1len < n))
+ __chk_fail ();
+
+ return __strlcpy (s1, s2, n);
+}
@@ -535,6 +535,20 @@ do_test (void)
strncpy (a.buf1 + (O + 6), "X", l0 + 4);
CHK_FAIL_END
+ CHK_FAIL_START
+ strlcpy (a.buf1 + (O + 6), "X", 4);
+ CHK_FAIL_END
+
+ CHK_FAIL_START
+ strlcpy (a.buf1 + (O + 6), "X", l0 + 4);
+ CHK_FAIL_END
+
+ {
+ char *volatile buf2 = buf;
+ if (strlcpy (buf2, "a", sizeof (buf) + 1) != 1)
+ FAIL ();
+ }
+
# if !defined __cplusplus || defined __va_arg_pack
CHK_FAIL_START
sprintf (a.buf1 + (O + 7), "%d", num1);
@@ -558,6 +572,23 @@ do_test (void)
CHK_FAIL_START
strncat (a.buf1, "ZYXWV", l0 + 3);
CHK_FAIL_END
+
+ memset (a.buf1, 0, sizeof (a.buf1));
+ CHK_FAIL_START
+ strlcat (a.buf1 + (O + 6), "X", 4);
+ CHK_FAIL_END
+
+ memset (a.buf1, 0, sizeof (a.buf1));
+ CHK_FAIL_START
+ strlcat (a.buf1 + (O + 6), "X", l0 + 4);
+ CHK_FAIL_END
+
+ {
+ buf[0] = '\0';
+ char *volatile buf2 = buf;
+ if (strlcat (buf2, "a", sizeof (buf) + 1) != 1)
+ FAIL ();
+ }
#endif
@@ -88,6 +88,10 @@ libc_hidden_proto (__stpcpy)
# define __stpcpy(dest, src) __builtin_stpcpy (dest, src)
#endif
libc_hidden_proto (__stpncpy)
+extern __typeof (strlcpy) __strlcpy;
+libc_hidden_proto (__strlcpy)
+extern __typeof (strlcat) __strlcat;
+libc_hidden_proto (__strlcat)
libc_hidden_proto (__rawmemchr)
libc_hidden_proto (__strcasecmp)
libc_hidden_proto (__strcasecmp_l)
@@ -92,6 +92,8 @@ routines := \
strerrorname_np \
strfry \
string-inlines \
+ strlcat \
+ strlcpy \
strlen \
strncase \
strncase_l \
@@ -175,6 +177,8 @@ tests := \
tst-inlcall \
tst-memmove-overflow \
tst-strfry \
+ tst-strlcat \
+ tst-strlcpy \
tst-strlen \
tst-strtok \
tst-strtok_r \
@@ -92,4 +92,8 @@ libc {
GLIBC_2.35 {
__memcmpeq;
}
+ GLIBC_2.38 {
+ strlcat;
+ strlcpy;
+ }
}
@@ -139,4 +139,40 @@ __NTH (strncat (char *__restrict __dest, const char *__restrict __src,
__glibc_objsize (__dest));
}
+#ifdef __USE_MISC
+extern size_t __strlcpy_chk (char *__dest, const char *__src, size_t __n,
+ size_t __destlen) __THROW;
+extern size_t __REDIRECT_NTH (__strlcpy_alias,
+ (char *__dest, const char *__src, size_t __n),
+ strlcpy);
+
+__fortify_function size_t
+__NTH (strlcpy (char *__restrict __dest, const char *__restrict __src,
+ size_t __n))
+{
+ if (__glibc_objsize (__dest) != (size_t) -1
+ && (!__builtin_constant_p (__n > __glibc_objsize (__dest))
+ || __n > __glibc_objsize (__dest)))
+ return __strlcpy_chk (__dest, __src, __n, __glibc_objsize (__dest));
+ return __strlcpy_alias (__dest, __src, __n);
+}
+
+extern size_t __strlcat_chk (char *__dest, const char *__src, size_t __n,
+ size_t __destlen) __THROW;
+extern size_t __REDIRECT_NTH (__strlcat_alias,
+ (char *__dest, const char *__src, size_t __n),
+ strlcat);
+
+__fortify_function size_t
+__NTH (strlcat (char *__restrict __dest, const char *__restrict __src,
+ size_t __n))
+{
+ if (__glibc_objsize (__dest) != (size_t) -1
+ && (!__builtin_constant_p (__n > __glibc_objsize (__dest))
+ || __n > __glibc_objsize (__dest)))
+ return __strlcat_chk (__dest, __src, __n, __glibc_objsize (__dest));
+ return __strlcat_alias (__dest, __src, __n);
+}
+#endif /* __USE_MISC */
+
#endif /* bits/string_fortified.h */
@@ -501,6 +501,19 @@ extern char *stpncpy (char *__restrict __dest,
__THROW __nonnull ((1, 2));
#endif
+#ifdef __USE_MISC
+/* Copy at most N - 1 characters from SRC to DEST. */
+extern size_t strlcpy (char *__restrict __dest,
+ const char *__restrict __src, size_t __n)
+ __THROW __nonnull ((1, 2)) __attr_access ((__write_only__, 1, 3));
+
+/* Append SRC to DEST, possibly with truncation to keep the total size
+ below N. */
+extern size_t strlcat (char *__restrict __dest,
+ const char *__restrict __src, size_t __n)
+ __THROW __nonnull ((1, 2)) __attr_access ((__read_write__, 1, 3));
+#endif
+
#ifdef __USE_GNU
/* Compare S1 and S2 as strings holding name & indices/version numbers. */
extern int strverscmp (const char *__s1, const char *__s2)
new file mode 100644
@@ -0,0 +1,59 @@
+/* Append a null-terminated string to another string, with length checking.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+#include <string.h>
+
+size_t
+__strlcat (char *__restrict dest, const char *__restrict src, size_t size)
+{
+ size_t src_length = strlen (src);
+
+ /* Our implementation strlcat supports dest == NULL if size == 0
+ (for consistency with snprintf and strlcpy), but strnlen does
+ not, so we have to cover this case explicitly. */
+ if (size == 0)
+ return src_length;
+
+ size_t dest_length = __strnlen (dest, size);
+ if (dest_length != size)
+ {
+ /* Copy at most the remaining number of characters in the
+ destination buffer. Leave for the NUL terminator. */
+ size_t to_copy = size - dest_length - 1;
+ /* But not more than what is available in the source string. */
+ if (to_copy > src_length)
+ to_copy = src_length;
+
+ char *target = dest + dest_length;
+ memcpy (target, src, to_copy);
+ target[to_copy] = '\0';
+ }
+
+ /* If the sum wraps around, we have more than SIZE_MAX + 2 bytes in
+ the two input strings (including both null terminators). If each
+ byte in the address space can be assigned a unique size_t value
+ (which the static_assert checks), then by the pigeonhole
+ principle, the two input strings must overlap, which is
+ undefined. */
+ _Static_assert (sizeof (uintptr_t) == sizeof (size_t),
+ "theoretical maximum object size covers address space");
+ return dest_length + src_length;
+}
+libc_hidden_def (__strlcat)
+weak_alias (__strlcat, strlcat)
new file mode 100644
@@ -0,0 +1,46 @@
+/* Copy a null-terminated string to a fixed-size buffer, with length checking.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <string.h>
+
+size_t
+__strlcpy (char *__restrict dest, const char *__restrict src, size_t size)
+{
+ size_t src_length = strlen (src);
+
+ if (__glibc_unlikely (src_length >= size))
+ {
+ if (size > 0)
+ {
+ /* Copy the leading portion of the string. The last
+ character is subsequently overwritten with the NUL
+ terminator, but the destination size is usually a
+ multiple of a small power of two, so writing it twice
+ should be more efficient than copying an odd number of
+ bytes. */
+ memcpy (dest, src, size);
+ dest[size - 1] = '\0';
+ }
+ }
+ else
+ /* Copy the string and its terminating NUL character. */
+ memcpy (dest, src, src_length + 1);
+ return src_length;
+}
+libc_hidden_def (__strlcpy)
+weak_alias (__strlcpy, strlcpy)
new file mode 100644
@@ -0,0 +1,84 @@
+/* Test the strlcat function.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ struct {
+ char buf1[16];
+ char buf2[16];
+ } s;
+
+ /* Nothing is written to the destination if its size is 0. */
+ memset (&s, '@', sizeof (s));
+ TEST_COMPARE (strlcat (s.buf1, "", 0), 0);
+ TEST_COMPARE_BLOB (&s, sizeof (s), "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
+ TEST_COMPARE (strlcat (s.buf1, "Hello!", 0), 6);
+ TEST_COMPARE_BLOB (&s, sizeof (s), "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
+
+ /* No bytes are are modified in the target buffer if the source
+ string is short enough. */
+ memset (&s, '@', sizeof (s));
+ strcpy (s.buf1, "He");
+ TEST_COMPARE (strlcat (s.buf1, "llo!", sizeof (s.buf1)), 6);
+ TEST_COMPARE_BLOB (&s, sizeof (s), "Hello!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
+
+ /* A source string which fits exactly into the destination buffer is
+ not truncated. */
+ memset (&s, '@', sizeof (s));
+ strcpy (s.buf1, "H");
+ TEST_COMPARE (strlcat (s.buf1, "ello, world!!!", sizeof (s.buf1)), 15);
+ TEST_COMPARE_BLOB (&s, sizeof (s),
+ "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
+
+ /* A source string one character longer than the destination buffer
+ is truncated by one character. The total length is returned. */
+ memset (&s, '@', sizeof (s));
+ strcpy (s.buf1, "Hello");
+ TEST_COMPARE (strlcat (s.buf1, ", world!!!!", sizeof (s.buf1)), 16);
+ TEST_COMPARE_BLOB (&s, sizeof (s),
+ "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
+
+ /* An even longer source string is truncated as well, and the total
+ length is returned. */
+ memset (&s, '@', sizeof (s));
+ strcpy (s.buf1, "Hello,");
+ TEST_COMPARE (strlcat (s.buf1, " world!!!!!!!!", sizeof (s.buf1)), 20);
+ TEST_COMPARE_BLOB (&s, sizeof (s),
+ "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
+
+ /* A destination string which is not NUL-terminated does not result
+ in any changes to the buffer. */
+ memset (&s, '@', sizeof (s));
+ memset (s.buf1, '$', sizeof (s.buf1));
+ TEST_COMPARE (strlcat (s.buf1, "", sizeof (s.buf1)), 16);
+ TEST_COMPARE_BLOB (&s, sizeof (s), "$$$$$$$$$$$$$$$$@@@@@@@@@@@@@@@@", 32);
+ TEST_COMPARE (strlcat (s.buf1, "Hello!", sizeof (s.buf1)), 22);
+ TEST_COMPARE_BLOB (&s, sizeof (s), "$$$$$$$$$$$$$$$$@@@@@@@@@@@@@@@@", 32);
+ TEST_COMPARE (strlcat (s.buf1, "Hello, world!!!!!!!!", sizeof (s.buf1)), 36);
+ TEST_COMPARE_BLOB (&s, sizeof (s), "$$$$$$$$$$$$$$$$@@@@@@@@@@@@@@@@", 32);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
new file mode 100644
@@ -0,0 +1,68 @@
+/* Test the strlcpy function.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ struct {
+ char buf1[16];
+ char buf2[16];
+ } s;
+
+ /* Nothing is written to the destination if its size is 0. */
+ memset (&s, '@', sizeof (s));
+ TEST_COMPARE (strlcpy (s.buf1, "Hello!", 0), 6);
+ TEST_COMPARE_BLOB (&s, sizeof (s), "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
+
+ /* No bytes are are modified in the target buffer if the source
+ string is short enough. */
+ memset (&s, '@', sizeof (s));
+ TEST_COMPARE (strlcpy (s.buf1, "Hello!", sizeof (s.buf1)), 6);
+ TEST_COMPARE_BLOB (&s, sizeof (s), "Hello!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
+
+ /* A source string which fits exactly into the destination buffer is
+ not truncated. */
+ memset (&s, '@', sizeof (s));
+ TEST_COMPARE (strlcpy (s.buf1, "Hello, world!!!", sizeof (s.buf1)), 15);
+ TEST_COMPARE_BLOB (&s, sizeof (s),
+ "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
+
+ /* A source string one character longer than the destination buffer
+ is truncated by one character. The untruncated source length is
+ returned. */
+ memset (&s, '@', sizeof (s));
+ TEST_COMPARE (strlcpy (s.buf1, "Hello, world!!!!", sizeof (s.buf1)), 16);
+ TEST_COMPARE_BLOB (&s, sizeof (s),
+ "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
+
+ /* An even longer source string is truncated as well, and the
+ original length is returned. */
+ memset (&s, '@', sizeof (s));
+ TEST_COMPARE (strlcpy (s.buf1, "Hello, world!!!!!!!!", sizeof (s.buf1)), 20);
+ TEST_COMPARE_BLOB (&s, sizeof (s),
+ "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@", 32);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
@@ -2326,6 +2326,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2665,3 +2665,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
@@ -2774,6 +2774,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2426,3 +2426,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
@@ -546,6 +546,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
@@ -543,6 +543,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
@@ -2702,3 +2702,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
@@ -2651,6 +2651,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2835,6 +2835,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2600,6 +2600,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2186,3 +2186,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
@@ -547,6 +547,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
GLIBC_2.4 _IO_2_1_stdin_ D 0x98
@@ -2778,6 +2778,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2751,3 +2751,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
@@ -2748,3 +2748,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
@@ -2743,6 +2743,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2741,6 +2741,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2749,6 +2749,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2651,6 +2651,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2790,3 +2790,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
@@ -2172,3 +2172,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
@@ -2817,6 +2817,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2850,6 +2850,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2571,6 +2571,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2885,3 +2885,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
@@ -2428,3 +2428,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
@@ -2628,3 +2628,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
@@ -2815,6 +2815,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2608,6 +2608,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2658,6 +2658,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2655,6 +2655,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2810,6 +2810,10 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2623,6 +2623,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2574,6 +2574,10 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2680,3 +2680,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 __strlcat_chk F
+GLIBC_2.38 __strlcpy_chk F
+GLIBC_2.38 strlcat F
+GLIBC_2.38 strlcpy F