diff --git a/malloc/hooks.c b/malloc/hooks.c
index ae7305b036..b77c908e28 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -227,12 +227,6 @@ malloc_check (size_t sz, const void *caller)
 {
   void *victim;
 
-  if (sz + 1 == 0)
-    {
-      __set_errno (ENOMEM);
-      return NULL;
-    }
-
   __libc_lock_lock (main_arena.mutex);
   top_check ();
   victim = _int_malloc (&main_arena, sz + 1);
@@ -269,11 +263,6 @@ realloc_check (void *oldmem, size_t bytes, const void *caller)
   void *newmem = 0;
   unsigned char *magic_p;
 
-  if (bytes + 1 == 0)
-    {
-      __set_errno (ENOMEM);
-      return NULL;
-    }
   if (oldmem == 0)
     return malloc_check (bytes, NULL);
 
@@ -289,7 +278,7 @@ 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);
+  nb = request2size (bytes + 1);
   __libc_lock_lock (main_arena.mutex);
 
   if (chunk_is_mmapped (oldp))
@@ -320,8 +309,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);
     }
 
@@ -362,13 +349,6 @@ memalign_check (size_t alignment, size_t bytes, const void *caller)
       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))
     {
diff --git a/malloc/malloc.c b/malloc/malloc.c
index c33709e966..bb80809983 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -247,6 +247,9 @@
 /* For SINGLE_THREAD_P.  */
 #include <sysdep-cancel.h>
 
+/* For INT_MULTIPLY_WRAPV.  */
+#include <intprops.h>
+
 /*
   Debugging:
 
@@ -1187,39 +1190,15 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   ((uintptr_t)(MALLOC_ALIGNMENT == 2 * SIZE_SZ ? (p) : chunk2mem (p)) \
    & MALLOC_ALIGN_MASK)
 
+/* pad request bytes into a usable size -- internal version */
 
-/*
-   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))
+#define padsize (SIZE_SZ + MALLOC_ALIGN_MASK)
 
-/* pad request bytes into a usable size -- internal version */
+#define request2size(req)                     \
+  (((req) + padsize < MINSIZE)  ?             \
+   MINSIZE :                                  \
+   ((req) + padsize) & ~MALLOC_ALIGN_MASK)
 
-#define request2size(req)                                         \
-  (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?             \
-   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;			    \
-    }				    \
-})
 
 /*
    --------------- Physical chunk operations ---------------
@@ -3109,14 +3088,20 @@ __libc_malloc (size_t bytes)
   mstate ar_ptr;
   void *victim;
 
+  if (__glibc_unlikely (bytes > PTRDIFF_MAX - padsize))
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+
   void *(*hook) (size_t, const void *)
     = atomic_forced_read (__malloc_hook);
   if (__builtin_expect (hook != NULL, 0))
     return (*hook)(bytes, RETURN_ADDRESS (0));
+
 #if USE_TCACHE
   /* int_free also calls request2size, be careful to not pad twice.  */
-  size_t tbytes;
-  checked_request2size (bytes, tbytes);
+  size_t tbytes = request2size (bytes);
   size_t tc_idx = csize2tidx (tbytes);
 
   MAYBE_INIT_TCACHE ();
@@ -3213,6 +3198,12 @@ __libc_realloc (void *oldmem, size_t bytes)
 
   void *newp;             /* chunk to return */
 
+  if (__glibc_unlikely (bytes > PTRDIFF_MAX - padsize))
+    {
+      __set_errno (ENOMEM);
+      return 0;
+    }
+
   void *(*hook) (void *, size_t, const void *) =
     atomic_forced_read (__realloc_hook);
   if (__builtin_expect (hook != NULL, 0))
@@ -3253,7 +3244,7 @@ __libc_realloc (void *oldmem, size_t bytes)
       && !DUMPED_MAIN_ARENA_CHUNK (oldp))
       malloc_printerr ("realloc(): invalid pointer");
 
-  checked_request2size (bytes, nb);
+  nb = request2size (bytes);
 
   if (chunk_is_mmapped (oldp))
     {
@@ -3342,6 +3333,12 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
   mstate ar_ptr;
   void *p;
 
+  if (__glibc_unlikely (bytes > PTRDIFF_MAX - padsize))
+    {
+      __set_errno (ENOMEM);
+      return 0;
+    }
+
   void *(*hook) (size_t, size_t, const void *) =
     atomic_forced_read (__memalign_hook);
   if (__builtin_expect (hook != NULL, 0))
@@ -3363,14 +3360,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))
     {
@@ -3432,7 +3421,7 @@ __libc_pvalloc (size_t bytes)
   size_t rounded_bytes = ALIGN_UP (bytes, pagesize);
 
   /* Check for overflow.  */
-  if (bytes > SIZE_MAX - 2 * pagesize - MINSIZE)
+  if (__glibc_unlikely (bytes > PTRDIFF_MAX - 2 * pagesize - MINSIZE))
     {
       __set_errno (ENOMEM);
       return 0;
@@ -3452,24 +3441,18 @@ __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 (INT_MULTIPLY_WRAPV (n, elem_size, &bytes)
+      || __glibc_unlikely (bytes > PTRDIFF_MAX - padsize))
     {
-      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;
@@ -3477,8 +3460,6 @@ __libc_calloc (size_t n, size_t elem_size)
       return memset (mem, 0, sz);
     }
 
-  sz = bytes;
-
   MAYBE_INIT_TCACHE ();
 
   if (SINGLE_THREAD_P)
@@ -3621,16 +3602,7 @@ _int_malloc (mstate av, size_t bytes)
   size_t tcache_unsorted_count;	    /* count of unsorted chunks processed */
 #endif
 
-  /*
-     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
-     that are so large that they wrap around zero when padded and
-     aligned.
-   */
-
-  checked_request2size (bytes, nb);
+  nb = request2size (bytes);
 
   /* There are no usable arenas.  Fall back to sysmalloc to get a chunk from
      mmap.  */
@@ -4741,22 +4713,18 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
   unsigned long remainder_size;   /* its size */
   INTERNAL_SIZE_T size;
 
-
-
-  checked_request2size (bytes, nb);
+  if (__glibc_unlikely (bytes > PTRDIFF_MAX - padsize))
+    {
+      __set_errno (ENOMEM);
+      return 0;
+    }
 
   /*
      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;
-    }
+  nb = request2size (bytes);
 
   /* Call malloc with worst case padding to hit alignment. */
 
diff --git a/malloc/malloc.h b/malloc/malloc.h
index 3e7c447be1..d3c4841f11 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 10fb136528..7e4721b78c 100644
--- a/malloc/tst-malloc-too-large.c
+++ b/malloc/tst-malloc-too-large.c
@@ -226,6 +226,16 @@ do_test (void)
       test_large_aligned_allocations (SIZE_MAX - i);
     }
 
+  /* Allocation larger than PTRDIFF_MAX does play well with C standard,
+     since pointer substraction within the object might overflow ptrdiff_t
+     resulting in undefined behaviour.  To prevent it malloc function fail
+     for such allocations.  */
+  for (size_t i = 0; 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 904bf9491d..3cba6dc7d3 100644
--- a/malloc/tst-memalign.c
+++ b/malloc/tst-memalign.c
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <libc-diag.h>
 
 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 81b4c05ef4..5c4188a7ac 100644
--- a/malloc/tst-posix_memalign.c
+++ b/malloc/tst-posix_memalign.c
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <libc-diag.h>
 
 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 aa391447ee..cd3b46d68b 100644
--- a/malloc/tst-pvalloc.c
+++ b/malloc/tst-pvalloc.c
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <libc-diag.h>
 
 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 b0d80ebc58..784f77e7b0 100644
--- a/malloc/tst-reallocarray.c
+++ b/malloc/tst-reallocarray.c
@@ -20,6 +20,23 @@
 #include <malloc.h>
 #include <string.h>
 #include <support/check.h>
+#include <libc-diag.h>
+
+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 ba57d9559a..b37edb6c74 100644
--- a/malloc/tst-valloc.c
+++ b/malloc/tst-valloc.c
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <libc-diag.h>
 
 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 870e02d904..303c90ff11 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,13 +571,14 @@ 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
 /* Allocate memory of SIZE bytes with an alignment of ALIGNMENT.  */
 extern int posix_memalign (void **__memptr, size_t __alignment, size_t __size)
-     __THROW __nonnull ((1)) __wur;
+     __THROW __nonnull ((1)) __attribute_alloc_size__ ((3)) __wur;
 #endif
 
 #ifdef __USE_ISOC11
