Blame gl/malloca.c

Packit Service 991b93
/* Safe automatic memory allocation.
Packit Service 991b93
   Copyright (C) 2003, 2006-2007, 2009-2020 Free Software Foundation, Inc.
Packit Service 991b93
   Written by Bruno Haible <bruno@clisp.org>, 2003, 2018.
Packit Service 991b93
Packit Service 991b93
   This program is free software; you can redistribute it and/or modify
Packit Service 991b93
   it under the terms of the GNU Lesser General Public License as published by
Packit Service 991b93
   the Free Software Foundation; either version 2.1, or (at your option)
Packit Service 991b93
   any later version.
Packit Service 991b93
Packit Service 991b93
   This program is distributed in the hope that it will be useful,
Packit Service 991b93
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 991b93
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 991b93
   GNU Lesser General Public License for more details.
Packit Service 991b93
Packit Service 991b93
   You should have received a copy of the GNU Lesser General Public License
Packit Service 991b93
   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
Packit Service 991b93
Packit Service 991b93
#define _GL_USE_STDLIB_ALLOC 1
Packit Service 991b93
#include <config.h>
Packit Service 991b93
Packit Service 991b93
/* Specification.  */
Packit Service 991b93
#include "malloca.h"
Packit Service 991b93
Packit Service 991b93
#include "verify.h"
Packit Service 991b93
Packit Service 991b93
/* The speed critical point in this file is freea() applied to an alloca()
Packit Service 991b93
   result: it must be fast, to match the speed of alloca().  The speed of
Packit Service 991b93
   mmalloca() and freea() in the other case are not critical, because they
Packit Service 991b93
   are only invoked for big memory sizes.
Packit Service 991b93
   Here we use a bit in the address as an indicator, an idea by Ondřej Bílka.
Packit Service 991b93
   malloca() can return three types of pointers:
Packit Service 991b93
     - Pointers ≡ 0 mod 2*sa_alignment_max come from stack allocation.
Packit Service 991b93
     - Pointers ≡ sa_alignment_max mod 2*sa_alignment_max come from heap
Packit Service 991b93
       allocation.
Packit Service 991b93
     - NULL comes from a failed heap allocation.  */
Packit Service 991b93
Packit Service 991b93
/* Type for holding very small pointer differences.  */
Packit Service 991b93
typedef unsigned char small_t;
Packit Service 991b93
/* Verify that it is wide enough.  */
Packit Service 991b93
verify (2 * sa_alignment_max - 1 <= (small_t) -1);
Packit Service 991b93
Packit Service 991b93
void *
Packit Service 991b93
mmalloca (size_t n)
Packit Service 991b93
{
Packit Service 991b93
#if HAVE_ALLOCA
Packit Service 991b93
  /* Allocate one more word, used to determine the address to pass to freea(),
Packit Service 991b93
     and room for the alignment ≡ sa_alignment_max mod 2*sa_alignment_max.  */
Packit Service 991b93
  size_t nplus = n + sizeof (small_t) + 2 * sa_alignment_max - 1;
Packit Service 991b93
Packit Service 991b93
  if (nplus >= n)
Packit Service 991b93
    {
Packit Service 991b93
      char *mem = (char *) malloc (nplus);
Packit Service 991b93
Packit Service 991b93
      if (mem != NULL)
Packit Service 991b93
        {
Packit Service 991b93
          char *p =
Packit Service 991b93
            (char *)((((uintptr_t)mem + sizeof (small_t) + sa_alignment_max - 1)
Packit Service 991b93
                      & ~(uintptr_t)(2 * sa_alignment_max - 1))
Packit Service 991b93
                     + sa_alignment_max);
Packit Service 991b93
          /* Here p >= mem + sizeof (small_t),
Packit Service 991b93
             and p <= mem + sizeof (small_t) + 2 * sa_alignment_max - 1
Packit Service 991b93
             hence p + n <= mem + nplus.
Packit Service 991b93
             So, the memory range [p, p+n) lies in the allocated memory range
Packit Service 991b93
             [mem, mem + nplus).  */
Packit Service 991b93
          ((small_t *) p)[-1] = p - mem;
Packit Service 991b93
          /* p ≡ sa_alignment_max mod 2*sa_alignment_max.  */
Packit Service 991b93
          return p;
Packit Service 991b93
        }
Packit Service 991b93
    }
Packit Service 991b93
  /* Out of memory.  */
Packit Service 991b93
  return NULL;
Packit Service 991b93
#else
Packit Service 991b93
# if !MALLOC_0_IS_NONNULL
Packit Service 991b93
  if (n == 0)
Packit Service 991b93
    n = 1;
Packit Service 991b93
# endif
Packit Service 991b93
  return malloc (n);
Packit Service 991b93
#endif
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
#if HAVE_ALLOCA
Packit Service 991b93
void
Packit Service 991b93
freea (void *p)
Packit Service 991b93
{
Packit Service 991b93
  /* Check argument.  */
Packit Service 991b93
  if ((uintptr_t) p & (sa_alignment_max - 1))
Packit Service 991b93
    {
Packit Service 991b93
      /* p was not the result of a malloca() call.  Invalid argument.  */
Packit Service 991b93
      abort ();
Packit Service 991b93
    }
Packit Service 991b93
  /* Determine whether p was a non-NULL pointer returned by mmalloca().  */
Packit Service 991b93
  if ((uintptr_t) p & sa_alignment_max)
Packit Service 991b93
    {
Packit Service 991b93
      void *mem = (char *) p - ((small_t *) p)[-1];
Packit Service 991b93
      free (mem);
Packit Service 991b93
    }
Packit Service 991b93
}
Packit Service 991b93
#endif
Packit Service 991b93
Packit Service 991b93
/*
Packit Service 991b93
 * Hey Emacs!
Packit Service 991b93
 * Local Variables:
Packit Service 991b93
 * coding: utf-8
Packit Service 991b93
 * End:
Packit Service 991b93
 */