Commit | Line | Data |
---|---|---|
98399780 | 1 | /* Safe automatic memory allocation. |
c0c3707f CB |
2 | Copyright (C) 2003, 2006-2007, 2009-2019 Free Software Foundation, Inc. |
3 | Written by Bruno Haible <bruno@clisp.org>, 2003, 2018. | |
98399780 YQ |
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 | |
c0c3707f | 16 | along with this program; if not, see <https://www.gnu.org/licenses/>. */ |
98399780 YQ |
17 | |
18 | #define _GL_USE_STDLIB_ALLOC 1 | |
19 | #include <config.h> | |
20 | ||
21 | /* Specification. */ | |
22 | #include "malloca.h" | |
23 | ||
98399780 YQ |
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 | |
c0c3707f CB |
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); | |
98399780 YQ |
41 | |
42 | void * | |
43 | mmalloca (size_t n) | |
44 | { | |
45 | #if HAVE_ALLOCA | |
c0c3707f CB |
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; | |
98399780 YQ |
49 | |
50 | if (nplus >= n) | |
51 | { | |
c0c3707f | 52 | char *mem = (char *) malloc (nplus); |
98399780 | 53 | |
c0c3707f | 54 | if (mem != NULL) |
98399780 | 55 | { |
c0c3707f CB |
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. */ | |
98399780 YQ |
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 | { | |
c0c3707f CB |
85 | /* Check argument. */ |
86 | if ((uintptr_t) p & (sa_alignment_max - 1)) | |
7a6dbc2f | 87 | { |
c0c3707f CB |
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); | |
98399780 YQ |
96 | } |
97 | } | |
98 | #endif | |
c0c3707f CB |
99 | |
100 | /* | |
101 | * Hey Emacs! | |
102 | * Local Variables: | |
103 | * coding: utf-8 | |
104 | * End: | |
105 | */ |