Line data Source code
1 : /* Safe automatic memory allocation.
2 : Copyright (C) 2003, 2006-2007, 2009-2020 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 250000 : 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 250000 : size_t nplus = n + sizeof (small_t) + 2 * sa_alignment_max - 1;
49 :
50 250000 : if (nplus >= n)
51 : {
52 250000 : char *mem = (char *) malloc (nplus);
53 :
54 250000 : if (mem != NULL)
55 : {
56 250000 : char *p =
57 250000 : (char *)((((uintptr_t)mem + sizeof (small_t) + sa_alignment_max - 1)
58 250000 : & ~(uintptr_t)(2 * sa_alignment_max - 1))
59 250000 : + 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 250000 : ((small_t *) p)[-1] = p - mem;
66 : /* p ≡ sa_alignment_max mod 2*sa_alignment_max. */
67 250000 : return p;
68 : }
69 : }
70 : /* Out of memory. */
71 0 : 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 500000 : freea (void *p)
84 : {
85 : /* Check argument. */
86 500000 : if ((uintptr_t) p & (sa_alignment_max - 1))
87 : {
88 : /* p was not the result of a malloca() call. Invalid argument. */
89 0 : abort ();
90 : }
91 : /* Determine whether p was a non-NULL pointer returned by mmalloca(). */
92 500000 : if ((uintptr_t) p & sa_alignment_max)
93 : {
94 250000 : void *mem = (char *) p - ((small_t *) p)[-1];
95 250000 : free (mem);
96 : }
97 500000 : }
98 : #endif
99 :
100 : /*
101 : * Hey Emacs!
102 : * Local Variables:
103 : * coding: utf-8
104 : * End:
105 : */
|