Add reallocarray function.
Commit Message
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-10 Dennis Wölfing <denniswoelfing@gmx.de>
* malloc/malloc.c (check_mul_overflow): Use
__builtin_mul_overflow if available.
* 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-10 Rüdiger Sonderfeld <ruediger@c-plusplus.de>
* malloc/Versions: Add reallocarray and __libc_rallocarray.
* 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 | 2 +-
malloc/Versions | 4 +
malloc/malloc.c | 48 +++++--
malloc/malloc.h | 8 ++
malloc/tst-reallocarray.c | 160 +++++++++++++++++++++
stdlib/stdlib.h | 11 ++
sysdeps/arm/nacl/libc.abilist | 3 +
sysdeps/unix/sysv/linux/aarch64/libc.abilist | 3 +
sysdeps/unix/sysv/linux/alpha/libc.abilist | 3 +
sysdeps/unix/sysv/linux/arm/libc.abilist | 3 +
sysdeps/unix/sysv/linux/hppa/libc.abilist | 3 +
sysdeps/unix/sysv/linux/i386/libc.abilist | 3 +
sysdeps/unix/sysv/linux/ia64/libc.abilist | 3 +
sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist | 3 +
sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist | 3 +
sysdeps/unix/sysv/linux/microblaze/libc.abilist | 3 +
.../unix/sysv/linux/mips/mips32/fpu/libc.abilist | 3 +
.../unix/sysv/linux/mips/mips32/nofpu/libc.abilist | 3 +
.../unix/sysv/linux/mips/mips64/n32/libc.abilist | 3 +
.../unix/sysv/linux/mips/mips64/n64/libc.abilist | 3 +
sysdeps/unix/sysv/linux/nios2/libc.abilist | 3 +
.../sysv/linux/powerpc/powerpc32/fpu/libc.abilist | 3 +
.../linux/powerpc/powerpc32/nofpu/libc.abilist | 3 +
.../sysv/linux/powerpc/powerpc64/libc-le.abilist | 3 +
.../unix/sysv/linux/powerpc/powerpc64/libc.abilist | 3 +
sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist | 3 +
sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist | 3 +
sysdeps/unix/sysv/linux/sh/libc.abilist | 3 +
sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist | 3 +
sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist | 3 +
.../sysv/linux/tile/tilegx/tilegx32/libc.abilist | 3 +
.../sysv/linux/tile/tilegx/tilegx64/libc.abilist | 3 +
sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist | 3 +
sysdeps/unix/sysv/linux/x86_64/64/libc.abilist | 3 +
sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist | 3 +
35 files changed, 309 insertions(+), 11 deletions(-)
create mode 100644 malloc/tst-reallocarray.c
Comments
On Mon, Apr 10, 2017 at 11:00 AM, Dennis Wölfing <denniswoelfing@gmx.de> 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>.
I agree in principle with adding this function. I skimmed the patch
and it seems to be mostly the Right Thing. I do have two concerns:
* There do not appear to be any uses of the internal aliases
__libc_reallocarray and __reallocarray. Have you audited glibc itself
for places that should use reallocarray? If you haven't, would you be
willing to do that? This will determine whether we actually need
those aliases.
* Please add documentation for reallocarray. It belongs in
manual/memory.texi, in the "Changing Block Size" section. This is the
place to explain when and why one should use reallocarray instead of
realloc.
zw
On Apr 10 2017, Dennis Wölfing <denniswoelfing@gmx.de> wrote:
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index 4c40e2ea19..ca22e53f63 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -2950,6 +2950,39 @@ __libc_free (void *mem)
> }
> libc_hidden_def (__libc_free)
>
> +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
> +}
> +
> +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 __libc_realloc (optr, bytes);
> +}
> +
Style: please put a space before paren on function calls.
Andreas.
On 10.04.2017 17:18, Zack Weinberg wrote:
> On Mon, Apr 10, 2017 at 11:00 AM, Dennis Wölfing <denniswoelfing@gmx.de> 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>.
>
> I agree in principle with adding this function. I skimmed the patch
> and it seems to be mostly the Right Thing. I do have two concerns:
>
> * There do not appear to be any uses of the internal aliases
> __libc_reallocarray and __reallocarray. Have you audited glibc itself
> for places that should use reallocarray? If you haven't, would you be
> willing to do that? This will determine whether we actually need
> those aliases.
I have not yet checked where glibc itself should use reallocarray but I
will do so.
> * Please add documentation for reallocarray. It belongs in
> manual/memory.texi, in the "Changing Block Size" section. This is the
> place to explain when and why one should use reallocarray instead of
> realloc.
Ok, I will look into this.
On 04/10/2017 05:00 PM, Dennis Wölfing wrote:
> +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 __libc_realloc (optr, bytes);
> +}
This needs to go into its own file and has to call realloc (not
__libc_realloc), otherwise it will not be compatible with malloc
interposition.
Thanks,
Florian
On 11.04.2017 09:55, Florian Weimer wrote:
> On 04/10/2017 05:00 PM, Dennis Wölfing wrote:
>> +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 __libc_realloc (optr, bytes);
>> +}
>
> This needs to go into its own file and has to call realloc (not
> __libc_realloc), otherwise it will not be compatible with malloc
> interposition.
Ok, I see the problem. When a statically linked program defines their
own memory allocation functions, calls to reallocarray pull in malloc.c
and thus cause link errors.
The static inline function check_mul_overflow is used in both
reallocarray and calloc. So that function would need to be in a file
that can be included by both malloc.c and a new reallocarray.c file.
Would malloc-internal.h be a good location to put that inline function
or should I place it into its own separate file?
On 04/12/2017 05:24 PM, Dennis Wölfing wrote:
> The static inline function check_mul_overflow is used in both
> reallocarray and calloc. So that function would need to be in a file
> that can be included by both malloc.c and a new reallocarray.c file.
>
> Would malloc-internal.h be a good location to put that inline function
> or should I place it into its own separate file?
Use malloc-internal.h or create a new malloc-private.h header.
malloc-internal.h is used for things which are used in other glibc
modules (fork handler and ld.so), but we aren't fully consistent yet
about the distinction in other areas of the library.
Thanks,
Florian
On 10.04.2017 20:26, Dennis Wölfing wrote:
> On 10.04.2017 17:18, Zack Weinberg wrote:
>> On Mon, Apr 10, 2017 at 11:00 AM, Dennis Wölfing <denniswoelfing@gmx.de> 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>.
>>
>> I agree in principle with adding this function. I skimmed the patch
>> and it seems to be mostly the Right Thing. I do have two concerns:
>>
>> * There do not appear to be any uses of the internal aliases
>> __libc_reallocarray and __reallocarray. Have you audited glibc itself
>> for places that should use reallocarray? If you haven't, would you be
>> willing to do that? This will determine whether we actually need
>> those aliases.
>
> I have not yet checked where glibc itself should use reallocarray but I
> will do so.
At least the following files contain calls to realloc where the size
argument is the result of a multiplication. Note that I have not checked
all of these files in detail so it is possible that many these
multiplications can never overflow.
catgets/gencat.c
dirent/scandir-tail.c
grp/compat-initgroups.c
hesiod/nss_hesiod/hesiod-grp.c
iconv/iconvconfig.c
io/fts.c
libidn/idna.c
libio/iogetdelim.c
locale/programs/3level.h
locale/programs/charmap-dir.c
locale/programs/ld-collate.c
locale/programs/ld-ctypes.c
locale/programs/ld-monetary.c
locale/programs/ld-numeric.c
locale/programs/ld-time.c
locale/programs/locfile.c
misc/err.c
misc/error.c
nis/nis_addmember.c
nis/nis_call.c
nis/nis_findserv.c
nis/nis_subr.c
nis/nis_table.c
nis/nss_compat/compat-initgroups.c
nis/nss_nis/nis_initgroups.c
nis/nss_nisplus/nisplus-initgroups.c
nscd/grpcache.c
nscd/hstcache.c
nscd/nscd_initgroups.c
nscd/pwdcache.c
nscd/servicescache.c
nss/getXXbyYY.c
nss/getnssent.c
posix/glob.c
resolv/gai_misc.c
resolv/res_hconf.c
Perhaps some of them should use reallocarray to detect overflows. So I
guess these internal aliases should be fine.
But another question occurred to me: Should __libc_reallocarray be
listed in malloc/Versions and the abilist files? I would guess no
because this name should only be used internally, but most other memory
allocation functions do have their __libc_ prefixed name listed as part
of the public abi.
* Dennis Wölfing:
> But another question occurred to me: Should __libc_reallocarray be
> listed in malloc/Versions and the abilist files?
It has to be listed under GLIBC_PRIVATE because otherwise, code
outside of libc.so proper (such as nss_nis) would not be able to call
it. Separate programs such as nscd can directly call reallocarray.
> I would guess no because this name should only be used internally,
> but most other memory allocation functions do have their __libc_
> prefixed name listed as part of the public abi.
That's more or less a historical accident. The dynamic linker used
memalign internally, but calling it under this name would result in a
namespace violation, so it uses __libc_memalign instead. This symbol
was made part of the public ABI so that external mallocs can interpose
it (although interposition would have worked just fine for a
GLIBC_PRIVATE symbol, too). I assume some of the other __libc_*
aliases were just added for consistency. Today, this is just historic
cruft, which we could replace with compat symbols.
@@ -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 \
@@ -61,6 +61,10 @@ libc {
GLIBC_2.16 {
aligned_alloc;
}
+ GLIBC_2.26 {
+ __libc_reallocarray;
+ reallocarray;
+ }
GLIBC_PRIVATE {
# Internal startup hook for libpthread.
__libc_malloc_pthread_startup;
@@ -2950,6 +2950,39 @@ __libc_free (void *mem)
}
libc_hidden_def (__libc_free)
+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
+}
+
+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 __libc_realloc (optr, bytes);
+}
+
void *
__libc_realloc (void *oldmem, size_t bytes)
{
@@ -3180,17 +3213,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 *) =
@@ -5295,6 +5321,8 @@ strong_alias (__libc_free, __free) strong_alias (__libc_free, free)
strong_alias (__libc_malloc, __malloc) strong_alias (__libc_malloc, malloc)
strong_alias (__libc_memalign, __memalign)
weak_alias (__libc_memalign, memalign)
+strong_alias (__libc_reallocarray, __reallocarray)
+weak_alias (__libc_reallocarray, reallocarray)
strong_alias (__libc_realloc, __realloc) strong_alias (__libc_realloc, realloc)
strong_alias (__libc_valloc, __valloc) weak_alias (__libc_valloc, valloc)
strong_alias (__libc_pvalloc, __pvalloc) weak_alias (__libc_pvalloc, pvalloc)
@@ -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;
new file mode 100644
@@ -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"
@@ -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;
@@ -1853,3 +1853,6 @@ 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 __libc_reallocarray F
+GLIBC_2.26 reallocarray F
@@ -2097,3 +2097,6 @@ 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 __libc_reallocarray F
+GLIBC_2.26 reallocarray F
@@ -2008,6 +2008,9 @@ 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 __libc_reallocarray F
+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
@@ -98,6 +98,9 @@ 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 __libc_reallocarray F
+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
@@ -1862,6 +1862,9 @@ 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 __libc_reallocarray F
+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
@@ -2020,6 +2020,9 @@ 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 __libc_reallocarray F
+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
@@ -1884,6 +1884,9 @@ 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 __libc_reallocarray F
+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
@@ -99,6 +99,9 @@ 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 __libc_reallocarray F
+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
@@ -1976,6 +1976,9 @@ 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 __libc_reallocarray F
+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
@@ -2097,3 +2097,6 @@ 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 __libc_reallocarray F
+GLIBC_2.26 reallocarray F
@@ -1951,6 +1951,9 @@ 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 __libc_reallocarray F
+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
@@ -1949,6 +1949,9 @@ 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 __libc_reallocarray F
+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
@@ -1947,6 +1947,9 @@ 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 __libc_reallocarray F
+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
@@ -1942,6 +1942,9 @@ 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 __libc_reallocarray F
+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
@@ -2138,3 +2138,6 @@ 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 __libc_reallocarray F
+GLIBC_2.26 reallocarray F
@@ -1980,6 +1980,9 @@ 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 __libc_reallocarray F
+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
@@ -1985,6 +1985,9 @@ 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 __libc_reallocarray F
+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
@@ -2185,3 +2185,6 @@ 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 __libc_reallocarray F
+GLIBC_2.26 reallocarray F
@@ -99,6 +99,9 @@ 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 __libc_reallocarray F
+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
@@ -1980,6 +1980,9 @@ 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 __libc_reallocarray F
+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
@@ -1881,6 +1881,9 @@ 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 __libc_reallocarray F
+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
@@ -1866,6 +1866,9 @@ 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 __libc_reallocarray F
+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
@@ -1972,6 +1972,9 @@ 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 __libc_reallocarray F
+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
@@ -1910,6 +1910,9 @@ 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 __libc_reallocarray F
+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
@@ -2104,3 +2104,6 @@ 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 __libc_reallocarray F
+GLIBC_2.26 reallocarray F
@@ -2104,3 +2104,6 @@ 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 __libc_reallocarray F
+GLIBC_2.26 reallocarray F
@@ -2104,3 +2104,6 @@ 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 __libc_reallocarray F
+GLIBC_2.26 reallocarray F
@@ -1861,6 +1861,9 @@ 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 __libc_reallocarray F
+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
@@ -2104,3 +2104,6 @@ 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 __libc_reallocarray F
+GLIBC_2.26 reallocarray F