Home | History | Annotate | Line # | Download | only in import
      1      1.1  christos /* Safe automatic memory allocation.
      2  1.1.1.2  christos    Copyright (C) 2003, 2006-2007, 2009-2022 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.1.2  christos    This file is free software: you can redistribute it and/or modify
      6  1.1.1.2  christos    it under the terms of the GNU Lesser General Public License as
      7  1.1.1.2  christos    published by the Free Software Foundation; either version 2.1 of the
      8  1.1.1.2  christos    License, or (at your option) any later version.
      9      1.1  christos 
     10  1.1.1.2  christos    This file 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.1.2  christos    GNU Lesser General Public License for more details.
     14      1.1  christos 
     15  1.1.1.2  christos    You should have received a copy of the GNU Lesser General Public License
     16  1.1.1.2  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.1.2  christos #include "idx.h"
     25  1.1.1.2  christos #include "intprops.h"
     26      1.1  christos #include "verify.h"
     27      1.1  christos 
     28      1.1  christos /* The speed critical point in this file is freea() applied to an alloca()
     29      1.1  christos    result: it must be fast, to match the speed of alloca().  The speed of
     30      1.1  christos    mmalloca() and freea() in the other case are not critical, because they
     31      1.1  christos    are only invoked for big memory sizes.
     32      1.1  christos    Here we use a bit in the address as an indicator, an idea by Ondej Blka.
     33      1.1  christos    malloca() can return three types of pointers:
     34      1.1  christos      - Pointers  0 mod 2*sa_alignment_max come from stack allocation.
     35      1.1  christos      - Pointers  sa_alignment_max mod 2*sa_alignment_max come from heap
     36      1.1  christos        allocation.
     37      1.1  christos      - NULL comes from a failed heap allocation.  */
     38      1.1  christos 
     39      1.1  christos /* Type for holding very small pointer differences.  */
     40      1.1  christos typedef unsigned char small_t;
     41      1.1  christos /* Verify that it is wide enough.  */
     42      1.1  christos verify (2 * sa_alignment_max - 1 <= (small_t) -1);
     43      1.1  christos 
     44      1.1  christos void *
     45      1.1  christos mmalloca (size_t n)
     46      1.1  christos {
     47      1.1  christos #if HAVE_ALLOCA
     48      1.1  christos   /* Allocate one more word, used to determine the address to pass to freea(),
     49      1.1  christos      and room for the alignment  sa_alignment_max mod 2*sa_alignment_max.  */
     50  1.1.1.2  christos   uintptr_t alignment2_mask = 2 * sa_alignment_max - 1;
     51  1.1.1.2  christos   int plus = sizeof (small_t) + alignment2_mask;
     52  1.1.1.2  christos   idx_t nplus;
     53  1.1.1.2  christos   if (!INT_ADD_WRAPV (n, plus, &nplus) && !xalloc_oversized (nplus, 1))
     54      1.1  christos     {
     55      1.1  christos       char *mem = (char *) malloc (nplus);
     56      1.1  christos 
     57      1.1  christos       if (mem != NULL)
     58      1.1  christos         {
     59  1.1.1.2  christos           uintptr_t umem = (uintptr_t)mem, umemplus;
     60  1.1.1.2  christos           /* The INT_ADD_WRAPV avoids signed integer overflow on
     61  1.1.1.2  christos              theoretical platforms where UINTPTR_MAX <= INT_MAX.  */
     62  1.1.1.2  christos           INT_ADD_WRAPV (umem, sizeof (small_t) + sa_alignment_max - 1,
     63  1.1.1.2  christos                          &umemplus);
     64  1.1.1.2  christos           idx_t offset = ((umemplus & ~alignment2_mask)
     65  1.1.1.2  christos                           + sa_alignment_max - umem);
     66  1.1.1.2  christos           void *vp = mem + offset;
     67  1.1.1.2  christos           small_t *p = vp;
     68      1.1  christos           /* Here p >= mem + sizeof (small_t),
     69      1.1  christos              and p <= mem + sizeof (small_t) + 2 * sa_alignment_max - 1
     70      1.1  christos              hence p + n <= mem + nplus.
     71      1.1  christos              So, the memory range [p, p+n) lies in the allocated memory range
     72      1.1  christos              [mem, mem + nplus).  */
     73  1.1.1.2  christos           p[-1] = offset;
     74      1.1  christos           /* p  sa_alignment_max mod 2*sa_alignment_max.  */
     75      1.1  christos           return p;
     76      1.1  christos         }
     77      1.1  christos     }
     78      1.1  christos   /* Out of memory.  */
     79      1.1  christos   return NULL;
     80      1.1  christos #else
     81      1.1  christos # if !MALLOC_0_IS_NONNULL
     82      1.1  christos   if (n == 0)
     83      1.1  christos     n = 1;
     84      1.1  christos # endif
     85      1.1  christos   return malloc (n);
     86      1.1  christos #endif
     87      1.1  christos }
     88      1.1  christos 
     89      1.1  christos #if HAVE_ALLOCA
     90      1.1  christos void
     91      1.1  christos freea (void *p)
     92      1.1  christos {
     93      1.1  christos   /* Check argument.  */
     94      1.1  christos   if ((uintptr_t) p & (sa_alignment_max - 1))
     95      1.1  christos     {
     96      1.1  christos       /* p was not the result of a malloca() call.  Invalid argument.  */
     97      1.1  christos       abort ();
     98      1.1  christos     }
     99      1.1  christos   /* Determine whether p was a non-NULL pointer returned by mmalloca().  */
    100      1.1  christos   if ((uintptr_t) p & sa_alignment_max)
    101      1.1  christos     {
    102      1.1  christos       void *mem = (char *) p - ((small_t *) p)[-1];
    103      1.1  christos       free (mem);
    104      1.1  christos     }
    105      1.1  christos }
    106      1.1  christos #endif
    107      1.1  christos 
    108      1.1  christos /*
    109      1.1  christos  * Hey Emacs!
    110      1.1  christos  * Local Variables:
    111      1.1  christos  * coding: utf-8
    112      1.1  christos  * End:
    113      1.1  christos  */
    114