1*946379e7Schristos /* Safe automatic memory allocation.
2*946379e7Schristos Copyright (C) 2003, 2006 Free Software Foundation, Inc.
3*946379e7Schristos Written by Bruno Haible <bruno@clisp.org>, 2003.
4*946379e7Schristos
5*946379e7Schristos This program is free software; you can redistribute it and/or modify
6*946379e7Schristos it under the terms of the GNU General Public License as published by
7*946379e7Schristos the Free Software Foundation; either version 2, or (at your option)
8*946379e7Schristos any later version.
9*946379e7Schristos
10*946379e7Schristos This program is distributed in the hope that it will be useful,
11*946379e7Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
12*946379e7Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*946379e7Schristos GNU General Public License for more details.
14*946379e7Schristos
15*946379e7Schristos You should have received a copy of the GNU General Public License
16*946379e7Schristos along with this program; if not, write to the Free Software Foundation,
17*946379e7Schristos Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18*946379e7Schristos
19*946379e7Schristos #include <config.h>
20*946379e7Schristos
21*946379e7Schristos /* Specification. */
22*946379e7Schristos #include "allocsa.h"
23*946379e7Schristos
24*946379e7Schristos /* The speed critical point in this file is freesa() applied to an alloca()
25*946379e7Schristos result: it must be fast, to match the speed of alloca(). The speed of
26*946379e7Schristos mallocsa() and freesa() in the other case are not critical, because they
27*946379e7Schristos are only invoked for big memory sizes. */
28*946379e7Schristos
29*946379e7Schristos #if HAVE_ALLOCA
30*946379e7Schristos
31*946379e7Schristos /* Store the mallocsa() results in a hash table. This is needed to reliably
32*946379e7Schristos distinguish a mallocsa() result and an alloca() result.
33*946379e7Schristos
34*946379e7Schristos Although it is possible that the same pointer is returned by alloca() and
35*946379e7Schristos by mallocsa() at different times in the same application, it does not lead
36*946379e7Schristos to a bug in freesa(), because:
37*946379e7Schristos - Before a pointer returned by alloca() can point into malloc()ed memory,
38*946379e7Schristos the function must return, and once this has happened the programmer must
39*946379e7Schristos not call freesa() on it anyway.
40*946379e7Schristos - Before a pointer returned by mallocsa() can point into the stack, it
41*946379e7Schristos must be freed. The only function that can free it is freesa(), and
42*946379e7Schristos when freesa() frees it, it also removes it from the hash table. */
43*946379e7Schristos
44*946379e7Schristos #define MAGIC_NUMBER 0x1415fb4a
45*946379e7Schristos #define MAGIC_SIZE sizeof (int)
46*946379e7Schristos /* This is how the header info would look like without any alignment
47*946379e7Schristos considerations. */
48*946379e7Schristos struct preliminary_header { void *next; char room[MAGIC_SIZE]; };
49*946379e7Schristos /* But the header's size must be a multiple of sa_alignment_max. */
50*946379e7Schristos #define HEADER_SIZE \
51*946379e7Schristos (((sizeof (struct preliminary_header) + sa_alignment_max - 1) / sa_alignment_max) * sa_alignment_max)
52*946379e7Schristos struct header { void *next; char room[HEADER_SIZE - sizeof (struct preliminary_header) + MAGIC_SIZE]; };
53*946379e7Schristos /* Verify that HEADER_SIZE == sizeof (struct header). */
54*946379e7Schristos typedef int verify1[2 * (HEADER_SIZE == sizeof (struct header)) - 1];
55*946379e7Schristos /* We make the hash table quite big, so that during lookups the probability
56*946379e7Schristos of empty hash buckets is quite high. There is no need to make the hash
57*946379e7Schristos table resizable, because when the hash table gets filled so much that the
58*946379e7Schristos lookup becomes slow, it means that the application has memory leaks. */
59*946379e7Schristos #define HASH_TABLE_SIZE 257
60*946379e7Schristos static void * mallocsa_results[HASH_TABLE_SIZE];
61*946379e7Schristos
62*946379e7Schristos #endif
63*946379e7Schristos
64*946379e7Schristos void *
mallocsa(size_t n)65*946379e7Schristos mallocsa (size_t n)
66*946379e7Schristos {
67*946379e7Schristos #if HAVE_ALLOCA
68*946379e7Schristos /* Allocate one more word, that serves as an indicator for malloc()ed
69*946379e7Schristos memory, so that freesa() of an alloca() result is fast. */
70*946379e7Schristos size_t nplus = n + HEADER_SIZE;
71*946379e7Schristos
72*946379e7Schristos if (nplus >= n)
73*946379e7Schristos {
74*946379e7Schristos char *p = (char *) malloc (nplus);
75*946379e7Schristos
76*946379e7Schristos if (p != NULL)
77*946379e7Schristos {
78*946379e7Schristos size_t slot;
79*946379e7Schristos
80*946379e7Schristos p += HEADER_SIZE;
81*946379e7Schristos
82*946379e7Schristos /* Put a magic number into the indicator word. */
83*946379e7Schristos ((int *) p)[-1] = MAGIC_NUMBER;
84*946379e7Schristos
85*946379e7Schristos /* Enter p into the hash table. */
86*946379e7Schristos slot = (unsigned long) p % HASH_TABLE_SIZE;
87*946379e7Schristos ((struct header *) (p - HEADER_SIZE))->next = mallocsa_results[slot];
88*946379e7Schristos mallocsa_results[slot] = p;
89*946379e7Schristos
90*946379e7Schristos return p;
91*946379e7Schristos }
92*946379e7Schristos }
93*946379e7Schristos /* Out of memory. */
94*946379e7Schristos return NULL;
95*946379e7Schristos #else
96*946379e7Schristos # if !MALLOC_0_IS_NONNULL
97*946379e7Schristos if (n == 0)
98*946379e7Schristos n = 1;
99*946379e7Schristos # endif
100*946379e7Schristos return malloc (n);
101*946379e7Schristos #endif
102*946379e7Schristos }
103*946379e7Schristos
104*946379e7Schristos #if HAVE_ALLOCA
105*946379e7Schristos void
freesa(void * p)106*946379e7Schristos freesa (void *p)
107*946379e7Schristos {
108*946379e7Schristos /* mallocsa() may have returned NULL. */
109*946379e7Schristos if (p != NULL)
110*946379e7Schristos {
111*946379e7Schristos /* Attempt to quickly distinguish the mallocsa() result - which has
112*946379e7Schristos a magic indicator word - and the alloca() result - which has an
113*946379e7Schristos uninitialized indicator word. It is for this test that sa_increment
114*946379e7Schristos additional bytes are allocated in the alloca() case. */
115*946379e7Schristos if (((int *) p)[-1] == MAGIC_NUMBER)
116*946379e7Schristos {
117*946379e7Schristos /* Looks like a mallocsa() result. To see whether it really is one,
118*946379e7Schristos perform a lookup in the hash table. */
119*946379e7Schristos size_t slot = (unsigned long) p % HASH_TABLE_SIZE;
120*946379e7Schristos void **chain = &mallocsa_results[slot];
121*946379e7Schristos for (; *chain != NULL;)
122*946379e7Schristos {
123*946379e7Schristos if (*chain == p)
124*946379e7Schristos {
125*946379e7Schristos /* Found it. Remove it from the hash table and free it. */
126*946379e7Schristos char *p_begin = (char *) p - HEADER_SIZE;
127*946379e7Schristos *chain = ((struct header *) p_begin)->next;
128*946379e7Schristos free (p_begin);
129*946379e7Schristos return;
130*946379e7Schristos }
131*946379e7Schristos chain = &((struct header *) ((char *) *chain - HEADER_SIZE))->next;
132*946379e7Schristos }
133*946379e7Schristos }
134*946379e7Schristos /* At this point, we know it was not a mallocsa() result. */
135*946379e7Schristos }
136*946379e7Schristos }
137*946379e7Schristos #endif
138