From 9bf8e29ca136094f73f69f725f15c51facc97206 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Tue, 18 Dec 2018 16:30:56 -0200 Subject: [PATCH] malloc: make malloc fail with requests larger than PTRDIFF_MAX (BZ#23741) As discussed previously on libc-alpha [1], this patch follows up the idea and add both the __attribute_alloc_size__ on malloc functions (malloc, calloc, realloc, reallocarray, valloc, pvalloc, and memalign) and limit maximum requested allocation size to up PTRDIFF_MAX (taking into consideration internal padding and alignment). This aligns glibc with gcc expected size defined by default warning -Walloc-size-larger-than value which warns for allocation larger than PTRDIFF_MAX. It also aligns with gcc expectation regarding libc and expected size, such as described in PR#67999 [2] and previously discussed ISO C11 issues [3] on libc-alpha. From the RFC thread [4] and previous discussion, it seems that consensus is only to limit such requested size for malloc functions, not the system allocation one (mmap, sbrk, etc.). The implementation changes checked_request2size to check for both overflow and maximum object size up to PTRDIFF_MAX. No additional checks are done on sysmalloc, so it can still issue mmap with values larger than PTRDIFF_T depending on the requested size. The __attribute_alloc_size__ is for functions that return a pointer only, which means it cannot be applied to posix_memalign (see remarks in GCC PR#87683 [5]). The runtimes checks to limit maximum requested allocation size does applies to posix_memalign. Checked on x86_64-linux-gnu and i686-linux-gnu. [1] https://sourceware.org/ml/libc-alpha/2018-11/msg00223.html [2] https://gcc.gnu.org/bugzilla//show_bug.cgi?id=67999 [3] https://sourceware.org/ml/libc-alpha/2011-12/msg00066.html [4] https://sourceware.org/ml/libc-alpha/2018-11/msg00224.html [5] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87683 [BZ #23741] * malloc/hooks.c (malloc_check, realloc_check): Use __builtin_add_overflow on overflow check and adapt to checked_request2size change. * malloc/malloc.c (__libc_malloc, __libc_realloc, _mid_memalign, __libc_pvalloc, __libc_calloc, _int_memalign): Limit maximum allocation size to PTRDIFF_MAX. (REQUEST_OUT_OF_RANGE): Remove macro. (checked_request2size): Change to inline function and limit maximum requested size to PTRDIFF_MAX. (__libc_malloc, __libc_realloc, _int_malloc, _int_memalign): Limit maximum allocation size to PTRDIFF_MAX. (_mid_memalign): Use _int_memalign call for overflow check. (__libc_pvalloc): Use __builtin_add_overflow on overflow check. (__libc_calloc): Use __builtin_mul_overflow for overflow check and limit maximum requested size to PTRDIFF_MAX. * malloc/malloc.h (malloc, calloc, realloc, reallocarray, memalign, valloc, pvalloc): Add __attribute_alloc_size__. * stdlib/stdlib.h (malloc, realloc, reallocarray, valloc): Likewise. * malloc/tst-malloc-too-large.c (do_test): Add check for allocation larger than PTRDIFF_MAX. * malloc/tst-memalign.c (do_test): Disable -Walloc-size-larger-than= around tests of malloc with negative sizes. * malloc/tst-posix_memalign.c (do_test): Likewise. * malloc/tst-pvalloc.c (do_test): Likewise. * malloc/tst-valloc.c (do_test): Likewise. * malloc/tst-reallocarray.c (do_test): Replace call to reallocarray with resulting size allocation larger than PTRDIFF_MAX with reallocarray_nowarn. (reallocarray_nowarn): New function. * NEWS: Mention the malloc function semantic change. --- ChangeLog | 34 +++++++++++ NEWS | 6 ++ malloc/hooks.c | 17 +++--- malloc/malloc.c | 112 +++++++++++++++------------------- malloc/malloc.h | 17 +++--- malloc/tst-malloc-too-large.c | 49 +++++++++++++++ malloc/tst-memalign.c | 10 +++ malloc/tst-posix_memalign.c | 10 +++ malloc/tst-pvalloc.c | 10 +++ malloc/tst-reallocarray.c | 27 ++++++-- malloc/tst-valloc.c | 10 +++ stdlib/stdlib.h | 13 ++-- 12 files changed, 227 insertions(+), 88 deletions(-) diff --git a/ChangeLog b/ChangeLog index f68bba94c7..79e9589aaf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +2019-04-18 Adhemerval Zanella + + [BZ #23741] + * malloc/hooks.c (malloc_check, realloc_check): Use + __builtin_add_overflow on overflow check and adapt to + checked_request2size change. + * malloc/malloc.c (__libc_malloc, __libc_realloc, _mid_memalign, + __libc_pvalloc, __libc_calloc, _int_memalign): Limit maximum + allocation size to PTRDIFF_MAX. + (REQUEST_OUT_OF_RANGE): Remove macro. + (checked_request2size): Change to inline function and limit maximum + requested size to PTRDIFF_MAX. + (__libc_malloc, __libc_realloc, _int_malloc, _int_memalign): Limit + maximum allocation size to PTRDIFF_MAX. + (_mid_memalign): Use _int_memalign call for overflow check. + (__libc_pvalloc): Use __builtin_add_overflow on overflow check. + (__libc_calloc): Use __builtin_mul_overflow for overflow check and + limit maximum requested size to PTRDIFF_MAX. + * malloc/malloc.h (malloc, calloc, realloc, reallocarray, memalign, + valloc, pvalloc): Add __attribute_alloc_size__. + * stdlib/stdlib.h (malloc, realloc, reallocarray, valloc): Likewise. + * malloc/tst-malloc-too-large.c (do_test): Add check for allocation + larger than PTRDIFF_MAX. + * malloc/tst-memalign.c (do_test): Disable -Walloc-size-larger-than= + around tests of malloc with negative sizes. + * malloc/tst-posix_memalign.c (do_test): Likewise. + * malloc/tst-pvalloc.c (do_test): Likewise. + * malloc/tst-valloc.c (do_test): Likewise. + * malloc/tst-reallocarray.c (do_test): Replace call to reallocarray + with resulting size allocation larger than PTRDIFF_MAX with + reallocarray_nowarn. + (reallocarray_nowarn): New function. + * NEWS: Mention the malloc function semantic change. + 2019-04-17 Adhemerval Zanella * sysdeps/powerpc/fpu/s_fma.c: Fix format. diff --git a/NEWS b/NEWS index b58e2469d4..db1ca8125b 100644 --- a/NEWS +++ b/NEWS @@ -160,6 +160,12 @@ Deprecated and removed features, and other changes affecting compatibility: as all functions that call vscanf, vfscanf, or vsscanf are annotated with __attribute__ ((format (scanf, ...))). +* Memory allocation functions malloc, calloc, realloc, reallocarray, valloc, + pvalloc, memalign, and posix_memalign fail now with total object size + larger than PTRDIFF_MAX. This is to avoid potential undefined behavior with + pointer subtraction within the allocated object, where results might + overflow the ptrdiff_t type. + Changes to build and runtime requirements: * Python 3.4 or later is required to build the GNU C Library. diff --git a/malloc/hooks.c b/malloc/hooks.c index 46789736f3..b7a453f6d2 100644 --- a/malloc/hooks.c +++ b/malloc/hooks.c @@ -226,8 +226,9 @@ static void * malloc_check (size_t sz, const void *caller) { void *victim; + size_t nb; - if (sz + 1 == 0) + if (__builtin_add_overflow (sz, 1, &nb)) { __set_errno (ENOMEM); return NULL; @@ -235,7 +236,7 @@ malloc_check (size_t sz, const void *caller) __libc_lock_lock (main_arena.mutex); top_check (); - victim = _int_malloc (&main_arena, sz + 1); + victim = _int_malloc (&main_arena, nb); __libc_lock_unlock (main_arena.mutex); return mem2mem_check (victim, sz); } @@ -268,8 +269,9 @@ realloc_check (void *oldmem, size_t bytes, const void *caller) INTERNAL_SIZE_T nb; void *newmem = 0; unsigned char *magic_p; + size_t rb; - if (bytes + 1 == 0) + if (__builtin_add_overflow (bytes, 1, &rb)) { __set_errno (ENOMEM); return NULL; @@ -289,7 +291,9 @@ realloc_check (void *oldmem, size_t bytes, const void *caller) malloc_printerr ("realloc(): invalid pointer"); const INTERNAL_SIZE_T oldsize = chunksize (oldp); - checked_request2size (bytes + 1, nb); + if (!checked_request2size (rb, &nb)) + goto invert; + __libc_lock_lock (main_arena.mutex); if (chunk_is_mmapped (oldp)) @@ -308,7 +312,7 @@ realloc_check (void *oldmem, size_t bytes, const void *caller) { /* Must alloc, copy, free. */ top_check (); - newmem = _int_malloc (&main_arena, bytes + 1); + newmem = _int_malloc (&main_arena, rb); if (newmem) { memcpy (newmem, oldmem, oldsize - 2 * SIZE_SZ); @@ -320,8 +324,6 @@ realloc_check (void *oldmem, size_t bytes, const void *caller) else { top_check (); - INTERNAL_SIZE_T nb; - checked_request2size (bytes + 1, nb); newmem = _int_realloc (&main_arena, oldp, oldsize, nb); } @@ -334,6 +336,7 @@ realloc_check (void *oldmem, size_t bytes, const void *caller) /* mem2chunk_check changed the magic byte in the old chunk. If newmem is NULL, then the old chunk will still be used though, so we need to invert that change here. */ +invert: if (newmem == NULL) *magic_p ^= 0xFF; DIAG_POP_NEEDS_COMMENT; diff --git a/malloc/malloc.c b/malloc/malloc.c index 801ba1f499..0e3d4dd516 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -1187,17 +1187,6 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ((uintptr_t)(MALLOC_ALIGNMENT == 2 * SIZE_SZ ? (p) : chunk2mem (p)) \ & MALLOC_ALIGN_MASK) - -/* - Check if a request is so large that it would wrap around zero when - padded and aligned. To simplify some other code, the bound is made - low enough so that adding MINSIZE will also not wrap around zero. - */ - -#define REQUEST_OUT_OF_RANGE(req) \ - ((unsigned long) (req) >= \ - (unsigned long) (INTERNAL_SIZE_T) (-2 * MINSIZE)) - /* pad request bytes into a usable size -- internal version */ #define request2size(req) \ @@ -1205,21 +1194,18 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ MINSIZE : \ ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) -/* Same, except also perform an argument and result check. First, we check - that the padding done by request2size didn't result in an integer - overflow. Then we check (using REQUEST_OUT_OF_RANGE) that the resulting - size isn't so large that a later alignment would lead to another integer - overflow. */ -#define checked_request2size(req, sz) \ -({ \ - (sz) = request2size (req); \ - if (((sz) < (req)) \ - || REQUEST_OUT_OF_RANGE (sz)) \ - { \ - __set_errno (ENOMEM); \ - return 0; \ - } \ -}) +/* Check if REQ overflows when padded and aligned and if the resulting value + is less than PTRDIFF_T. Returns TRUE and the requested size or MINSIZE in + case the value is less than MINSIZE on SZ or false if any of the previous + check fail. */ +static inline bool +checked_request2size (size_t req, size_t *sz) __nonnull (1) +{ + if (__glibc_unlikely (req > PTRDIFF_MAX)) + return false; + *sz = request2size (req); + return true; +} /* --------------- Physical chunk operations --------------- @@ -3037,6 +3023,9 @@ __libc_malloc (size_t bytes) mstate ar_ptr; void *victim; + _Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2, + "PTRDIFF_MAX is not more than half of SIZE_MAX"); + void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook); if (__builtin_expect (hook != NULL, 0)) @@ -3044,7 +3033,11 @@ __libc_malloc (size_t bytes) #if USE_TCACHE /* int_free also calls request2size, be careful to not pad twice. */ size_t tbytes; - checked_request2size (bytes, tbytes); + if (!checked_request2size (bytes, &tbytes)) + { + __set_errno (ENOMEM); + return NULL; + } size_t tc_idx = csize2tidx (tbytes); MAYBE_INIT_TCACHE (); @@ -3181,7 +3174,11 @@ __libc_realloc (void *oldmem, size_t bytes) && !DUMPED_MAIN_ARENA_CHUNK (oldp)) malloc_printerr ("realloc(): invalid pointer"); - checked_request2size (bytes, nb); + if (!checked_request2size (bytes, &nb)) + { + __set_errno (ENOMEM); + return NULL; + } if (chunk_is_mmapped (oldp)) { @@ -3291,13 +3288,6 @@ _mid_memalign (size_t alignment, size_t bytes, void *address) return 0; } - /* Check for overflow. */ - if (bytes > SIZE_MAX - alignment - MINSIZE) - { - __set_errno (ENOMEM); - return 0; - } - /* Make sure alignment is power of 2. */ if (!powerof2 (alignment)) @@ -3357,14 +3347,16 @@ __libc_pvalloc (size_t bytes) void *address = RETURN_ADDRESS (0); size_t pagesize = GLRO (dl_pagesize); - size_t rounded_bytes = ALIGN_UP (bytes, pagesize); - - /* Check for overflow. */ - if (bytes > SIZE_MAX - 2 * pagesize - MINSIZE) + size_t rounded_bytes; + /* ALIGN_UP with overflow check. */ + if (__glibc_unlikely (__builtin_add_overflow (bytes, + pagesize - 1, + &rounded_bytes))) { __set_errno (ENOMEM); return 0; } + rounded_bytes = rounded_bytes & -(pagesize - 1); return _mid_memalign (pagesize, rounded_bytes, address); } @@ -3374,30 +3366,24 @@ __libc_calloc (size_t n, size_t elem_size) { mstate av; mchunkptr oldtop, p; - INTERNAL_SIZE_T bytes, sz, csz, oldtopsize; + INTERNAL_SIZE_T sz, csz, oldtopsize; void *mem; unsigned long clearsize; unsigned long nclears; INTERNAL_SIZE_T *d; + ptrdiff_t bytes; - /* 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 (__glibc_unlikely (__builtin_mul_overflow (n, elem_size, &bytes))) { - if (elem_size != 0 && bytes / elem_size != n) - { - __set_errno (ENOMEM); - return 0; - } + __set_errno (ENOMEM); + return NULL; } + sz = bytes; void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook); if (__builtin_expect (hook != NULL, 0)) { - sz = bytes; mem = (*hook)(sz, RETURN_ADDRESS (0)); if (mem == 0) return 0; @@ -3405,8 +3391,6 @@ __libc_calloc (size_t n, size_t elem_size) return memset (mem, 0, sz); } - sz = bytes; - MAYBE_INIT_TCACHE (); if (SINGLE_THREAD_P) @@ -3553,12 +3537,16 @@ _int_malloc (mstate av, size_t bytes) Convert request size to internal form by adding SIZE_SZ bytes overhead plus possibly more to obtain necessary alignment and/or to obtain a size of at least MINSIZE, the smallest allocatable - size. Also, checked_request2size traps (returning 0) request sizes + size. Also, checked_request2size returns false for request sizes that are so large that they wrap around zero when padded and aligned. */ - checked_request2size (bytes, nb); + if (!checked_request2size (bytes, &nb)) + { + __set_errno (ENOMEM); + return NULL; + } /* There are no usable arenas. Fall back to sysmalloc to get a chunk from mmap. */ @@ -4680,21 +4668,17 @@ _int_memalign (mstate av, size_t alignment, size_t bytes) - checked_request2size (bytes, nb); + if (!checked_request2size (bytes, &nb)) + { + __set_errno (ENOMEM); + return NULL; + } /* Strategy: find a spot within that chunk that meets the alignment request, and then possibly free the leading and trailing space. */ - - /* Check for overflow. */ - if (nb > SIZE_MAX - alignment - MINSIZE) - { - __set_errno (ENOMEM); - return 0; - } - /* Call malloc with worst case padding to hit alignment. */ m = (char *) (_int_malloc (av, nb + alignment + MINSIZE)); diff --git a/malloc/malloc.h b/malloc/malloc.h index 4428edc06f..523f1b1af5 100644 --- a/malloc/malloc.h +++ b/malloc/malloc.h @@ -35,11 +35,12 @@ __BEGIN_DECLS /* Allocate SIZE bytes of memory. */ -extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur; +extern void *malloc (size_t __size) __THROW __attribute_malloc__ + __attribute_alloc_size__ ((1)) __wur; /* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ extern void *calloc (size_t __nmemb, size_t __size) -__THROW __attribute_malloc__ __wur; +__THROW __attribute_malloc__ __attribute_alloc_size__ ((1, 2)) __wur; /* Re-allocate the previously allocated block in __ptr, making the new block SIZE bytes long. */ @@ -47,7 +48,7 @@ __THROW __attribute_malloc__ __wur; the same pointer that was passed to it, aliasing needs to be allowed between objects pointed by the old and new pointers. */ extern void *realloc (void *__ptr, size_t __size) -__THROW __attribute_warn_unused_result__; +__THROW __attribute_warn_unused_result__ __attribute_alloc_size__ ((2)); /* Re-allocate the previously allocated block in PTR, making the new block large enough for NMEMB elements of SIZE bytes each. */ @@ -55,21 +56,23 @@ __THROW __attribute_warn_unused_result__; 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__; +__THROW __attribute_warn_unused_result__ __attribute_alloc_size__ ((2, 3)); /* Free a block allocated by `malloc', `realloc' or `calloc'. */ extern void free (void *__ptr) __THROW; /* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ extern void *memalign (size_t __alignment, size_t __size) -__THROW __attribute_malloc__ __wur; +__THROW __attribute_malloc__ __attribute_alloc_size__ ((2)) __wur; /* Allocate SIZE bytes on a page boundary. */ -extern void *valloc (size_t __size) __THROW __attribute_malloc__ __wur; +extern void *valloc (size_t __size) __THROW __attribute_malloc__ + __attribute_alloc_size__ ((1)) __wur; /* Equivalent to valloc(minimum-page-that-holds(n)), that is, round up __size to nearest pagesize. */ -extern void *pvalloc (size_t __size) __THROW __attribute_malloc__ __wur; +extern void *pvalloc (size_t __size) __THROW __attribute_malloc__ + __attribute_alloc_size__ ((1)) __wur; /* Underlying allocation function; successive calls should return contiguous pieces of memory. */ diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c index 15e25f558e..c1c8cb88cc 100644 --- a/malloc/tst-malloc-too-large.c +++ b/malloc/tst-malloc-too-large.c @@ -72,13 +72,28 @@ test_large_allocations (size_t size) void * ptr_to_realloc; test_setup (); + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we want to test + that they fail. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif TEST_VERIFY (malloc (size) == NULL); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif TEST_VERIFY (errno == ENOMEM); ptr_to_realloc = malloc (16); TEST_VERIFY_EXIT (ptr_to_realloc != NULL); test_setup (); +#if __GNUC_PREREQ (7, 0) + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif TEST_VERIFY (realloc (ptr_to_realloc, size) == NULL); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif TEST_VERIFY (errno == ENOMEM); free (ptr_to_realloc); @@ -135,7 +150,13 @@ test_large_aligned_allocations (size_t size) for (align = 1; align <= pagesize; align *= 2) { test_setup (); +#if __GNUC_PREREQ (7, 0) + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif TEST_VERIFY (memalign (align, size) == NULL); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif TEST_VERIFY (errno == ENOMEM); /* posix_memalign expects an alignment that is a power of 2 *and* a @@ -151,7 +172,13 @@ test_large_aligned_allocations (size_t size) if ((size % align) == 0) { test_setup (); +#if __GNUC_PREREQ (7, 0) + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif TEST_VERIFY (aligned_alloc (align, size) == NULL); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif TEST_VERIFY (errno == ENOMEM); } } @@ -159,11 +186,23 @@ test_large_aligned_allocations (size_t size) /* Both valloc and pvalloc return page-aligned memory. */ test_setup (); +#if __GNUC_PREREQ (7, 0) + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif TEST_VERIFY (valloc (size) == NULL); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif TEST_VERIFY (errno == ENOMEM); test_setup (); +#if __GNUC_PREREQ (7, 0) + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif TEST_VERIFY (pvalloc (size) == NULL); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif TEST_VERIFY (errno == ENOMEM); } @@ -226,6 +265,16 @@ do_test (void) test_large_aligned_allocations (SIZE_MAX - i); } + /* Allocation larger than PTRDIFF_MAX does play well with C standard, + since pointer subtraction within the object might overflow ptrdiff_t + resulting in undefined behavior. To prevent it malloc function fail + for such allocations. */ + for (size_t i = 1; i <= FOURTEEN_ON_BITS; i++) + { + test_large_allocations (PTRDIFF_MAX + i); + test_large_aligned_allocations (PTRDIFF_MAX + i); + } + #if __WORDSIZE >= 64 /* On 64-bit targets, we need to test a much wider range of too-large sizes, so we test at intervals of (1 << 50) that allocation sizes diff --git a/malloc/tst-memalign.c b/malloc/tst-memalign.c index a6a9140a3d..e7997518cb 100644 --- a/malloc/tst-memalign.c +++ b/malloc/tst-memalign.c @@ -21,6 +21,7 @@ #include #include #include +#include static int errors = 0; @@ -41,9 +42,18 @@ do_test (void) errno = 0; + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we want to test + that they fail. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif /* An attempt to allocate a huge value should return NULL and set errno to ENOMEM. */ p = memalign (sizeof (void *), -1); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif save = errno; diff --git a/malloc/tst-posix_memalign.c b/malloc/tst-posix_memalign.c index bcf1592679..fc46955c51 100644 --- a/malloc/tst-posix_memalign.c +++ b/malloc/tst-posix_memalign.c @@ -21,6 +21,7 @@ #include #include #include +#include static int errors = 0; @@ -41,9 +42,18 @@ do_test (void) p = NULL; + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we want to test + that they fail. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif /* An attempt to allocate a huge value should return ENOMEM and p should remain NULL. */ ret = posix_memalign (&p, sizeof (void *), -1); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif if (ret != ENOMEM) merror ("posix_memalign (&p, sizeof (void *), -1) succeeded."); diff --git a/malloc/tst-pvalloc.c b/malloc/tst-pvalloc.c index 0b4baba67a..c0356c0c71 100644 --- a/malloc/tst-pvalloc.c +++ b/malloc/tst-pvalloc.c @@ -21,6 +21,7 @@ #include #include #include +#include static int errors = 0; @@ -41,9 +42,18 @@ do_test (void) errno = 0; + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we want to test + that they fail. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif /* An attempt to allocate a huge value should return NULL and set errno to ENOMEM. */ p = pvalloc (-1); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif save = errno; diff --git a/malloc/tst-reallocarray.c b/malloc/tst-reallocarray.c index 9a71ec7f45..fd50d4e36b 100644 --- a/malloc/tst-reallocarray.c +++ b/malloc/tst-reallocarray.c @@ -20,6 +20,23 @@ #include #include #include +#include + +static void * +reallocarray_nowarn (void *ptr, size_t nmemb, size_t size) +{ +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we want to test + that they fail. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif + void *ret = reallocarray (ptr, nmemb, size); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif + return ret; +} + static int do_test (void) @@ -34,24 +51,24 @@ do_test (void) /* Test overflow detection. */ errno = 0; - ptr = reallocarray (NULL, max, 2); + ptr = reallocarray_nowarn (NULL, max, 2); TEST_VERIFY (!ptr); TEST_VERIFY (errno == ENOMEM); errno = 0; - ptr = reallocarray (NULL, 2, max); + ptr = reallocarray_nowarn (NULL, 2, max); TEST_VERIFY (!ptr); TEST_VERIFY (errno == ENOMEM); a = 65537; b = max/65537 + 1; errno = 0; - ptr = reallocarray (NULL, a, b); + ptr = reallocarray_nowarn (NULL, a, b); TEST_VERIFY (!ptr); TEST_VERIFY (errno == ENOMEM); errno = 0; - ptr = reallocarray (NULL, b, a); + ptr = reallocarray_nowarn (NULL, b, a); TEST_VERIFY (!ptr); TEST_VERIFY (errno == ENOMEM); @@ -97,7 +114,7 @@ do_test (void) /* Overflow should leave buffer untouched. */ errno = 0; - ptr2 = reallocarray (ptr, 2, ~(size_t)0); + ptr2 = reallocarray_nowarn (ptr, 2, ~(size_t)0); TEST_VERIFY (!ptr2); TEST_VERIFY (errno == ENOMEM); diff --git a/malloc/tst-valloc.c b/malloc/tst-valloc.c index a2e27c1e91..1a1a2d2500 100644 --- a/malloc/tst-valloc.c +++ b/malloc/tst-valloc.c @@ -21,6 +21,7 @@ #include #include #include +#include static int errors = 0; @@ -41,9 +42,18 @@ do_test (void) errno = 0; + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we want to test + that they fail. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif /* An attempt to allocate a huge value should return NULL and set errno to ENOMEM. */ p = valloc (-1); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif save = errno; diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h index 15debe1e31..a9fd989d39 100644 --- a/stdlib/stdlib.h +++ b/stdlib/stdlib.h @@ -536,10 +536,11 @@ extern int lcong48_r (unsigned short int __param[7], #endif /* Use misc or X/Open. */ /* Allocate SIZE bytes of memory. */ -extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur; +extern void *malloc (size_t __size) __THROW __attribute_malloc__ + __attribute_alloc_size__ ((1)) __wur; /* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ extern void *calloc (size_t __nmemb, size_t __size) - __THROW __attribute_malloc__ __wur; + __THROW __attribute_malloc__ __attribute_alloc_size__ ((1, 2)) __wur; /* Re-allocate the previously allocated block in PTR, making the new block SIZE bytes long. */ @@ -547,7 +548,7 @@ extern void *calloc (size_t __nmemb, size_t __size) the same pointer that was passed to it, aliasing needs to be allowed between objects pointed by the old and new pointers. */ extern void *realloc (void *__ptr, size_t __size) - __THROW __attribute_warn_unused_result__; + __THROW __attribute_warn_unused_result__ __attribute_alloc_size__ ((2)); #ifdef __USE_MISC /* Re-allocate the previously allocated block in PTR, making the new @@ -556,7 +557,8 @@ extern void *realloc (void *__ptr, size_t __size) 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__; + __THROW __attribute_warn_unused_result__ + __attribute_alloc_size__ ((2, 3)); #endif /* Free a block allocated by `malloc', `realloc' or `calloc'. */ @@ -569,7 +571,8 @@ extern void free (void *__ptr) __THROW; #if (defined __USE_XOPEN_EXTENDED && !defined __USE_XOPEN2K) \ || defined __USE_MISC /* Allocate SIZE bytes on a page boundary. The storage cannot be freed. */ -extern void *valloc (size_t __size) __THROW __attribute_malloc__ __wur; +extern void *valloc (size_t __size) __THROW __attribute_malloc__ + __attribute_alloc_size__ ((1)) __wur; #endif #ifdef __USE_XOPEN2K