This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] Add strlcpy, strlcat [BZ #178]
- From: Florian Weimer <fweimer at redhat dot com>
- To: GNU C Library <libc-alpha at sourceware dot org>
- Date: Fri, 16 Jun 2017 12:25:38 +0200
- Subject: [PATCH] Add strlcpy, strlcat [BZ #178]
- Authentication-results: sourceware.org; auth=none
- Authentication-results: ext-mx03.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com
- Authentication-results: ext-mx03.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=fweimer at redhat dot com
- Dkim-filter: OpenDKIM Filter v2.11.0 mx1.redhat.com A50597FD59
- Dmarc-filter: OpenDMARC Filter v1.3.2 mx1.redhat.com A50597FD59
I want to start again the discussion to include strlcpy and strlcat in
glibc. The attached patch has been rebased to current master (changing
the symbol versions to GLIBC_2.26).
I don't think there are any technical issues with the patch left, so the
remaining question is whether we can reach consensus.
Thanks,
Florian
Implement strlcpy and strlcat [BZ #178]
This change may cause application code not to compile anymore, but
strlcpy is in the implementation namespace (per C11 7.31.13), so this
is an application issue.
2017-06-16 Paul Eggert <eggert@cs.ucla.edu>
Document strlcpy, strlcat
[BZ #178]
This patch was partly derived from text by Florian Weimer in:
https://sourceware.org/ml/libc-alpha/2015-12/msg00593.html
* manual/string.texi (Truncating Strings): New functions from
OpenBSD.
2017-06-16 Florian Weimer <fweimer@redhat.com>
[BZ #178]
* string/Makefile (routines): Add strlcpy, strlcat.
(tests): Add tst-strlcpy, tst-strlcat.
* string/Versions (2.26): Export strlcpy, strlcat.
* string/string.h (strlcpy, strlcat): Add.
* string/bits/string3.h (__warn_strlcpy_size_zero)
(__warn_strlcpy_size_large, __strlcpy_chk, __strlcpy_alias, strlcpy)
(__warn_strlcat_size_zero, __warn_strlcat_size_large)
(__strlcat_chk, __strlcat_alias, strlcat): Add.
* string/strlcpy.c: New file.
* string/strlcat.c: New file.
* string/tst-strlcpy.c: Likewise.
* string/tst-strlcat.c: Likewise.
* include/string.h (strlcpy, strlcat): Declare as hidden.
* debug/Makefile (routines): Add strlcpy_chk, strlcat_chk.
* debug/Versions (2.26): Export __strlcpy_chk, __strlcat_chk.
* debug/strlcpy_chk.c: New file.
* debug/strlcat_chk.c: New file.
* debug/tst-chk1.c (doit): Test strlcpy, strlcat.
* sysdeps/*/libc.abilist: Add strlcpy, __strlcpy_chk, strlcat,
__strlcat_chk.
diff --git a/NEWS b/NEWS
index 804c1b9..f871f83 100644
--- a/NEWS
+++ b/NEWS
@@ -98,6 +98,9 @@ Version 2.26
* The tunables feature is now enabled by default. This allows users to tweak
behavior of the GNU C Library using the GLIBC_TUNABLES environment variable.
+* The GNU C Library now includes implementations of strlcpy and strlcat.
+ Contributed by Florian Weimer (Red Hat).
+
Security related changes:
* The DNS stub resolver limits the advertised UDP buffer size to 1200 bytes,
diff --git a/debug/Makefile b/debug/Makefile
index cd4975c..b36e23b 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -30,6 +30,7 @@ headers := execinfo.h
routines = backtrace backtracesyms backtracesymsfd noophooks \
memcpy_chk memmove_chk mempcpy_chk memset_chk stpcpy_chk \
strcat_chk strcpy_chk strncat_chk strncpy_chk stpncpy_chk \
+ strlcpy_chk strlcat_chk \
sprintf_chk vsprintf_chk snprintf_chk vsnprintf_chk \
printf_chk fprintf_chk vprintf_chk vfprintf_chk \
gets_chk chk_fail readonly-area fgets_chk fgets_u_chk \
diff --git a/debug/Versions b/debug/Versions
index a6628db..3dd0f7f 100644
--- a/debug/Versions
+++ b/debug/Versions
@@ -57,6 +57,9 @@ libc {
}
GLIBC_2.25 {
__explicit_bzero_chk;
+ GLIBC_2.26 {
+ __strlcpy_chk;
+ __strlcat_chk;
}
GLIBC_PRIVATE {
__fortify_fail;
diff --git a/debug/strlcat_chk.c b/debug/strlcat_chk.c
new file mode 100644
index 0000000..c7b9f03
--- /dev/null
+++ b/debug/strlcat_chk.c
@@ -0,0 +1,32 @@
+/* Fortified version of strlcat.
+ Copyright (C) 2016 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <string.h>
+#include <memcopy.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);
+}
diff --git a/debug/strlcpy_chk.c b/debug/strlcpy_chk.c
new file mode 100644
index 0000000..842f44f
--- /dev/null
+++ b/debug/strlcpy_chk.c
@@ -0,0 +1,32 @@
+/* Fortified version of strlcpy.
+ Copyright (C) 2016 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <string.h>
+#include <memcopy.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);
+}
diff --git a/debug/tst-chk1.c b/debug/tst-chk1.c
index 60c8e1e..4a87a2e 100644
--- a/debug/tst-chk1.c
+++ b/debug/tst-chk1.c
@@ -509,6 +509,16 @@ do_test (void)
strncpy (a.buf1 + (O + 6), "X", l0 + 4);
CHK_FAIL_END
+ CHK_FAIL_START
+ strlcpy (buf, "", sizeof (buf) + 1);
+ 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);
@@ -532,6 +542,18 @@ do_test (void)
CHK_FAIL_START
strncat (a.buf1, "ZYXWV", l0 + 3);
CHK_FAIL_END
+
+ buf[0] = '\0';
+ CHK_FAIL_START
+ strlcat (buf, "ZYXWV", sizeof (buf) + 1);
+ CHK_FAIL_END
+
+ {
+ buf[0] = '\0';
+ char *volatile buf2 = buf;
+ if (strlcat (buf2, "a", sizeof (buf) + 1) != 1)
+ FAIL ();
+ }
#endif
diff --git a/include/string.h b/include/string.h
index 2bf2944..ad7c217 100644
--- a/include/string.h
+++ b/include/string.h
@@ -78,6 +78,8 @@ extern __typeof (strncasecmp_l) __strncasecmp_l;
libc_hidden_proto (__mempcpy)
libc_hidden_proto (__stpcpy)
libc_hidden_proto (__stpncpy)
+libc_hidden_proto (strlcpy)
+libc_hidden_proto (strlcat)
libc_hidden_proto (__rawmemchr)
libc_hidden_proto (__strcasecmp)
libc_hidden_proto (__strcasecmp_l)
diff --git a/manual/string.texi b/manual/string.texi
index ac02c6d..963c587 100644
--- a/manual/string.texi
+++ b/manual/string.texi
@@ -1071,6 +1071,79 @@ processing text. Also, this function has significant performance
issues. @xref{Concatenating Strings}.
@end deftypefun
+@comment string.h
+@comment BSD
+@deftypefun size_t strlcpy (char *restrict @var{to}, const char *restrict @var{from}, size_t @var{size})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+This function is similar to @code{strcpy}, but copies at most
+@var{size} bytes from the string @var{from} into the destination
+array @var{to}, including a terminating null byte.
+
+If @var{size} is greater than the length of the string @var{from},
+this function copies all of the string @var{from} to the destination
+array @var{to}, including the terminating null byte. Like other
+string functions such as @code{strcpy}, but unlike @code{strncpy}, any
+remaining bytes in the destination array remain unchanged.
+
+If @var{size} is nonzero and less than or equal to the the length of the string
+@var{from}, this function copies only the first @samp{@var{size} - 1}
+bytes to the destination array @var{to}, and writes a terminating null
+byte to the last byte of the array.
+
+The return value @var{result} of @code{strlcpy} is the length of the
+string @var{from}. This means that @samp{@var{result} >= @var{size}} is
+true whenever truncation occurs.
+
+The behavior of @code{strlcpy} is undefined if @var{size} is zero, or if
+the source string and the first @var{size} bytes of the destination
+array overlap.
+
+As noted below, this function is generally a poor choice for processing
+text. Unlike @code{strncpy}, @code{strlcpy} requires @var{size} to be
+nonzero and the source string to be null-terminated, computes the
+source string's length, ensures that the destination is
+null-terminated, and does not fill the remaining part of the destination
+with null bytes.
+
+This function is derived from OpenBSD.
+@end deftypefun
+
+@comment string.h
+@comment BSD
+@deftypefun size_t strlcat (char *restrict @var{to}, const char *restrict @var{from}, size_t @var{size})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+This function appends the string @var{from} to the
+string @var{to}, limiting the total size of the result string at
+@var{to} (including the null terminator) to @var{size}.
+
+This function copies as much as possible of the string @var{from} into
+the array at @var{to} of @var{size} bytes, starting at the terminating
+null byte of the original string @var{to}. In effect, this appends
+the string @var{from} to the string @var{to}. Although the resulting
+string will contain a null terminator, it can be truncated (not all
+bytes in @var{from} are copied).
+
+This function returns the sum of the original length of @var{to} and
+the length of @var{from}. This means that truncation occurs unless
+the returned value is less than @var{size}.
+
+The behavior is undefined if the array at @var{to} does not contain a
+null byte in its first @var{size} bytes, or if the source string and the
+first @var{size} bytes of @var{to} overlap.
+
+As noted below, this function is generally a poor choice for processing
+text. Also, this function has significant performance issues.
+@xref{Concatenating Strings}. Unlike @code{strncat}, @var{size}
+specifies the maximum total size of the result string (including its
+null terminator), not the number of bytes copied from the source string
+@var{from}.
+Also, unlike @code{strncat} this function requires the source and
+destination to be null-terminated, computes the source string's
+length, and keeps the destination null-terminated.
+
+This function is derived from OpenBSD.
+@end deftypefun
+
Because these functions can abruptly truncate strings or wide strings,
they are generally poor choices for processing text. When coping or
concatening multibyte strings, they can truncate within a multibyte
diff --git a/string/Makefile b/string/Makefile
index 8d0d6b0..526ee4b 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -42,7 +42,8 @@ routines := strcat strchr strcmp strcoll strcpy strcspn \
addsep replace) \
envz basename \
strcoll_l strxfrm_l string-inlines memrchr \
- xpg-strerror strerror_l explicit_bzero
+ xpg-strerror strerror_l explicit_bzero \
+ strlcpy strlcat
strop-tests := memchr memcmp memcpy memmove mempcpy memset memccpy \
stpcpy stpncpy strcat strchr strcmp strcpy strcspn \
@@ -57,7 +58,7 @@ tests := tester inl-tester noinl-tester testcopy test-ffs \
bug-strtok1 $(addprefix test-,$(strop-tests)) \
bug-envz1 tst-strxfrm2 tst-endian tst-svc2 \
tst-strtok_r bug-strcoll2 tst-cmp tst-xbzero-opt \
- test-endian-types
+ test-endian-types tst-strlcpy tst-strlcat
# This test allocates a lot of memory and can run for a long time.
xtests = tst-strcoll-overflow
diff --git a/string/Versions b/string/Versions
index 9b709d1..65368c2 100644
--- a/string/Versions
+++ b/string/Versions
@@ -85,4 +85,8 @@ libc {
GLIBC_2.25 {
explicit_bzero;
}
+ GLIBC_2.26 {
+ strlcpy;
+ strlcat;
+ }
}
diff --git a/string/bits/string3.h b/string/bits/string3.h
index 738226d..8e85a0d 100644
--- a/string/bits/string3.h
+++ b/string/bits/string3.h
@@ -40,6 +40,8 @@ __warndecl (__warn_memset_zero_len,
# undef stpcpy
# endif
# ifdef __USE_MISC
+# undef strlcpy
+# undef strlcat
# undef bcopy
# undef bzero
# endif
@@ -154,3 +156,59 @@ __NTH (strncat (char *__restrict __dest, const char *__restrict __src,
{
return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest));
}
+
+#ifdef __USE_MISC
+__warndecl (__warn_strlcpy_size_zero,
+ "strlcpy used with a size argument of zero");
+__warndecl (__warn_strlcpy_size_large,
+ "strlcpy used with a size argument which is too large");
+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 __len))
+{
+ if (__builtin_constant_p (__len == 0) && __len == 0)
+ {
+ __warn_strlcpy_size_zero ();
+ return 0;
+ }
+ if (__builtin_constant_p (__len > __bos (__dest)) && __len > __bos (__dest))
+ __warn_strlcpy_size_large ();
+ if (__builtin_constant_p (__bos (__dest) == (size_t) -1)
+ && __bos (__dest) == (size_t) -1)
+ return __strlcpy_alias (__dest, __src, __len);
+ return __strlcpy_chk (__dest, __src, __len, __bos (__dest));
+}
+
+__warndecl (__warn_strlcat_size_zero,
+ "strlcat used with a size argument of zero");
+__warndecl (__warn_strlcat_size_large,
+ "strlcat used with a size argument which is too large");
+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 __len))
+{
+ if (__builtin_constant_p (__len == 0) && __len == 0)
+ {
+ __warn_strlcat_size_zero ();
+ return strlen (__src);
+ }
+ if (__builtin_constant_p (__len > __bos (__dest)) && __len > __bos (__dest))
+ __warn_strlcat_size_large ();
+ if (__builtin_constant_p (__bos (__dest) == (size_t) -1)
+ && __bos (__dest) == (size_t) -1)
+ return __strlcat_alias (__dest, __src, __len);
+ return __strlcat_chk (__dest, __src, __len, __bos (__dest));
+}
+#endif
diff --git a/string/string.h b/string/string.h
index d1a2746..8af9f1e 100644
--- a/string/string.h
+++ b/string/string.h
@@ -460,6 +460,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 ((2));
+
+/* 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 ((2));
+#endif
+
#ifdef __USE_GNU
/* Compare S1 and S2 as strings holding name & indices/version numbers. */
extern int strverscmp (const char *__s1, const char *__s2)
diff --git a/string/strlcat.c b/string/strlcat.c
new file mode 100644
index 0000000..fbee540
--- /dev/null
+++ b/string/strlcat.c
@@ -0,0 +1,60 @@
+/* Append a null-terminated string to another string, with length checking.
+ Copyright (C) 2016 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+#include <string.h>
+
+#undef strlcat
+
+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)
diff --git a/string/strlcpy.c b/string/strlcpy.c
new file mode 100644
index 0000000..c04c1d4
--- /dev/null
+++ b/string/strlcpy.c
@@ -0,0 +1,47 @@
+/* Copy a null-terminated string to a fixed-size buffer, with length checking.
+ Copyright (C) 2016 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <string.h>
+
+#undef strlcpy
+
+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)
diff --git a/string/tst-strlcat.c b/string/tst-strlcat.c
new file mode 100644
index 0000000..2e841af
--- /dev/null
+++ b/string/tst-strlcat.c
@@ -0,0 +1,93 @@
+/* Test the strlcat function.
+ Copyright (C) 2016 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define CHECK(cond) \
+ if (!(cond)) \
+ { \
+ printf ("%s:%d: FAIL\n", __FILE__, __LINE__); \
+ exit (1); \
+ }
+
+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));
+ CHECK (strlcat (s.buf1, "", 0) == 0);
+ CHECK (memcmp (&s, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", sizeof (s)) == 0);
+ CHECK (strlcat (s.buf1, "Hello!", 0) == 6);
+ CHECK (memcmp (&s, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", sizeof (s)) == 0);
+ CHECK (strlcat (NULL, "Hello!", 0) == 6);
+
+ /* No bytes are are modified in the target buffer if the source
+ string is short enough. */
+ memset (&s, '@', sizeof (s));
+ strcpy (s.buf1, "He");
+ CHECK (strlcat (s.buf1, "llo!", sizeof (s.buf1)) == 6);
+ CHECK (memcmp (&s, "Hello!\0@@@@@@@@@@@@@@@@@@@@@@@@@", sizeof (s)) == 0);
+
+ /* A source string which fits exactly into the destination buffer is
+ not truncated. */
+ memset (&s, '@', sizeof (s));
+ strcpy (s.buf1, "H");
+ CHECK (strlcat (s.buf1, "ello, world!!!", sizeof (s.buf1)) == 15);
+ CHECK (memcmp (&s, "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@",
+ sizeof (s)) == 0);
+
+ /* 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");
+ CHECK (strlcat (s.buf1, ", world!!!!", sizeof (s.buf1)) == 16);
+ CHECK (memcmp (&s, "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@",
+ sizeof (s)) == 0);
+
+ /* An even longer source string is truncated as well, and the total
+ length is returned. */
+ memset (&s, '@', sizeof (s));
+ strcpy (s.buf1, "Hello,");
+ CHECK (strlcat (s.buf1, " world!!!!!!!!", sizeof (s.buf1)) == 20);
+ CHECK (memcmp (&s, "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@",
+ sizeof (s)) == 0);
+
+ /* 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));
+ CHECK (strlcat (s.buf1, "", sizeof (s.buf1)) == 16);
+ CHECK (memcmp (&s, "$$$$$$$$$$$$$$$$@@@@@@@@@@@@@@@@", sizeof (s)) == 0);
+ CHECK (strlcat (s.buf1, "Hello!", sizeof (s.buf1)) == 22);
+ CHECK (memcmp (&s, "$$$$$$$$$$$$$$$$@@@@@@@@@@@@@@@@", sizeof (s)) == 0);
+ CHECK (strlcat (s.buf1, "Hello, world!!!!!!!!", sizeof (s.buf1)) == 36);
+ CHECK (memcmp (&s, "$$$$$$$$$$$$$$$$@@@@@@@@@@@@@@@@", sizeof (s)) == 0);
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
diff --git a/string/tst-strlcpy.c b/string/tst-strlcpy.c
new file mode 100644
index 0000000..8635288
--- /dev/null
+++ b/string/tst-strlcpy.c
@@ -0,0 +1,77 @@
+/* Test the strlcpy function.
+ Copyright (C) 2016 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define CHECK(cond) \
+ if (!(cond)) \
+ { \
+ printf ("%s:%d: FAIL\n", __FILE__, __LINE__); \
+ exit (1); \
+ }
+
+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));
+ CHECK (strlcpy (s.buf1, "Hello!", 0) == 6);
+ CHECK (memcmp (&s, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", sizeof (s)) == 0);
+ CHECK (strlcpy (NULL, "Hello!", 0) == 6);
+
+ /* No bytes are are modified in the target buffer if the source
+ string is short enough. */
+ memset (&s, '@', sizeof (s));
+ CHECK (strlcpy (s.buf1, "Hello!", sizeof (s.buf1)) == 6);
+ CHECK (memcmp (&s, "Hello!\0@@@@@@@@@@@@@@@@@@@@@@@@@", sizeof (s)) == 0);
+
+ /* A source string which fits exactly into the destination buffer is
+ not truncated. */
+ memset (&s, '@', sizeof (s));
+ CHECK (strlcpy (s.buf1, "Hello, world!!!", sizeof (s.buf1)) == 15);
+ CHECK (memcmp (&s, "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@",
+ sizeof (s)) == 0);
+
+ /* 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));
+ CHECK (strlcpy (s.buf1, "Hello, world!!!!", sizeof (s.buf1)) == 16);
+ CHECK (memcmp (&s, "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@",
+ sizeof (s)) == 0);
+
+ /* An even longer source string is truncated as well, and the
+ original length is returned. */
+ memset (&s, '@', sizeof (s));
+ CHECK (strlcpy (s.buf1, "Hello, world!!!!!!!!", sizeof (s.buf1)) == 20);
+ CHECK (memcmp (&s, "Hello, world!!!\0@@@@@@@@@@@@@@@@@@@@@@@@@",
+ sizeof (s)) == 0);
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 81e4fe9..368b57e 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2098,8 +2098,12 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index fab7331..e7c3155 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2009,11 +2009,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index d2a206a..07f58ea 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -99,11 +99,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.4 GLIBC_2.4 A
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 24bb730..c78467b 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1863,11 +1863,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 2ff1998..f46f425 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2021,11 +2021,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 39ccf2b..f3de373 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1885,11 +1885,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index b594ebd..6160252 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -100,11 +100,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.4 GLIBC_2.4 A
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index a36739d..86348c0 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1977,11 +1977,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 16aa254..9dcc6c5 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2098,8 +2098,12 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 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 907ab33..13a26e5 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1952,11 +1952,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 36ee235..c712066 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1950,11 +1950,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 783aa73..2c572dd 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1948,11 +1948,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index e1275df..011cc96 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1943,11 +1943,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index be25228..3be1d17 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2139,8 +2139,12 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 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 e213895..c16d5a6 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1981,11 +1981,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index d25aefd..be7cd7a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1986,11 +1986,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 5eb056b..be70578 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -100,11 +100,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 _Exit F
GLIBC_2.3 _IO_2_1_stderr_ D 0xe0
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 63d33e8..d64515c 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1981,11 +1981,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index b1b2b29..b739897 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1882,11 +1882,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index f3a70a0..50b901d 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1867,11 +1867,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 8c4c2e5..ba02e87 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1973,11 +1973,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 1653164..416c198 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1911,11 +1911,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index 41647d4..7affded 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2105,8 +2105,12 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index 1088923..b2250e9 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2105,8 +2105,12 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index 41647d4..7affded 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2105,8 +2105,12 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 513524d..13b4fc0 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1862,11 +1862,15 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 0c557e9..6d46187 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2105,8 +2105,12 @@ GLIBC_2.25 strfromd F
GLIBC_2.25 strfromf F
GLIBC_2.25 strfroml F
GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 __strlcat_chk F
+GLIBC_2.26 __strlcpy_chk F
GLIBC_2.26 preadv2 F
GLIBC_2.26 preadv64v2 F
GLIBC_2.26 pwritev2 F
GLIBC_2.26 pwritev64v2 F
GLIBC_2.26 reallocarray F
+GLIBC_2.26 strlcat F
+GLIBC_2.26 strlcpy F