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