[v6] Implement strlcpy [BZ #178]
diff mbox

Message ID 564B3494.4040209@redhat.com
State New
Headers show

Commit Message

Florian Weimer Nov. 17, 2015, 2:07 p.m. UTC
On 11/17/2015 06:58 AM, Carlos O'Donell wrote:

>> +size_t
>> +__strlcpy_chk (char *__restrict s1, const char *__restrict s2,
>> +	       size_t n, size_t s1len)
>> +{
> 
> Despite the simplicity I think this should have a comment about
> the invariant being tested.

Fixed.

>> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
>> +This function is similar to @code{strcpy}, but copies at most @var{size}
>> +characters into @var{to}, including the terminating null character.
>> +
>> +If the length of @var{from} is equal to or more than @var{size}, then
>> +@code{strlcpy} copies just the first @samp{@var{size} - 1} characters.
> 
> ... and the null character?

I have slightly reworded this section (--word-diff helps for incremental
review).

>> +static int
>> +do_test (void)
>> +{
>> +  struct {
>> +    char buf1[16];
>> +    char buf2[16];
>> +  } s;
>> +
> 
> This needs more comments.
> 
> Each of these tests needs a comment explaining the intent of the test,
> even a succinct comment is worth a lot to a future maintainer reviewing
> the failed test.

Good point, comments added.

I'm attaching what I hope is the final version.

Regarding attribution in NEWS, we can add that once strlcat is committed. :)

Florian

Comments

Andreas Schwab Nov. 17, 2015, 2:12 p.m. UTC | #1
Florian Weimer <fweimer@redhat.com> writes:

> +  /* Nothing is written to the destiantion if its size is 0.  */

s/ian/ina/

Andreas.
Florian Weimer Nov. 17, 2015, 2:14 p.m. UTC | #2
On 11/17/2015 03:12 PM, Andreas Schwab wrote:
> Florian Weimer <fweimer@redhat.com> writes:
> 
>> +  /* Nothing is written to the destiantion if its size is 0.  */
> 
> s/ian/ina/

Thanks, fixed.

Florian
Carlos O'Donell Nov. 17, 2015, 3:44 p.m. UTC | #3
On 11/17/2015 09:07 AM, Florian Weimer wrote:
> I'm attaching what I hope is the final version.
> 
> Regarding attribution in NEWS, we can add that once strlcat is committed. :)

v6 looks perfect to me.

I think this should get committed and strlcat worked on next.

Have all objections to this patch been addressed?

> diff --git a/debug/strlcpy_chk.c b/debug/strlcpy_chk.c
> index a13bcfe..94bc0a2 100644
> --- a/debug/strlcpy_chk.c
> +++ b/debug/strlcpy_chk.c
> @@ -19,6 +19,8 @@
>  #include <string.h>
>  #include <memcopy.h>
>  
> +/* Check that the user-supplied size does not exceed the
> +   compiler-determined size, and then forward to strlcpy.  */

OK.

>  size_t
>  __strlcpy_chk (char *__restrict s1, const char *__restrict s2,
>  	       size_t n, size_t s1len)
> diff --git a/manual/string.texi b/manual/string.texi
> index b7f94c5..ce4880a 100644
> --- a/manual/string.texi
> +++ b/manual/string.texi
> @@ -590,29 +590,31 @@ destination buffer does not have length zero.
>  @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}
> -characters into @var{to}, including the terminating null character.
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} This function is similar
> +to @code{strcpy}, but copies at most @var{size} characters into the
> +destination buffer @var{to}, including the terminating null character.
> +
> +If @var{size} is zero, nothing is written to @var{to}.
>  
> -If the length of @var{from} is equal to or more than @var{size}, then
> -@code{strlcpy} copies just the first @samp{@var{size} - 1} characters.
> -As a special case, if @var{size} is zero, no bytes are written to
> -@var{to}.
> +If the length of the string @var{from} is equal to or greater than
> +@var{size}, @code{strlcpy} copies only the first @samp{@var{size} - 1}
> +characters to the destination buffer @var{to}, and writes a terminating
> +null character to the last character in the buffer.

OK. Perfect, this is exactly what I wanted to see here.

> -If the length of @var{from} is less than @var{size}, then @code{strlcpy}
> -copies all of @var{from}, followed by a single null character.  Like
> -other string functions such as @code{strcpy}, but unlike @code{strncpy},
> -the remaining characters in the destination buffer, if any, remain
> -unchanged.
> +If the length of @var{from} is less than @var{size}, @code{strlcpy}
> +copies all of the string @var{from} to the destination buffer @var{to},
> +followed by a single null character.  Like other string functions such
> +as @code{strcpy}, but unlike @code{strncpy}, the remaining characters in
> +the destination buffer, if any, remain unchanged.

OK.

>  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 string @var{from} must be null-terminated even if its length exceeds
> -that of the destination buffer.  The behavior of @code{strlcpy} is
> -undefined if the strings overlap or if the source or destination are
> -null pointers.
> +that of the destination buffer specified as @var{size}.  The behavior of
> +@code{strlcpy} is undefined if the strings overlap or if the source or
> +destination are null pointers.

OK.

>  Using @code{strlcpy} as opposed to @code{strcpy} is a way to avoid bugs
>  relating to writing past the end of the allocated space for @var{to}.
> diff --git a/string/tst-strlcpy.c b/string/tst-strlcpy.c
> index b97f591..77b7677 100644
> --- a/string/tst-strlcpy.c
> +++ b/string/tst-strlcpy.c
> @@ -35,24 +35,34 @@ do_test (void)
>      char buf2[16];
>    } s;
>  
> +  /* Nothing is written to the destiantion if its size is 0.  */
>    memset (&s, '@', sizeof (s));
>    CHECK (strlcpy (s.buf1, "Hello!", 0) == 6);
>    CHECK (memcmp (&s, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", sizeof (s)) == 0);
>  
> +  /* 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@@@@@@@@@@@@@@@@@@@@@@@@@",

OK.

Cheers,
Carlos.
Florian Weimer Nov. 17, 2015, 3:48 p.m. UTC | #4
On 11/17/2015 04:44 PM, Carlos O'Donell wrote:
> On 11/17/2015 09:07 AM, Florian Weimer wrote:
>> I'm attaching what I hope is the final version.
>>
>> Regarding attribution in NEWS, we can add that once strlcat is committed. :)
> 
> v6 looks perfect to me.
> 
> I think this should get committed and strlcat worked on next.

Thanks, Carlos.

> Have all objections to this patch been addressed?

Roland, would you please clarify the objection you voiced here?

  <https://sourceware.org/ml/libc-alpha/2015-11/msg00086.html>

I think Rich's comments are spot-on:

  <https://sourceware.org/ml/libc-alpha/2015-11/msg00104.html>

Thanks,
Florian
Rical Jasan Nov. 18, 2015, 9:41 a.m. UTC | #5
On 11/17/2015 06:07 AM, Florian Weimer wrote:
> diff --git a/manual/string.texi b/manual/string.texi
> index 5f8a17e..ce4880a 100644
> --- a/manual/string.texi
> +++ b/manual/string.texi
> @@ -576,17 +576,57 @@ there is no null terminator written into @var{to}.
>  
>  If the length of @var{from} is less than @var{size}, then @code{strncpy}
>  copies all of @var{from}, followed by enough null characters to add up
> -to @var{size} characters in all.  This behavior is rarely useful, but it
> -is specified by the @w{ISO C} standard.
> +to @var{size} characters in all.
>  
>  The behavior of @code{strncpy} is undefined if the strings overlap.
>  
> -Using @code{strncpy} as opposed to @code{strcpy} is a way to avoid bugs
> +Not guaranteeing null termination and always overwriting the entire
> +destination buffer makes @code{strncpy} rarely useful, but this behavior
> +is specified by the @w{ISO C} standard.  See @code{strlcpy} below for an
> +alternative which null-terminates the destination string as long as the
> +destination buffer does not have length zero.
> +@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

The beginning of this line should be moved below the @safety macro.

> +to @code{strcpy}, but copies at most @var{size} characters into the
> +destination buffer @var{to}, including the terminating null character.
> +
> +If @var{size} is zero, nothing is written to @var{to}.
> +
> +If the length of the string @var{from} is equal to or greater than
> +@var{size}, @code{strlcpy} copies only the first @samp{@var{size} - 1}
> +characters to the destination buffer @var{to}, and writes a terminating
> +null character to the last character in the buffer.
> +
> +If the length of @var{from} is less than @var{size}, @code{strlcpy}
> +copies all of the string @var{from} to the destination buffer @var{to},
> +followed by a single null character.  Like other string functions such
> +as @code{strcpy}, but unlike @code{strncpy}, the remaining characters in
> +the destination buffer, if any, remain unchanged.
> +
> +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 string @var{from} must be null-terminated even if its length exceeds
> +that of the destination buffer specified as @var{size}.  The behavior of
> +@code{strlcpy} is undefined if the strings overlap or if the source or
> +destination are null pointers.
> +
> +Using @code{strlcpy} as opposed to @code{strcpy} is a way to avoid bugs
>  relating to writing past the end of the allocated space for @var{to}.
> -However, it can also make your program much slower in one common case:
> -copying a string which is probably small into a potentially large buffer.
> -In this case, @var{size} may be large, and when it is, @code{strncpy} will
> -waste a considerable amount of time copying null characters.
> +Unlike @code{strncpy}, @code{strlcpy} ensures that the destination
> +string is always null-terminated (unless the buffer size is zero), and
> +it does not fill the remaining part of the buffer with null characters.
> +
> +@strong{Note:} GNU programs should not use statically sized buffers for
> +storing strings.  @xref{Semantics, , Writing Robust Programs, standards,
> +The GNU Coding Standards}.  Instead of using @code{strlcpy}, it is
> +usually better to use dynamic memory allocation and functions such as
> +@code{strdup} or @code{asprintf} to construct strings.

A reference to dynamic memory allocation would be suitable here.

>  @end deftypefun
>  
>  @comment wchar.h
> 

Overall, I like this explanation.

> diff --git a/string/tst-strlcpy.c b/string/tst-strlcpy.c
> new file mode 100644
> index 0000000..77b7677
> --- /dev/null
> +++ b/string/tst-strlcpy.c
> @@ -0,0 +1,76 @@

> +#define CHECK(cond)					\
> +  if (!(cond))						\
> +    {							\
> +      printf ("%s:%d: FAIL\n", __FILE__, __LINE__);	\
> +      exit (1);						\
> +    }

The manual taught me to use `exit (EXIT_FAILURE);', but it seems that is
not in vogue:

$ for a in 1 EXIT_FAILURE; do find -name '*.c' | xargs grep "exit ($a)"
| wc -l; done
1896
114

Rical
Florian Weimer Nov. 18, 2015, 10:28 a.m. UTC | #6
On 11/18/2015 10:41 AM, ricaljasan wrote:

>> +@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
> 
> The beginning of this line should be moved below the @safety macro.

Thanks, fixed.

>> +@strong{Note:} GNU programs should not use statically sized buffers for
>> +storing strings.  @xref{Semantics, , Writing Robust Programs, standards,
>> +The GNU Coding Standards}.  Instead of using @code{strlcpy}, it is
>> +usually better to use dynamic memory allocation and functions such as
>> +@code{strdup} or @code{asprintf} to construct strings.
> 
> A reference to dynamic memory allocation would be suitable here.

I added:

better to use dynamic memory allocation {+(@pxref{Unconstrained+}
{+Allocation})+} and functions such as @code{strdup} or @code{asprintf}

Florian

Patch
diff mbox

2015-11-02  Florian Weimer  <fweimer@redhat.com>

	[BZ #178]
	* string/Makefile (routines): Add strlcpy.
	(tests): Add tst-strlcpy.
	* string/Versions (2.21): Export strlcpy.
	* string/strlcpy.c: New file.
	* string/tst-strlcpy.c: Likewise.
	* include/string.h (strlcpy): Declare as hidden.
	* manual/string.texi (Copying and Concatenation): Document
	strlcpy.  Update strncpy documentation.
	* debug/Makefile (routines): Add strlcpy_chk.
	* debug/Versions (2.21): Export __strlcpy_chk.
	* debug/tst-chk1.c (doit): Test strlcpy.
	* debug/strlcpy_chk.c: New file.
	* sysdeps/*/libc.abilist: Add strlcpy, __strlcpy_chk.

diff --git a/NEWS b/NEWS
index 0831d35..aa2fef5 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,8 @@  Version 2.23
   19074, 19076, 19077, 19078, 19079, 19085, 19086, 19088, 19094, 19095,
   19124, 19125, 19129, 19134, 19137, 19156, 19174, 19181.
 
+* The GNU C Library now includes an implementation of strlcpy.
+
 * 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 a383417..f6cebab 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 \
 	    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..60a7aed 100644
--- a/debug/Versions
+++ b/debug/Versions
@@ -55,6 +55,9 @@  libc {
   GLIBC_2.16 {
     __poll_chk; __ppoll_chk;
   }
+  GLIBC_2.23 {
+    __strlcpy_chk;
+  }
   GLIBC_PRIVATE {
     __fortify_fail;
   }
diff --git a/debug/strlcpy_chk.c b/debug/strlcpy_chk.c
new file mode 100644
index 0000000..94bc0a2
--- /dev/null
+++ b/debug/strlcpy_chk.c
@@ -0,0 +1,32 @@ 
+/* Fortified version of strlcpy.
+   Copyright (C) 2015 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 bded583..0805a85 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);
diff --git a/include/string.h b/include/string.h
index a684fd9..82413af 100644
--- a/include/string.h
+++ b/include/string.h
@@ -73,6 +73,7 @@  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 (__rawmemchr)
 libc_hidden_proto (__strcasecmp)
 libc_hidden_proto (__strcasecmp_l)
diff --git a/manual/string.texi b/manual/string.texi
index 5f8a17e..ce4880a 100644
--- a/manual/string.texi
+++ b/manual/string.texi
@@ -576,17 +576,57 @@  there is no null terminator written into @var{to}.
 
 If the length of @var{from} is less than @var{size}, then @code{strncpy}
 copies all of @var{from}, followed by enough null characters to add up
-to @var{size} characters in all.  This behavior is rarely useful, but it
-is specified by the @w{ISO C} standard.
+to @var{size} characters in all.
 
 The behavior of @code{strncpy} is undefined if the strings overlap.
 
-Using @code{strncpy} as opposed to @code{strcpy} is a way to avoid bugs
+Not guaranteeing null termination and always overwriting the entire
+destination buffer makes @code{strncpy} rarely useful, but this behavior
+is specified by the @w{ISO C} standard.  See @code{strlcpy} below for an
+alternative which null-terminates the destination string as long as the
+destination buffer does not have length zero.
+@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} characters into the
+destination buffer @var{to}, including the terminating null character.
+
+If @var{size} is zero, nothing is written to @var{to}.
+
+If the length of the string @var{from} is equal to or greater than
+@var{size}, @code{strlcpy} copies only the first @samp{@var{size} - 1}
+characters to the destination buffer @var{to}, and writes a terminating
+null character to the last character in the buffer.
+
+If the length of @var{from} is less than @var{size}, @code{strlcpy}
+copies all of the string @var{from} to the destination buffer @var{to},
+followed by a single null character.  Like other string functions such
+as @code{strcpy}, but unlike @code{strncpy}, the remaining characters in
+the destination buffer, if any, remain unchanged.
+
+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 string @var{from} must be null-terminated even if its length exceeds
+that of the destination buffer specified as @var{size}.  The behavior of
+@code{strlcpy} is undefined if the strings overlap or if the source or
+destination are null pointers.
+
+Using @code{strlcpy} as opposed to @code{strcpy} is a way to avoid bugs
 relating to writing past the end of the allocated space for @var{to}.
-However, it can also make your program much slower in one common case:
-copying a string which is probably small into a potentially large buffer.
-In this case, @var{size} may be large, and when it is, @code{strncpy} will
-waste a considerable amount of time copying null characters.
+Unlike @code{strncpy}, @code{strlcpy} ensures that the destination
+string is always null-terminated (unless the buffer size is zero), and
+it does not fill the remaining part of the buffer with null characters.
+
+@strong{Note:} GNU programs should not use statically sized buffers for
+storing strings.  @xref{Semantics, , Writing Robust Programs, standards,
+The GNU Coding Standards}.  Instead of using @code{strlcpy}, it is
+usually better to use dynamic memory allocation and functions such as
+@code{strdup} or @code{asprintf} to construct strings.
 @end deftypefun
 
 @comment wchar.h
diff --git a/string/Makefile b/string/Makefile
index ebe9354..0d1fb52 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
 
 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
 
 xtests = tst-strcoll-overflow
 
diff --git a/string/Versions b/string/Versions
index 59bf35a..bd00ca1 100644
--- a/string/Versions
+++ b/string/Versions
@@ -80,4 +80,7 @@  libc {
   GLIBC_2.6 {
     strerror_l;
   }
+  GLIBC_2.23 {
+    strlcpy;
+  }
 }
diff --git a/string/bits/string3.h b/string/bits/string3.h
index 4d11aa6..9f28a73 100644
--- a/string/bits/string3.h
+++ b/string/bits/string3.h
@@ -40,6 +40,7 @@  __warndecl (__warn_memset_zero_len,
 #  undef stpcpy
 # endif
 # ifdef __USE_MISC
+#  undef strlcpy
 #  undef bcopy
 #  undef bzero
 # endif
@@ -155,3 +156,29 @@  __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));
+}
+#endif
diff --git a/string/string.h b/string/string.h
index 3ab7103..92a5d80 100644
--- a/string/string.h
+++ b/string/string.h
@@ -574,6 +574,13 @@  extern char *stpncpy (char *__restrict __dest,
      __THROW __nonnull ((1, 2));
 #endif
 
+#ifdef __USE_MISC
+/* Copy at most N characters from SRC to DEST.  */
+extern size_t strlcpy (char *__restrict __dest,
+		       const char *__restrict __src, size_t __n)
+  __THROW __nonnull ((1, 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/strlcpy.c b/string/strlcpy.c
new file mode 100644
index 0000000..3833a50
--- /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) 2015 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-strlcpy.c b/string/tst-strlcpy.c
new file mode 100644
index 0000000..77b7677
--- /dev/null
+++ b/string/tst-strlcpy.c
@@ -0,0 +1,76 @@ 
+/* Test the strlcpy function.
+   Copyright (C) 2015 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 destiantion if its size is 0.  */
+  memset (&s, '@', sizeof (s));
+  CHECK (strlcpy (s.buf1, "Hello!", 0) == 6);
+  CHECK (memcmp (&s, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", sizeof (s)) == 0);
+
+  /* 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..9137c51 100644
--- a/sysdeps/arm/nacl/libc.abilist
+++ b/sysdeps/arm/nacl/libc.abilist
@@ -1834,3 +1834,6 @@  GLIBC_2.22 wprintf F
 GLIBC_2.22 write F
 GLIBC_2.22 writev F
 GLIBC_2.22 wscanf F
+GLIBC_2.23 GLIBC_2.23 A
+GLIBC_2.23 __strlcpy_chk 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 c1ba62c..62c6412 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2081,3 +2081,6 @@  GLIBC_2.18 __cxa_thread_atexit_impl F
 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 __strlcpy_chk 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 7d2d121..e5bff7e 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -1992,6 +1992,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 a30b258..5e7f8e9 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -82,6 +82,9 @@  GLIBC_2.18 GLIBC_2.18 A
 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 __strlcpy_chk 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 571548a..ff90320 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1846,6 +1846,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 87abbbd..ecf1d72 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2004,6 +2004,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 1cbdffe..8039f68 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1868,6 +1868,9 @@  GLIBC_2.2.6 __nanosleep F
 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 __strlcpy_chk 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 061b5ee..8053211 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -83,6 +83,9 @@  GLIBC_2.18 GLIBC_2.18 A
 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 __strlcpy_chk 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 91be3d8..d3d9863 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1960,6 +1960,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 c1b1cad..6fe3aeb 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2081,3 +2081,6 @@  GLIBC_2.18 xprt_register F
 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 __strlcpy_chk 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 3ef9b99..87de055 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1935,6 +1935,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 c44ee13..aed7e26 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1933,6 +1933,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 e8908e4..06d5c94 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1931,6 +1931,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 c6d1da2..e06e184 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1926,6 +1926,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 703979a..c837ec4 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2122,3 +2122,6 @@  GLIBC_2.21 xprt_register F
 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 __strlcpy_chk 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 90ca484..866c0c5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1964,6 +1964,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 a5ecc76..2b647f7 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1969,6 +1969,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 c6bea69..b0359b2 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2169,3 +2169,6 @@  GLIBC_2.18 GLIBC_2.18 A
 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 __strlcpy_chk 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 21e736b..df9a5f5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -83,6 +83,9 @@  GLIBC_2.18 GLIBC_2.18 A
 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 __strlcpy_chk 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 d6c037b..12528d0 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1964,6 +1964,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 02422da..99d63b4 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1865,6 +1865,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 5accb42..5d7baaa 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1850,6 +1850,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 0ecba65..eda8cc2 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1956,6 +1956,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 ce45412..9c72aaf 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1894,6 +1894,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 63441e9..50bbb2d 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2088,3 +2088,6 @@  GLIBC_2.18 GLIBC_2.18 A
 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 __strlcpy_chk 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 212e4d5..51c87cd 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2088,3 +2088,6 @@  GLIBC_2.18 GLIBC_2.18 A
 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 __strlcpy_chk 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 63441e9..50bbb2d 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2088,3 +2088,6 @@  GLIBC_2.18 GLIBC_2.18 A
 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 __strlcpy_chk 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 afb29dc..60e85dc 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1845,6 +1845,9 @@  GLIBC_2.2.6 GLIBC_2.2.6 A
 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 __strlcpy_chk 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 7ac7104..386d4b3 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2088,3 +2088,6 @@  GLIBC_2.18 GLIBC_2.18 A
 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 __strlcpy_chk F
+GLIBC_2.23 strlcpy F