Blame malloc/tst-malloc-too-large.c

Packit Service 82fcde
/* Test and verify that too-large memory allocations fail with ENOMEM.
Packit Service 82fcde
   Copyright (C) 2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
/* Bug 22375 reported a regression in malloc where if after malloc'ing then
Packit Service 82fcde
   free'ing a small block of memory, malloc is then called with a really
Packit Service 82fcde
   large size argument (close to SIZE_MAX): instead of returning NULL and
Packit Service 82fcde
   setting errno to ENOMEM, malloc incorrectly returns the previously
Packit Service 82fcde
   allocated block instead.  Bug 22343 reported a similar case where
Packit Service 82fcde
   posix_memalign incorrectly returns successfully when called with an with
Packit Service 82fcde
   a really large size argument.
Packit Service 82fcde
Packit Service 82fcde
   Both of these were caused by integer overflows in the allocator when it
Packit Service 82fcde
   was trying to pad the requested size to allow for book-keeping or
Packit Service 82fcde
   alignment.  This test guards against such bugs by repeatedly allocating
Packit Service 82fcde
   and freeing small blocks of memory then trying to allocate various block
Packit Service 82fcde
   sizes larger than the memory bus width of 64-bit targets, or almost
Packit Service 82fcde
   as large as SIZE_MAX on 32-bit targets supported by glibc.  In each case,
Packit Service 82fcde
   it verifies that such impossibly large allocations correctly fail.  */
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <malloc.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <stdint.h>
Packit Service 82fcde
#include <sys/resource.h>
Packit Service 82fcde
#include <libc-diag.h>
Packit Service 82fcde
#include <support/check.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <sys/param.h>
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* This function prepares for each 'too-large memory allocation' test by
Packit Service 82fcde
   performing a small successful malloc/free and resetting errno prior to
Packit Service 82fcde
   the actual test.  */
Packit Service 82fcde
static void
Packit Service 82fcde
test_setup (void)
Packit Service 82fcde
{
Packit Service 82fcde
  void *volatile ptr = malloc (16);
Packit Service 82fcde
  TEST_VERIFY_EXIT (ptr != NULL);
Packit Service 82fcde
  free (ptr);
Packit Service 82fcde
  errno = 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* This function tests each of:
Packit Service 82fcde
   - malloc (SIZE)
Packit Service 82fcde
   - realloc (PTR_FOR_REALLOC, SIZE)
Packit Service 82fcde
   - for various values of NMEMB:
Packit Service 82fcde
    - calloc (NMEMB, SIZE/NMEMB)
Packit Service 82fcde
    - calloc (SIZE/NMEMB, NMEMB)
Packit Service 82fcde
    - reallocarray (PTR_FOR_REALLOC, NMEMB, SIZE/NMEMB)
Packit Service 82fcde
    - reallocarray (PTR_FOR_REALLOC, SIZE/NMEMB, NMEMB)
Packit Service 82fcde
   and precedes each of these tests with a small malloc/free before it.  */
Packit Service 82fcde
static void
Packit Service 82fcde
test_large_allocations (size_t size)
Packit Service 82fcde
{
Packit Service 82fcde
  void * ptr_to_realloc;
Packit Service 82fcde
Packit Service 82fcde
  test_setup ();
Packit Service 82fcde
  TEST_VERIFY (malloc (size) == NULL);
Packit Service 82fcde
  TEST_VERIFY (errno == ENOMEM);
Packit Service 82fcde
Packit Service 82fcde
  ptr_to_realloc = malloc (16);
Packit Service 82fcde
  TEST_VERIFY_EXIT (ptr_to_realloc != NULL);
Packit Service 82fcde
  test_setup ();
Packit Service 82fcde
  TEST_VERIFY (realloc (ptr_to_realloc, size) == NULL);
Packit Service 82fcde
  TEST_VERIFY (errno == ENOMEM);
Packit Service 82fcde
  free (ptr_to_realloc);
Packit Service 82fcde
Packit Service 82fcde
  for (size_t nmemb = 1; nmemb <= 8; nmemb *= 2)
Packit Service 82fcde
    if ((size % nmemb) == 0)
Packit Service 82fcde
      {
Packit Service 82fcde
        test_setup ();
Packit Service 82fcde
        TEST_VERIFY (calloc (nmemb, size / nmemb) == NULL);
Packit Service 82fcde
        TEST_VERIFY (errno == ENOMEM);
Packit Service 82fcde
Packit Service 82fcde
        test_setup ();
Packit Service 82fcde
        TEST_VERIFY (calloc (size / nmemb, nmemb) == NULL);
Packit Service 82fcde
        TEST_VERIFY (errno == ENOMEM);
Packit Service 82fcde
Packit Service 82fcde
        ptr_to_realloc = malloc (16);
Packit Service 82fcde
        TEST_VERIFY_EXIT (ptr_to_realloc != NULL);
Packit Service 82fcde
        test_setup ();
Packit Service 82fcde
        TEST_VERIFY (reallocarray (ptr_to_realloc, nmemb, size / nmemb) == NULL);
Packit Service 82fcde
        TEST_VERIFY (errno == ENOMEM);
Packit Service 82fcde
        free (ptr_to_realloc);
Packit Service 82fcde
Packit Service 82fcde
        ptr_to_realloc = malloc (16);
Packit Service 82fcde
        TEST_VERIFY_EXIT (ptr_to_realloc != NULL);
Packit Service 82fcde
        test_setup ();
Packit Service 82fcde
        TEST_VERIFY (reallocarray (ptr_to_realloc, size / nmemb, nmemb) == NULL);
Packit Service 82fcde
        TEST_VERIFY (errno == ENOMEM);
Packit Service 82fcde
        free (ptr_to_realloc);
Packit Service 82fcde
      }
Packit Service 82fcde
    else
Packit Service 82fcde
      break;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static long pagesize;
Packit Service 82fcde
Packit Service 82fcde
/* This function tests the following aligned memory allocation functions
Packit Service 82fcde
   using several valid alignments and precedes each allocation test with a
Packit Service 82fcde
   small malloc/free before it:
Packit Service 82fcde
   memalign, posix_memalign, aligned_alloc, valloc, pvalloc.  */
Packit Service 82fcde
static void
Packit Service 82fcde
test_large_aligned_allocations (size_t size)
Packit Service 82fcde
{
Packit Service 82fcde
  /* ptr stores the result of posix_memalign but since all those calls
Packit Service 82fcde
     should fail, posix_memalign should never change ptr.  We set it to
Packit Service 82fcde
     NULL here and later on we check that it remains NULL after each
Packit Service 82fcde
     posix_memalign call.  */
Packit Service 82fcde
  void * ptr = NULL;
Packit Service 82fcde
Packit Service 82fcde
  size_t align;
Packit Service 82fcde
Packit Service 82fcde
  /* All aligned memory allocation functions expect an alignment that is a
Packit Service 82fcde
     power of 2.  Given this, we test each of them with every valid
Packit Service 82fcde
     alignment from 1 thru PAGESIZE.  */
Packit Service 82fcde
  for (align = 1; align <= pagesize; align *= 2)
Packit Service 82fcde
    {
Packit Service 82fcde
      test_setup ();
Packit Service 82fcde
      TEST_VERIFY (memalign (align, size) == NULL);
Packit Service 82fcde
      TEST_VERIFY (errno == ENOMEM);
Packit Service 82fcde
Packit Service 82fcde
      /* posix_memalign expects an alignment that is a power of 2 *and* a
Packit Service 82fcde
         multiple of sizeof (void *).  */
Packit Service 82fcde
      if ((align % sizeof (void *)) == 0)
Packit Service 82fcde
        {
Packit Service 82fcde
          test_setup ();
Packit Service 82fcde
          TEST_VERIFY (posix_memalign (&ptr, align, size) == ENOMEM);
Packit Service 82fcde
          TEST_VERIFY (ptr == NULL);
Packit Service 82fcde
        }
Packit Service 82fcde
Packit Service 82fcde
      /* aligned_alloc expects a size that is a multiple of alignment.  */
Packit Service 82fcde
      if ((size % align) == 0)
Packit Service 82fcde
        {
Packit Service 82fcde
          test_setup ();
Packit Service 82fcde
          TEST_VERIFY (aligned_alloc (align, size) == NULL);
Packit Service 82fcde
          TEST_VERIFY (errno == ENOMEM);
Packit Service 82fcde
        }
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Both valloc and pvalloc return page-aligned memory.  */
Packit Service 82fcde
Packit Service 82fcde
  test_setup ();
Packit Service 82fcde
  TEST_VERIFY (valloc (size) == NULL);
Packit Service 82fcde
  TEST_VERIFY (errno == ENOMEM);
Packit Service 82fcde
Packit Service 82fcde
  test_setup ();
Packit Service 82fcde
  TEST_VERIFY (pvalloc (size) == NULL);
Packit Service 82fcde
  TEST_VERIFY (errno == ENOMEM);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
#define FOURTEEN_ON_BITS ((1UL << 14) - 1)
Packit Service 82fcde
#define FIFTY_ON_BITS ((1UL << 50) - 1)
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
do_test (void)
Packit Service 82fcde
{
Packit Service 82fcde
Packit Service 82fcde
#if __WORDSIZE >= 64
Packit Service 82fcde
Packit Service 82fcde
  /* This test assumes that none of the supported targets have an address
Packit Service 82fcde
     bus wider than 50 bits, and that therefore allocations for sizes wider
Packit Service 82fcde
     than 50 bits will fail.  Here, we ensure that the assumption continues
Packit Service 82fcde
     to be true in the future when we might have address buses wider than 50
Packit Service 82fcde
     bits.  */
Packit Service 82fcde
Packit Service 82fcde
  struct rlimit alloc_size_limit
Packit Service 82fcde
    = {
Packit Service 82fcde
        .rlim_cur = FIFTY_ON_BITS,
Packit Service 82fcde
        .rlim_max = FIFTY_ON_BITS
Packit Service 82fcde
      };
Packit Service 82fcde
Packit Service 82fcde
  setrlimit (RLIMIT_AS, &alloc_size_limit);
Packit Service 82fcde
Packit Service 82fcde
#endif /* __WORDSIZE >= 64 */
Packit Service 82fcde
Packit Service 82fcde
  DIAG_PUSH_NEEDS_COMMENT;
Packit Service 82fcde
#if __GNUC_PREREQ (7, 0)
Packit Service 82fcde
  /* GCC 7 warns about too-large allocations; here we want to test
Packit Service 82fcde
     that they fail.  */
Packit Service 82fcde
  DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  /* Aligned memory allocation functions need to be tested up to alignment
Packit Service 82fcde
     size equivalent to page size, which should be a power of 2.  */
Packit Service 82fcde
  pagesize = sysconf (_SC_PAGESIZE);
Packit Service 82fcde
  TEST_VERIFY_EXIT (powerof2 (pagesize));
Packit Service 82fcde
Packit Service 82fcde
  /* Loop 1: Ensure that all allocations with SIZE close to SIZE_MAX, i.e.
Packit Service 82fcde
     in the range (SIZE_MAX - 2^14, SIZE_MAX], fail.
Packit Service 82fcde
Packit Service 82fcde
     We can expect that this range of allocation sizes will always lead to
Packit Service 82fcde
     an allocation failure on both 64 and 32 bit targets, because:
Packit Service 82fcde
Packit Service 82fcde
     1. no currently supported 64-bit target has an address bus wider than
Packit Service 82fcde
     50 bits -- and (2^64 - 2^14) is much wider than that;
Packit Service 82fcde
Packit Service 82fcde
     2. on 32-bit targets, even though 2^32 is only 4 GB and potentially
Packit Service 82fcde
     addressable, glibc itself is more than 2^14 bytes in size, and
Packit Service 82fcde
     therefore once glibc is loaded, less than (2^32 - 2^14) bytes remain
Packit Service 82fcde
     available.  */
Packit Service 82fcde
Packit Service 82fcde
  for (size_t i = 0; i <= FOURTEEN_ON_BITS; i++)
Packit Service 82fcde
    {
Packit Service 82fcde
      test_large_allocations (SIZE_MAX - i);
Packit Service 82fcde
      test_large_aligned_allocations (SIZE_MAX - i);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
#if __WORDSIZE >= 64
Packit Service 82fcde
  /* On 64-bit targets, we need to test a much wider range of too-large
Packit Service 82fcde
     sizes, so we test at intervals of (1 << 50) that allocation sizes
Packit Service 82fcde
     ranging from SIZE_MAX down to (1 << 50) fail:
Packit Service 82fcde
     The 14 MSBs are decremented starting from "all ON" going down to 1,
Packit Service 82fcde
     the 50 LSBs are "all ON" and then "all OFF" during every iteration.  */
Packit Service 82fcde
  for (size_t msbs = FOURTEEN_ON_BITS; msbs >= 1; msbs--)
Packit Service 82fcde
    {
Packit Service 82fcde
      size_t size = (msbs << 50) | FIFTY_ON_BITS;
Packit Service 82fcde
      test_large_allocations (size);
Packit Service 82fcde
      test_large_aligned_allocations (size);
Packit Service 82fcde
Packit Service 82fcde
      size = msbs << 50;
Packit Service 82fcde
      test_large_allocations (size);
Packit Service 82fcde
      test_large_aligned_allocations (size);
Packit Service 82fcde
    }
Packit Service 82fcde
#endif /* __WORDSIZE >= 64 */
Packit Service 82fcde
Packit Service 82fcde
  DIAG_POP_NEEDS_COMMENT;
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
#include <support/test-driver.c>