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>