[v8] Implement strlcpy and strlcat [BZ #178]

Message ID 56902FA4.7070002@redhat.com
State Superseded
Headers

Commit Message

Florian Weimer Jan. 8, 2016, 9:52 p.m. UTC
  This version incorporates Paul's latest documentation changes.

I also adjusted the copyright years to 2016.

Florian
  

Comments

Alexander Cherepanov Jan. 11, 2016, midnight UTC | #1
On 2016-01-09 00:52, Florian Weimer wrote:
> +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';
> +    }
> +
> +  /* The sum cannot wrap around because both strings would be larger
> +     than half of the address space, which is not possible due to
> +     the restrict qualifier.  */
> +  _Static_assert (sizeof (uintptr_t) == sizeof (size_t),
> +		  "theoretical maximum object size covers address space");
> +  return dest_length + src_length;
> +}

First, I don't think the last comment is fully accurate -- both strings 
are not required to be larger than half of the address space each, 1.5GB 
and 3GB are enough for wrapping with 32-bit size_t.

Second, AIUI the full story is like this: strlcat (as documented in the 
latest version) requires @var{to} to contain a null byte in its first 
@var{size} bytes, hence @var{to} and @var{from} both being a sequence of 
non-nulls followed by a mandatory null can overlap only when their 
trailing nulls are the same. But the trailing null in @var{to} is 
overwritten while the trailing null in @var{from} is read which 
contradicts the restrict qualifier. Hence the strings don't overlap.

If you permit @var{to} to be non-null-terminated the situation is worse 
-- it doesn't write anything and resrict doesn't come into play. Then 
the following is defined and should return 5GB on 32-bit arch:

   size_t gb = (size_t)1024 * 1024 * 1024;
   s = malloc(3 * gb);
   memset(s, 'A', 3 * gb);
   strlcat(s, s, 2 * gb);
  
Paul Eggert Jan. 11, 2016, 6:22 a.m. UTC | #2
Alexander Cherepanov wrote:
>> +  /* The sum cannot wrap around because both strings would be larger
>> +     than half of the address space, which is not possible due to
>> +     the restrict qualifier.  */
>> +  _Static_assert (sizeof (uintptr_t) == sizeof (size_t),
>> +          "theoretical maximum object size covers address space");
>> +  return dest_length + src_length;
>> +}
>
> First, I don't think the last comment is fully accurate -- both strings are not
> required to be larger than half of the address space each, 1.5GB and 3GB are
> enough for wrapping with 32-bit size_t.

Yes, the comment could be changed to something like this:

   /* The API for this function says behavior is undefined if the source string
      and destination array overlap.  The following sanity check succeeds
      on conventional architectures with flat address spaces, where the sum
      of the two lengths cannot wrap around when there is no overlap.  */

> If you permit @var{to} to be non-null-terminated the situation is worse

Yes, it's one more nail in that particular coffin.
  

Patch

2016-01-08  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 BSD.

2016-01-08  Florian Weimer  <fweimer@redhat.com>

	[BZ #178]
	* string/Makefile (routines): Add strlcpy, strlcat.
	(tests): Add tst-strlcpy, tst-strlcat.
	* string/Versions (2.23): Export strlcpy, strlcat.
	* string/string.h (strlcpy, strlcat): Add.
	* string/bits/string3.h (__warn_strlcpy_size_zero)
	(__warn_strlcpy_size_large, __strlcpy_chk)
	(__warn_strlcat_size_zero, __warn_strlcat_size_large)
	(__strlcat_chk): 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.
	* manual/string.texi (Truncating Strings while Copying): Document
	strlcpy, strlcat.  Add reference to the strncpy documentation.
	* debug/Makefile (routines): Add strlcpy_chk, strlcat_chk.
	* debug/Versions (2.23): 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 93c09be..d098bb8 100644
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,9 @@  Version 2.23
   multi-threaded application which erroneously closes and reuses the netlink
   file descriptor while it is used by getaddrinfo.
 
+* The GNU C Library now includes implementations of strlcpy and strlcat.
+  Contributed by Florian Weimer (Red Hat).
+
 * A defect in the malloc implementation, present since glibc 2.15 (2012) or
   glibc 2.10 via --enable-experimental-malloc (2009), could result in the
   unnecessary serialization of memory allocation requests across threads.
diff --git a/debug/Makefile b/debug/Makefile
index 6b5f31e..6a915a7 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 0482c85..8d807a2 100644
--- a/debug/Versions
+++ b/debug/Versions
@@ -55,6 +55,10 @@  libc {
   GLIBC_2.16 {
     __poll_chk; __ppoll_chk;
   }
+  GLIBC_2.23 {
+    __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 4f968ee..63964b6 100644
--- a/debug/tst-chk1.c
+++ b/debug/tst-chk1.c
@@ -415,6 +415,10 @@  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
+
 # if !defined __cplusplus || defined __va_arg_pack
   CHK_FAIL_START
   sprintf (a.buf1 + (O + 7), "%d", num1);
@@ -438,6 +442,11 @@  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
 #endif
 
 
diff --git a/include/string.h b/include/string.h
index a684fd9..2b3f054 100644
--- a/include/string.h
+++ b/include/string.h
@@ -73,6 +73,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 016fd0b..3d2fff3 100644
--- a/manual/string.texi
+++ b/manual/string.texi
@@ -1099,6 +1099,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 BSD.
+@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 BSD.
+@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 9c87419..5a404e9 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -41,7 +41,7 @@  routines	:= strcat strchr strcmp strcoll strcpy strcspn		\
 				     addsep replace)			\
 		   envz basename					\
 		   strcoll_l strxfrm_l string-inlines memrchr		\
-		   xpg-strerror strerror_l
+		   xpg-strerror strerror_l strlcpy strlcat
 
 strop-tests	:= memchr memcmp memcpy memmove mempcpy memset memccpy	\
 		   stpcpy stpncpy strcat strchr strcmp strcpy strcspn	\
@@ -54,7 +54,7 @@  tests		:= tester inl-tester noinl-tester testcopy test-ffs	\
 		   tst-strtok tst-strxfrm bug-strcoll1 tst-strfry	\
 		   bug-strtok1 $(addprefix test-,$(strop-tests))	\
 		   bug-envz1 tst-strxfrm2 tst-endian tst-svc2		\
-		   tst-strtok_r bug-strcoll2
+		   tst-strtok_r bug-strcoll2 tst-strlcpy tst-strlcat
 
 xtests = tst-strcoll-overflow
 
diff --git a/string/Versions b/string/Versions
index 59bf35a..92804b7 100644
--- a/string/Versions
+++ b/string/Versions
@@ -80,4 +80,8 @@  libc {
   GLIBC_2.6 {
     strerror_l;
   }
+  GLIBC_2.23 {
+    strlcpy;
+    strlcat;
+  }
 }
diff --git a/string/bits/string3.h b/string/bits/string3.h
index dd8db68..c543f41 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
@@ -155,3 +157,53 @@  __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;
+
+__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 (__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;
+
+__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 (__dest, __src, __len);
+  return __strlcat_chk (__dest, __src, __len, __bos (__dest));
+}
+#endif
diff --git a/string/string.h b/string/string.h
index 1f3e348..7cd6f8f 100644
--- a/string/string.h
+++ b/string/string.h
@@ -574,6 +574,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..dadd102
--- /dev/null
+++ b/string/strlcat.c
@@ -0,0 +1,57 @@ 
+/* 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';
+    }
+
+  /* The sum cannot wrap around because both strings would be larger
+     than half of the address space, which is not possible due to
+     the restrict qualifier.  */
+  _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/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist
index 561441e..41db1bc 100644
--- a/sysdeps/arm/nacl/libc.abilist
+++ b/sysdeps/arm/nacl/libc.abilist
@@ -1834,3 +1834,7 @@  GLIBC_2.22 wprintf F
 GLIBC_2.22 write F
 GLIBC_2.22 writev F
 GLIBC_2.22 wscanf F
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 strlcpy F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 5799239..2f3268a 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2082,8 +2082,12 @@  GLIBC_2.18 _mcount F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 strlcpy F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 0fa4ee9..e7138cb 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -1993,11 +1993,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 db9fa35..cc7de2b 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -83,11 +83,15 @@  GLIBC_2.18 __cxa_thread_atexit_impl F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 1d30644..31564cc 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1847,11 +1847,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 8f3502d..9fe3fbf 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2005,11 +2005,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 921ec55..7799a8b 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1869,11 +1869,15 @@  GLIBC_2.2.6 getunwind F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 019095b..8dd73d7 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -84,11 +84,15 @@  GLIBC_2.18 __cxa_thread_atexit_impl F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 a999a48..1838a39 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1961,11 +1961,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 0a08bba..b9b55d7 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2082,8 +2082,12 @@  GLIBC_2.18 xprt_unregister F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 2ab9e94..7dd6302 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1936,11 +1936,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 b9b4b74..23b7946 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1934,11 +1934,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 14e1236..873ba2d 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1932,11 +1932,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 53e0c9a..53058f3 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1927,11 +1927,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 dff1ee9..8860d27 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2123,8 +2123,12 @@  GLIBC_2.21 xprt_unregister F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 6861846..24de613 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1965,11 +1965,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 fd611aa..2100793 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1970,11 +1970,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index a97bd43..3c05524 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2170,8 +2170,12 @@  GLIBC_2.18 __cxa_thread_atexit_impl F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 strlcpy F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 00772cb..d211f76 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -84,11 +84,15 @@  GLIBC_2.18 __cxa_thread_atexit_impl F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 05cb85e..40f0fdd 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1965,11 +1965,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 1af185f..0bf57c5 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1866,11 +1866,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 e128692..839de3c 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1851,11 +1851,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 eb14113..5844201 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1957,11 +1957,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 91b97ef..d43ebbb 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1895,11 +1895,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 ffcc4a0..1f8f99d 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2089,8 +2089,12 @@  GLIBC_2.18 __cxa_thread_atexit_impl F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 a66e8ec..3d8abe8 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2089,8 +2089,12 @@  GLIBC_2.18 __cxa_thread_atexit_impl F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 strlcpy F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index ffcc4a0..1f8f99d 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2089,8 +2089,12 @@  GLIBC_2.18 __cxa_thread_atexit_impl F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 c6e3cd4..c76d112 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1846,11 +1846,15 @@  GLIBC_2.2.6 __nanosleep F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 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 04dc8e4..59a835d 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2089,8 +2089,12 @@  GLIBC_2.18 __cxa_thread_atexit_impl F
 GLIBC_2.22 GLIBC_2.22 A
 GLIBC_2.22 fmemopen F
 GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcat_chk F
+GLIBC_2.23 __strlcpy_chk F
 GLIBC_2.23 fts64_children F
 GLIBC_2.23 fts64_close F
 GLIBC_2.23 fts64_open F
 GLIBC_2.23 fts64_read F
 GLIBC_2.23 fts64_set F
+GLIBC_2.23 strlcat F
+GLIBC_2.23 strlcpy F