[v2] Add reallocarray function.

Message ID 20170417140148.23212-1-denniswoelfing@gmx.de
State New
Headers show

Commit Message

Dennis Wölfing April 17, 2017, 2:01 p.m.
The reallocarray function is an extension from OpenBSD.  It is an
integer-overflow-safe replacement for realloc(p, X*Y) and
malloc(X*Y) (realloc(NULL, X*Y)).  It can therefore help in preventing
certain security issues in code.

This is an updated version of a patch originally submitted by Rüdiger
Sonderfeld in May 2014.
See <https://sourceware.org/ml/libc-alpha/2014-05/msg00481.html>.

Tested on x86_64-linux.

2017-04-17  Dennis Wölfing  <denniswoelfing@gmx.de>

	* malloc/Makefile (routines): Add reallocarray.
	* malloc/malloc-private.h: New file.
	(check_mul_overflow): Use __builtin_mul_overflow if available.
	* malloc/malloc.c (check_mul_overflow): Move to malloc-private.h.
	(reallocarray): Move to reallocarray.c.
	* malloc/reallocarray.c: New file.
	* manual/memory.texi: Document reallocarray.
	* stdlib/stdlib.h (reallocarray): Declare only for __USE_GNU.
	* sysdeps/arm/nacl/libc.abilist: Add reallocarray.
	* sysdeps/unix/sysv/linux/aarch64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tilepro/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.

2017-04-17  Rüdiger Sonderfeld  <ruediger@c-plusplus.de>

	* malloc/Versions: Add reallocarray and __libc_reallocarray.
	* malloc/Makefile (tests): Add tst-reallocarray.c.
	* malloc/tst-reallocarray.c: New test file.
	* malloc/malloc.h (reallocarray): New declaration.
	* stdlib/stdlib.h (reallocarray): Likewise.
	* malloc/malloc.c (check_mul_overflow): New inline function.
	(__libc_reallocarray): New function.
	(__libc_calloc): Use `check_mul_overflow'.
---
 malloc/Makefile                                    |   4 +-
 malloc/Versions                                    |   6 +
 malloc/malloc-private.h                            |  44 ++++++
 malloc/malloc.c                                    |  14 +-
 malloc/malloc.h                                    |   8 ++
 malloc/reallocarray.c                              |  35 +++++
 malloc/tst-reallocarray.c                          | 160 +++++++++++++++++++++
 manual/memory.texi                                 |  24 +++-
 stdlib/stdlib.h                                    |  11 ++
 sysdeps/arm/nacl/libc.abilist                      |   2 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |   2 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |   2 +
 sysdeps/unix/sysv/linux/arm/libc.abilist           |   2 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |   2 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |   2 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |   2 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |   2 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/microblaze/libc.abilist    |   2 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |   2 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |   2 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |   2 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |   2 +
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |   2 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |   2 +
 .../sysv/linux/powerpc/powerpc64/libc-le.abilist   |   2 +
 .../unix/sysv/linux/powerpc/powerpc64/libc.abilist |   2 +
 sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist  |   2 +
 sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist  |   2 +
 sysdeps/unix/sysv/linux/sh/libc.abilist            |   2 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |   2 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |   2 +
 .../sysv/linux/tile/tilegx/tilegx32/libc.abilist   |   2 +
 .../sysv/linux/tile/tilegx/tilegx64/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist  |   2 +
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |   2 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |   2 +
 38 files changed, 350 insertions(+), 14 deletions(-)
 create mode 100644 malloc/malloc-private.h
 create mode 100644 malloc/reallocarray.c
 create mode 100644 malloc/tst-reallocarray.c

Comments

Florian Weimer April 17, 2017, 2:32 p.m. | #1
* Dennis Wölfing:

> +static inline bool
> +check_mul_overflow (size_t l, size_t r, INTERNAL_SIZE_T *result)
> +{
> +#if __GNUC__ >= 5
> +  return __builtin_mul_overflow (l, r, result);

This is not correct for size_t != INTERNAL_SIZE_T.  Either change the
type of result to size_t * (so that the code fails to compile if the
types differ, something which we have not done for a long time), or
add another check against (INTERNAL_SIZE_T) -1.
Paul Eggert April 17, 2017, 2:34 p.m. | #2
On 04/17/2017 07:32 AM, Florian Weimer wrote:
> * Dennis Wölfing:
>
>> +static inline bool
>> +check_mul_overflow (size_t l, size_t r, INTERNAL_SIZE_T *result)
>> +{
>> +#if __GNUC__ >= 5
>> +  return __builtin_mul_overflow (l, r, result);
> This is not correct for size_t != INTERNAL_SIZE_T.

Why not? Could you give an example?
Dennis Wölfing April 17, 2017, 2:40 p.m. | #3
On 17.04.2017 16:32, Florian Weimer wrote:
> * Dennis Wölfing:
> 
>> +static inline bool
>> +check_mul_overflow (size_t l, size_t r, INTERNAL_SIZE_T *result)
>> +{
>> +#if __GNUC__ >= 5
>> +  return __builtin_mul_overflow (l, r, result);
> 
> This is not correct for size_t != INTERNAL_SIZE_T.  Either change the
> type of result to size_t * (so that the code fails to compile if the
> types differ, something which we have not done for a long time), or
> add another check against (INTERNAL_SIZE_T) -1.

Are you sure that this is not correct? The GCC manual says about the
overflow builtins:

> These built-in functions promote the first two operands into infinite
> precision signed type and perform addition on those promoted operands.
> The result is then cast to the type the third pointer argument points
> to and stored there. If the stored result is equal to the infinite
> precision result, the built-in functions return false, otherwise they
> return true. As the addition is performed in infinite signed
> precision, these built-in functions have fully defined behavior for
> all argument values.

So the result should be correct even if the types are different.
Florian Weimer April 17, 2017, 2:44 p.m. | #4
* Dennis Wölfing:

> On 17.04.2017 16:32, Florian Weimer wrote:
>> * Dennis Wölfing:
>> 
>>> +static inline bool
>>> +check_mul_overflow (size_t l, size_t r, INTERNAL_SIZE_T *result)
>>> +{
>>> +#if __GNUC__ >= 5
>>> +  return __builtin_mul_overflow (l, r, result);
>> 
>> This is not correct for size_t != INTERNAL_SIZE_T.  Either change the
>> type of result to size_t * (so that the code fails to compile if the
>> types differ, something which we have not done for a long time), or
>> add another check against (INTERNAL_SIZE_T) -1.
>
> Are you sure that this is not correct? The GCC manual says about the
> overflow builtins:

Sorry, you are right.  I actually tested this, but misread the
generated assembly.
Carlos O'Donell April 18, 2017, 12:34 p.m. | #5
On 04/17/2017 10:01 AM, Dennis Wölfing wrote:
> The reallocarray function is an extension from OpenBSD.  It is an
> integer-overflow-safe replacement for realloc(p, X*Y) and
> malloc(X*Y) (realloc(NULL, X*Y)).  It can therefore help in preventing
> certain security issues in code.
> 
> This is an updated version of a patch originally submitted by Rüdiger
> Sonderfeld in May 2014.
> See <https://sourceware.org/ml/libc-alpha/2014-05/msg00481.html>.
> 
> Tested on x86_64-linux.

Rüdiger Sonderfeld has a future's copyright assignment for glibc, which
means we can accept work from Rüdiger.

However, we have no such assignment that I can see for yourself. It isn't
clear exactly how much you changed from Rüdiger's originally submitted
works. Say you only changed ~15 legally significant lines, then we might
be able to accept the new patch, but it would certainly need both author
names in the ChangeLog.

Would you consider signing a future's copyright assignment for glibc so
we can accept your present and future work for the project? Such an assignment
would allow us as maintainers to accept your current and all future work
submitted to the project.

https://sourceware.org/glibc/wiki/Contribution%20checklist

https://sourceware.org/glibc/wiki/Contribution%20checklist#FSF_copyright_Assignment

http://git.savannah.gnu.org/cgit/gnulib.git/plain/doc/Copyright/request-assign.future
Dennis Wölfing April 18, 2017, 2:28 p.m. | #6
On 18.04.2017 14:34, Carlos O'Donell wrote:
> However, we have no such assignment that I can see for yourself.

I have already assigned copyright for glibc to the FSF and got it back
signed by the FSF.

I will send you a copy of the signed copyright papers in a separate mail.
Carlos O'Donell April 18, 2017, 3:50 p.m. | #7
On 04/18/2017 10:28 AM, Dennis Wölfing wrote:
> On 18.04.2017 14:34, Carlos O'Donell wrote:
>> However, we have no such assignment that I can see for yourself.
> 
> I have already assigned copyright for glibc to the FSF and got it back
> signed by the FSF.
> 
> I will send you a copy of the signed copyright papers in a separate mail.
 
Thank you for proactively taking that step.

Your assignment is not yet on file with the FSF for me to review, this is
likely because your assignment was just recently completed last week.

However, given your assignment papers that makes it easy for the technical
review to continue.

My only remaining issue is that the works you present are based on Sonderfeld's
work, and should include his name in the ChangeLog to give credit for the basis
of the work.

e.g.

2017-04-17  Dennis Wölfing  <denniswoelfing@gmx.de>
	    Rüdiger Sonderfeld  <ruediger@c-plusplus.de>

	* ...
Dennis Wölfing April 18, 2017, 3:57 p.m. | #8
On 18.04.2017 17:50, Carlos O'Donell wrote:> My only remaining issue is
that the works you present are based on Sonderfeld's
> work, and should include his name in the ChangeLog to give credit for the basis
> of the work.
> 
> e.g.
> 
> 2017-04-17  Dennis Wölfing  <denniswoelfing@gmx.de>
> 	    Rüdiger Sonderfeld  <ruediger@c-plusplus.de>
> 
> 	* ...
> 

The patch I have submitted already contains two separate ChangeLog entries:

2017-04-17  Dennis Wölfing  <denniswoelfing@gmx.de>

	* ...

2017-04-17  Rüdiger Sonderfeld  <ruediger@c-plusplus.de>

	* malloc/Versions: Add reallocarray and __libc_reallocarray.
	* malloc/Makefile (tests): Add tst-reallocarray.c.
	* malloc/tst-reallocarray.c: New test file.
	* malloc/malloc.h (reallocarray): New declaration.
	* stdlib/stdlib.h (reallocarray): Likewise.
	* malloc/malloc.c (check_mul_overflow): New inline function.
	(__libc_reallocarray): New function.
	(__libc_calloc): Use `check_mul_overflow'.

Should I merge these entries?
Joseph Myers April 19, 2017, 3:02 p.m. | #9
On Mon, 17 Apr 2017, Dennis Wölfing wrote:

> The reallocarray function is an extension from OpenBSD.  It is an
> integer-overflow-safe replacement for realloc(p, X*Y) and
> malloc(X*Y) (realloc(NULL, X*Y)).  It can therefore help in preventing
> certain security issues in code.
> 
> This is an updated version of a patch originally submitted by Rüdiger
> Sonderfeld in May 2014.
> See <https://sourceware.org/ml/libc-alpha/2014-05/msg00481.html>.

A patch adding a new function should also include NEWS file changes to 
mention that new feature.

> diff --git a/malloc/reallocarray.c b/malloc/reallocarray.c
> new file mode 100644
> index 0000000000..4915ca7a7d
> --- /dev/null
> +++ b/malloc/reallocarray.c
> @@ -0,0 +1,35 @@
> +/* Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.

New files should have a descriptive comment on their first line, before 
the copyright notice.

> diff --git a/malloc/tst-reallocarray.c b/malloc/tst-reallocarray.c
> new file mode 100644
> index 0000000000..a43419b82b
> --- /dev/null
> +++ b/malloc/tst-reallocarray.c
> @@ -0,0 +1,160 @@
> +/* Copyright (C) 2014-2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.

Likewise.

> +#define TEST_FUNCTION do_test ()
> +#include "../test-skeleton.c"

Please use the new-style support/test-driver.c for new tests.
Joseph Myers April 19, 2017, 3:16 p.m. | #10
On Tue, 18 Apr 2017, Dennis Wölfing wrote:

> On 18.04.2017 17:50, Carlos O'Donell wrote:> My only remaining issue is
> that the works you present are based on Sonderfeld's
> > work, and should include his name in the ChangeLog to give credit for the basis
> > of the work.
> > 
> > e.g.
> > 
> > 2017-04-17  Dennis Wölfing  <denniswoelfing@gmx.de>
> > 	    Rüdiger Sonderfeld  <ruediger@c-plusplus.de>
> > 
> > 	* ...
> > 
> 
> The patch I have submitted already contains two separate ChangeLog entries:
> 
> 2017-04-17  Dennis Wölfing  <denniswoelfing@gmx.de>
> 
> 	* ...
> 
> 2017-04-17  Rüdiger Sonderfeld  <ruediger@c-plusplus.de>
> 
> 	* malloc/Versions: Add reallocarray and __libc_reallocarray.
> 	* malloc/Makefile (tests): Add tst-reallocarray.c.
> 	* malloc/tst-reallocarray.c: New test file.
> 	* malloc/malloc.h (reallocarray): New declaration.
> 	* stdlib/stdlib.h (reallocarray): Likewise.
> 	* malloc/malloc.c (check_mul_overflow): New inline function.
> 	(__libc_reallocarray): New function.
> 	(__libc_calloc): Use `check_mul_overflow'.
> 
> Should I merge these entries?

Yes.  There should be a single entry, with both names, describing the 
actual set of changes proposed for commit.  There should not be a separate 
ChangeLog entry relating to an intermediate set of changes not committed 
in that state.

Patch

diff --git a/malloc/Makefile b/malloc/Makefile
index e93b83b57d..6534594f7f 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -26,7 +26,7 @@  dist-headers := malloc.h
 headers := $(dist-headers) obstack.h mcheck.h
 tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
 	 tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 \
-	 tst-malloc-usable tst-realloc tst-posix_memalign \
+	 tst-malloc-usable tst-realloc tst-reallocarray tst-posix_memalign \
 	 tst-pvalloc tst-memalign tst-mallopt tst-scratch_buffer \
 	 tst-malloc-backtrace tst-malloc-thread-exit \
 	 tst-malloc-thread-fail tst-malloc-fork-deadlock \
@@ -47,7 +47,7 @@  endif
 tests += $(tests-static)
 test-srcs = tst-mtrace
 
-routines = malloc morecore mcheck mtrace obstack \
+routines = malloc morecore mcheck mtrace obstack reallocarray \
   scratch_buffer_grow scratch_buffer_grow_preserve \
   scratch_buffer_set_array_size
 
diff --git a/malloc/Versions b/malloc/Versions
index f3c3d8a093..23aafb5ccc 100644
--- a/malloc/Versions
+++ b/malloc/Versions
@@ -61,6 +61,9 @@  libc {
   GLIBC_2.16 {
     aligned_alloc;
   }
+  GLIBC_2.26 {
+    reallocarray;
+  }
   GLIBC_PRIVATE {
     # Internal startup hook for libpthread.
     __libc_malloc_pthread_startup;
@@ -72,5 +75,8 @@  libc {
     __libc_scratch_buffer_grow;
     __libc_scratch_buffer_grow_preserve;
     __libc_scratch_buffer_set_array_size;
+
+    # Internal name for reallocarray
+    __libc_reallocarray;
   }
 }
diff --git a/malloc/malloc-private.h b/malloc/malloc-private.h
new file mode 100644
index 0000000000..56b9fbd708
--- /dev/null
+++ b/malloc/malloc-private.h
@@ -0,0 +1,44 @@ 
+/* Private declarations for malloc, for use within libc.
+   Copyright (C) 2017 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; see the file COPYING.LIB.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _MALLOC_PRIVATE_H
+#define _MALLOC_PRIVATE_H
+
+#include <malloc/malloc-internal.h>
+
+static inline bool
+check_mul_overflow (size_t l, size_t r, INTERNAL_SIZE_T *result)
+{
+#if __GNUC__ >= 5
+  return __builtin_mul_overflow (l, r, result);
+#else
+  /* size_t is unsigned so the behavior on overflow is defined.  */
+  *result = l * r;
+# define HALF_INTERNAL_SIZE_T                                   \
+  (((INTERNAL_SIZE_T) 1) << (8 * sizeof (INTERNAL_SIZE_T) / 2))
+  if (__glibc_unlikely ((l | r) >= HALF_INTERNAL_SIZE_T))
+    {
+      if (r != 0 && *result / r != l)
+        return true;
+    }
+  return false;
+# undef HALF_INTERNAL_SIZE_T
+#endif
+}
+
+#endif /* _MALLOC_PRIVATE_H */
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 4c40e2ea19..35cf4ec1fe 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -240,6 +240,7 @@ 
 #include <libc-pointer-arith.h>
 
 #include <malloc/malloc-internal.h>
+#include <malloc/malloc-private.h>
 
 /*
   Debugging:
@@ -3180,17 +3181,10 @@  __libc_calloc (size_t n, size_t elem_size)
   unsigned long nclears;
   INTERNAL_SIZE_T *d;
 
-  /* size_t is unsigned so the behavior on overflow is defined.  */
-  bytes = n * elem_size;
-#define HALF_INTERNAL_SIZE_T \
-  (((INTERNAL_SIZE_T) 1) << (8 * sizeof (INTERNAL_SIZE_T) / 2))
-  if (__builtin_expect ((n | elem_size) >= HALF_INTERNAL_SIZE_T, 0))
+  if (check_mul_overflow (n, elem_size, &bytes))
     {
-      if (elem_size != 0 && bytes / elem_size != n)
-        {
-          __set_errno (ENOMEM);
-          return 0;
-        }
+      __set_errno (ENOMEM);
+      return 0;
     }
 
   void *(*hook) (size_t, const void *) =
diff --git a/malloc/malloc.h b/malloc/malloc.h
index 0bd8f97bc3..105fdbe691 100644
--- a/malloc/malloc.h
+++ b/malloc/malloc.h
@@ -49,6 +49,14 @@  __THROW __attribute_malloc__ __wur;
 extern void *realloc (void *__ptr, size_t __size)
 __THROW __attribute_warn_unused_result__;
 
+/* Re-allocate the previously allocated block in PTR, making the new
+   block large enough for NMEMB elements of SIZE bytes each.  */
+/* __attribute_malloc__ is not used, because if reallocarray returns
+   the same pointer that was passed to it, aliasing needs to be allowed
+   between objects pointed by the old and new pointers.  */
+extern void *reallocarray (void *__ptr, size_t __nmemb, size_t __size)
+__THROW __attribute_warn_unused_result__;
+
 /* Free a block allocated by `malloc', `realloc' or `calloc'.  */
 extern void free (void *__ptr) __THROW;
 
diff --git a/malloc/reallocarray.c b/malloc/reallocarray.c
new file mode 100644
index 0000000000..4915ca7a7d
--- /dev/null
+++ b/malloc/reallocarray.c
@@ -0,0 +1,35 @@ 
+/* Copyright (C) 2017 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; see the file COPYING.LIB.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <malloc.h>
+#include <malloc/malloc-private.h>
+
+void *
+__libc_reallocarray (void *optr, size_t nmemb, size_t elem_size)
+{
+  INTERNAL_SIZE_T bytes;
+  if (check_mul_overflow (nmemb, elem_size, &bytes))
+    {
+      __set_errno (ENOMEM);
+      return 0;
+    }
+  else
+    return realloc (optr, bytes);
+}
+
+strong_alias (__libc_reallocarray, __reallocarray)
+weak_alias (__libc_reallocarray, reallocarray)
diff --git a/malloc/tst-reallocarray.c b/malloc/tst-reallocarray.c
new file mode 100644
index 0000000000..a43419b82b
--- /dev/null
+++ b/malloc/tst-reallocarray.c
@@ -0,0 +1,160 @@ 
+/* Copyright (C) 2014-2017 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 <errno.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+  ++errors;
+  printf ("Error: %s.\n", msg);
+}
+
+static int
+do_test (void)
+
+{
+  void *ptr = NULL;
+  void *ptr2 = NULL;
+  unsigned char *c;
+  size_t i;
+  int ok;
+  const size_t max = ~(size_t)0;
+  size_t a, b;
+
+  /* Test overflow detection.  */
+  errno = 0;
+  ptr = reallocarray (NULL, max, 2);
+  if (ptr)
+    {
+      merror ("Overflow for size_t MAX * 2 not detected");
+      free (ptr);
+    }
+  else if (errno != ENOMEM)
+    merror ("errno is not set correctly");
+
+  errno = 0;
+  ptr = reallocarray (NULL, 2, max);
+  if (ptr)
+    {
+      merror ("Overflow for 2 * size_t MAX not detected");
+      free (ptr);
+    }
+  else if (errno != ENOMEM)
+    merror ("errno is not set correctly");
+
+  a = 65537;
+  b = max/65537 + 1;
+  errno = 0;
+  ptr = reallocarray (NULL, a, b);
+  if (ptr)
+    {
+      merror ("Overflow for (size_t MAX/65537 + 1) * 65537 not detected");
+      free (ptr);
+    }
+  else if (errno != ENOMEM)
+    merror ("errno is not set correctly");
+
+  errno = 0;
+  ptr = reallocarray (NULL, b, a);
+  if (ptr)
+    {
+      merror ("Overflow for 65537 * (size_t MAX/65537 + 1)  not detected");
+      free (ptr);
+    }
+  else if (errno != ENOMEM)
+    merror ("errno is not set correctly");
+
+  /* Test realloc-like behavior.  */
+  /* Allocate memory like malloc.  */
+  ptr = reallocarray (NULL, 10, 2);
+  if (!ptr)
+    merror ("realloc(NULL, 10, 2) failed");
+
+  memset (ptr, 0xAF, 10*2);
+
+  /* Enlarge buffer.   */
+  ptr2 = reallocarray (ptr, 20, 2);
+  if (!ptr2)
+    merror ("realloc(ptr, 20, 2) failed (enlarge)");
+  else
+    ptr = ptr2;
+
+  c = ptr;
+  ok = 1;
+  for (i = 0; i < 10*2; ++i)
+    {
+      if (c[i] != 0xAF)
+        ok = 0;
+    }
+  if (!ok)
+    merror ("Enlarging changed buffer content (10*2)");
+
+  /* Decrease buffer size.  */
+  ptr2 = reallocarray (ptr, 5, 3);
+  if (!ptr2)
+    merror ("realloc(ptr, 5, 3) failed (decrease)");
+  else
+    ptr = ptr2;
+
+  c = ptr;
+  ok = 1;
+  for (i = 0; i < 5*3; ++i)
+    {
+      if (c[i] != 0xAF)
+        ok = 0;
+    }
+  if (!ok)
+    merror ("Reducing changed buffer content (5*3)");
+
+  /* Overflow should leave buffer untouched.  */
+  errno = 0;
+  ptr2 = reallocarray (ptr, 2, ~(size_t)0);
+  if (ptr2)
+    merror ("realloc(ptr, 2, size_t MAX) failed to detect overflow");
+  if (errno != ENOMEM)
+    merror ("errno not set correctly");
+
+  c = ptr;
+  ok = 1;
+  for (i = 0; i < 5*3; ++i)
+    {
+      if (c[i] != 0xAF)
+        ok = 0;
+    }
+  if (!ok)
+    merror ("Overflow changed buffer content (5*3)");
+
+  /* Free buffer (glibc).  */
+  errno = 0;
+  ptr2 = reallocarray (ptr, 0, 0);
+  if (ptr2)
+    merror ("reallocarray (ptr, 0, 0) returned non-NULL");
+
+  free (ptr2);
+
+  return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/manual/memory.texi b/manual/memory.texi
index 38d3c3a4bb..3658fef647 100644
--- a/manual/memory.texi
+++ b/manual/memory.texi
@@ -756,8 +756,8 @@  be a buffer that you use to hold a line being read from a file; no matter
 how long you make the buffer initially, you may encounter a line that is
 longer.
 
-You can make the block longer by calling @code{realloc}.  This function
-is declared in @file{stdlib.h}.
+You can make the block longer by calling @code{realloc} or
+@code{reallocarray}.  These functions are declared in @file{stdlib.h}.
 @pindex stdlib.h
 
 @comment malloc.h stdlib.h
@@ -821,6 +821,21 @@  behavior, and will probably crash when @code{realloc} is passed a null
 pointer.
 @end deftypefun
 
+@comment malloc.h stdlib.h
+@comment BSD
+@deftypefun {void *} reallocarray (void *@var{ptr}, size_t @var{nmemb}, size_t @var{size})
+@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}}
+
+The @code{reallocarray} function changes the size of the block whose address
+is @var{ptr} to be long enough to contain a vector of @var{nmemb} elements,
+each of size @var{size}.  It is equivalent to @samp{realloc (@var{ptr},
+@var{nmemb} * @var{size})}, except that @code{reallocarray} fails if the
+multiplication overflows.
+
+@code{reallocarray} should be used instead of @code{realloc} when the new size
+of the allocated block is the result of a multiplication that might overflow.
+@end deftypefun
+
 Like @code{malloc}, @code{realloc} may return a null pointer if no
 memory space is available to make the block bigger.  When this happens,
 the original block is untouched; it has not been modified or relocated.
@@ -1593,6 +1608,11 @@  Malloc}.
 Make a block previously allocated by @code{malloc} larger or smaller,
 possibly by copying it to a new location.  @xref{Changing Block Size}.
 
+@item void *reallocarray (void *@var{ptr}, size_t @var{nmemb}, size_t @var{size})
+Change the size of a block previously allocated by @code{malloc} to
+@code{@var{nmemb} * @var{size}} bytes as with @code{realloc}.  @xref{Changing
+Block Size}.
+
 @item void *calloc (size_t @var{count}, size_t @var{eltsize})
 Allocate a block of @var{count} * @var{eltsize} bytes using
 @code{malloc}, and set its contents to zero.  @xref{Allocating Cleared
diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h
index c1f389253a..dad94dcc74 100644
--- a/stdlib/stdlib.h
+++ b/stdlib/stdlib.h
@@ -422,6 +422,17 @@  extern void *calloc (size_t __nmemb, size_t __size)
    between objects pointed by the old and new pointers.  */
 extern void *realloc (void *__ptr, size_t __size)
      __THROW __attribute_warn_unused_result__;
+
+#ifdef __USE_GNU
+/* Re-allocate the previously allocated block in PTR, making the new
+   block large enough for NMEMB elements of SIZE bytes each.  */
+/* __attribute_malloc__ is not used, because if reallocarray returns
+   the same pointer that was passed to it, aliasing needs to be allowed
+   between objects pointed by the old and new pointers.  */
+extern void *reallocarray (void *__ptr, size_t __nmemb, size_t __size)
+     __THROW __attribute_warn_unused_result__;
+#endif
+
 /* Free a block allocated by `malloc', `realloc' or `calloc'.  */
 extern void free (void *__ptr) __THROW;
 
diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist
index abd70c8108..b60bf7049a 100644
--- a/sysdeps/arm/nacl/libc.abilist
+++ b/sysdeps/arm/nacl/libc.abilist
@@ -1853,3 +1853,5 @@  GLIBC_2.25 gnu_dev_minor F
 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 reallocarray F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 58d768c6bc..a494c3947d 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2097,3 +2097,5 @@  GLIBC_2.25 getrandom F
 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 reallocarray F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 906050d2c3..2fc1a9bae7 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2008,6 +2008,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 66112dd0a7..4465a62ff1 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -98,6 +98,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 3ddadd2a24..96126d9e6a 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1862,6 +1862,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 977ab90bc7..aae351bbff 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2020,6 +2020,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 c7edb9a272..81ec65bec0 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1884,6 +1884,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 450be4e9c1..9db205b68e 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -99,6 +99,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 9e016bd76e..ee59e950b6 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1976,6 +1976,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 1a455be0f5..feb869757c 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2097,3 +2097,5 @@  GLIBC_2.25 getrandom F
 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 reallocarray F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 8eb5e668b9..a5b1c42929 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1951,6 +1951,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 416d9ac0ae..570a859aac 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1949,6 +1949,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 f4949e5a38..71008ad873 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1947,6 +1947,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 c7375aee3f..1a07d66caf 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1942,6 +1942,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 724a0e3a04..a62a41be62 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2138,3 +2138,5 @@  GLIBC_2.25 getrandom F
 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 reallocarray F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 2dc32b631c..f4f11dc625 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1980,6 +1980,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 5658109ca2..2977569f2c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1985,6 +1985,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 c761221ffe..271d32e19b 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2185,3 +2185,5 @@  GLIBC_2.25 getrandom F
 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 reallocarray F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 265c76914b..372ef67c27 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -99,6 +99,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 ed1b6bf26f..705ff851a9 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1980,6 +1980,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 2e75d29e47..21fd2b5671 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1881,6 +1881,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 bd74c0cdab..313a71e589 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1866,6 +1866,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 5584838409..94a4fb2213 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1972,6 +1972,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 efedbe2874..6db5811c3f 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1910,6 +1910,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 ffd988a33d..5d83926aac 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2104,3 +2104,5 @@  GLIBC_2.25 getrandom F
 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 reallocarray F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index f0c13ceea8..ce14ceb15f 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2104,3 +2104,5 @@  GLIBC_2.25 getrandom F
 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 reallocarray F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index ffd988a33d..5d83926aac 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2104,3 +2104,5 @@  GLIBC_2.25 getrandom F
 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 reallocarray F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index f57004c860..f69de7aa83 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1861,6 +1861,8 @@  GLIBC_2.25 getrandom F
 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 reallocarray 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 05629e17e7..a330855308 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2104,3 +2104,5 @@  GLIBC_2.25 getrandom F
 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 reallocarray F