Home | History | Annotate | Line # | Download | only in import
malloca.c revision 1.1
      1  1.1  christos /* Safe automatic memory allocation.
      2  1.1  christos    Copyright (C) 2003, 2006-2007, 2009-2020 Free Software Foundation, Inc.
      3  1.1  christos    Written by Bruno Haible <bruno (at) clisp.org>, 2003, 2018.
      4  1.1  christos 
      5  1.1  christos    This program is free software; you can redistribute it and/or modify
      6  1.1  christos    it under the terms of the GNU General Public License as published by
      7  1.1  christos    the Free Software Foundation; either version 3, or (at your option)
      8  1.1  christos    any later version.
      9  1.1  christos 
     10  1.1  christos    This program is distributed in the hope that it will be useful,
     11  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  1.1  christos    GNU General Public License for more details.
     14  1.1  christos 
     15  1.1  christos    You should have received a copy of the GNU General Public License
     16  1.1  christos    along with this program; if not, see <https://www.gnu.org/licenses/>.  */
     17  1.1  christos 
     18  1.1  christos #define _GL_USE_STDLIB_ALLOC 1
     19  1.1  christos #include <config.h>
     20  1.1  christos 
     21  1.1  christos /* Specification.  */
     22  1.1  christos #include "malloca.h"
     23  1.1  christos 
     24  1.1  christos #include "verify.h"
     25  1.1  christos 
     26  1.1  christos /* The speed critical point in this file is freea() applied to an alloca()
     27  1.1  christos    result: it must be fast, to match the speed of alloca().  The speed of
     28  1.1  christos    mmalloca() and freea() in the other case are not critical, because they
     29  1.1  christos    are only invoked for big memory sizes.
     30  1.1  christos    Here we use a bit in the address as an indicator, an idea by Ondej Blka.
     31  1.1  christos    malloca() can return three types of pointers:
     32  1.1  christos      - Pointers  0 mod 2*sa_alignment_max come from stack allocation.
     33  1.1  christos      - Pointers  sa_alignment_max mod 2*sa_alignment_max come from heap
     34  1.1  christos        allocation.
     35  1.1  christos      - NULL comes from a failed heap allocation.  */
     36  1.1  christos 
     37  1.1  christos /* Type for holding very small pointer differences.  */
     38  1.1  christos typedef unsigned char small_t;
     39  1.1  christos /* Verify that it is wide enough.  */
     40  1.1  christos verify (2 * sa_alignment_max - 1 <= (small_t) -1);
     41  1.1  christos 
     42  1.1  christos void *
     43  1.1  christos mmalloca (size_t n)
     44  1.1  christos {
     45  1.1  christos #if HAVE_ALLOCA
     46  1.1  christos   /* Allocate one more word, used to determine the address to pass to freea(),
     47  1.1  christos      and room for the alignment  sa_alignment_max mod 2*sa_alignment_max.  */
     48  1.1  christos   size_t nplus = n + sizeof (small_t) + 2 * sa_alignment_max - 1;
     49  1.1  christos 
     50  1.1  christos   if (nplus >= n)
     51  1.1  christos     {
     52  1.1  christos       char *mem = (char *) malloc (nplus);
     53  1.1  christos 
     54  1.1  christos       if (mem != NULL)
     55  1.1  christos         {
     56  1.1  christos           char *p =
     57  1.1  christos             (char *)((((uintptr_t)mem + sizeof (small_t) + sa_alignment_max - 1)
     58  1.1  christos                       & ~(uintptr_t)(2 * sa_alignment_max - 1))
     59  1.1  christos                      + sa_alignment_max);
     60  1.1  christos           /* Here p >= mem + sizeof (small_t),
     61  1.1  christos              and p <= mem + sizeof (small_t) + 2 * sa_alignment_max - 1
     62  1.1  christos              hence p + n <= mem + nplus.
     63  1.1  christos              So, the memory range [p, p+n) lies in the allocated memory range
     64  1.1  christos              [mem, mem + nplus).  */
     65  1.1  christos           ((small_t *) p)[-1] = p - mem;
     66  1.1  christos           /* p  sa_alignment_max mod 2*sa_alignment_max.  */
     67  1.1  christos           return p;
     68  1.1  christos         }
     69  1.1  christos     }
     70  1.1  christos   /* Out of memory.  */
     71  1.1  christos   return NULL;
     72  1.1  christos #else
     73  1.1  christos # if !MALLOC_0_IS_NONNULL
     74  1.1  christos   if (n == 0)
     75  1.1  christos     n = 1;
     76  1.1  christos # endif
     77  1.1  christos   return malloc (n);
     78  1.1  christos #endif
     79  1.1  christos }
     80  1.1  christos 
     81  1.1  christos #if HAVE_ALLOCA
     82  1.1  christos void
     83  1.1  christos freea (void *p)
     84  1.1  christos {
     85  1.1  christos   /* Check argument.  */
     86  1.1  christos   if ((uintptr_t) p & (sa_alignment_max - 1))
     87  1.1  christos     {
     88  1.1  christos       /* p was not the result of a malloca() call.  Invalid argument.  */
     89  1.1  christos       abort ();
     90  1.1  christos     }
     91  1.1  christos   /* Determine whether p was a non-NULL pointer returned by mmalloca().  */
     92  1.1  christos   if ((uintptr_t) p & sa_alignment_max)
     93  1.1  christos     {
     94  1.1  christos       void *mem = (char *) p - ((small_t *) p)[-1];
     95  1.1  christos       free (mem);
     96  1.1  christos     }
     97  1.1  christos }
     98  1.1  christos #endif
     99  1.1  christos 
    100  1.1  christos /*
    101  1.1  christos  * Hey Emacs!
    102  1.1  christos  * Local Variables:
    103  1.1  christos  * coding: utf-8
    104  1.1  christos  * End:
    105  1.1  christos  */
    106