File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / srclib / malloca.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 13:38:46 2021 UTC (3 years, 3 months ago) by misho
Branches: libiconv, MAIN
CVS tags: v1_16p0, HEAD
libiconv 1.16

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>