root/trunk/malloc.c

Revision 58, 8.6 kB (checked in by wez, 4 years ago)

move umem_startup constructor to the umem .so itself, rather than
the malloc replacement.

Rename ec_atomic to umem_atomic.

Add a posix_memalign function.

-ldl isn't universal; make a configure check for it.

  • Property svn:eol-style set to native
Line 
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26
27 #pragma ident   "@(#)malloc.c   1.5     05/06/08 SMI"
28
29 #include "config.h"
30 #include <unistd.h>
31
32 #include <errno.h>
33
34 #include <string.h>
35
36 #ifdef HAVE_SYS_SYSMACROS_H
37 #include <sys/sysmacros.h>
38 #endif
39
40 #include "umem_base.h"
41
42 #include "misc.h"
43
44 /*
45  * malloc_data_t is an 8-byte structure which is located "before" the pointer
46  * returned from {m,c,re}alloc and memalign.  The first four bytes give
47  * information about the buffer, and the second four bytes are a status byte.
48  *
49  * See umem_impl.h for the various magic numbers used, and the size
50  * encode/decode macros.
51  *
52  * The 'size' of the buffer includes the tags.  That is, we encode the
53  * argument to umem_alloc(), not the argument to malloc().
54  */
55
56 typedef struct malloc_data {
57         uint32_t malloc_size;
58         uint32_t malloc_stat; /* = UMEM_MALLOC_ENCODE(state, malloc_size) */
59 } malloc_data_t;
60
61 void *
62 malloc(size_t size_arg)
63 {
64 #ifdef _LP64
65         uint32_t high_size = 0;
66 #endif
67         size_t size;
68
69         malloc_data_t *ret;
70         size = size_arg + sizeof (malloc_data_t);
71
72 #ifdef _LP64
73         if (size > UMEM_SECOND_ALIGN) {
74                 size += sizeof (malloc_data_t);
75                 high_size = (size >> 32);
76         }
77 #endif
78         if (size < size_arg) {
79                 errno = ENOMEM;                 /* overflow */
80                 return (NULL);
81         }
82         ret = (malloc_data_t *)_umem_alloc(size, UMEM_DEFAULT);
83         if (ret == NULL) {
84                 if (size <= UMEM_MAXBUF)
85                         errno = EAGAIN;
86                 else
87                         errno = ENOMEM;
88                 return (NULL);
89 #ifdef _LP64
90         } else if (high_size > 0) {
91                 uint32_t low_size = (uint32_t)size;
92
93                 /*
94                  * uses different magic numbers to make it harder to
95                  * undetectably corrupt
96                  */
97                 ret->malloc_size = high_size;
98                 ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_MAGIC, high_size);
99                 ret++;
100
101                 ret->malloc_size = low_size;
102                 ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_OVERSIZE_MAGIC,
103                     low_size);
104                 ret++;
105         } else if (size > UMEM_SECOND_ALIGN) {
106                 uint32_t low_size = (uint32_t)size;
107
108                 ret++; /* leave the first 8 bytes alone */
109
110                 ret->malloc_size = low_size;
111                 ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_SECOND_MAGIC,
112                     low_size);
113                 ret++;
114 #endif
115         } else {
116                 ret->malloc_size = size;
117                 ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_MAGIC, size);
118                 ret++;
119         }
120         return ((void *)ret);
121 }
122
123 void *
124 calloc(size_t nelem, size_t elsize)
125 {
126         size_t size = nelem * elsize;
127         void *retval;
128
129         if (nelem > 0 && elsize > 0 && size/nelem != elsize) {
130                 errno = ENOMEM;                         /* overflow */
131                 return (NULL);
132         }
133
134         retval = malloc(size);
135         if (retval == NULL)
136                 return (NULL);
137
138         (void) memset(retval, 0, size);
139         return (retval);
140 }
141
142 /*
143  * memalign uses vmem_xalloc to do its work.
144  *
145  * in 64-bit, the memaligned buffer always has two tags.  This simplifies the
146  * code.
147  */
148
149 void *
150 memalign(size_t align, size_t size_arg)
151 {
152         size_t size;
153         uintptr_t phase;
154
155         void *buf;
156         malloc_data_t *ret;
157
158         size_t overhead;
159
160         if (size_arg == 0 || align == 0 || (align & (align - 1)) != 0) {
161                 errno = EINVAL;
162                 return (NULL);
163         }
164
165         /*
166          * if malloc provides the required alignment, use it.
167          */
168         if (align <= UMEM_ALIGN ||
169             (align <= UMEM_SECOND_ALIGN && size_arg >= UMEM_SECOND_ALIGN))
170                 return (malloc(size_arg));
171
172 #ifdef _LP64
173         overhead = 2 * sizeof (malloc_data_t);
174 #else
175         overhead = sizeof (malloc_data_t);
176 #endif
177
178         ASSERT(overhead <= align);
179
180         size = size_arg + overhead;
181         phase = align - overhead;
182
183         if (umem_memalign_arena == NULL && umem_init() == 0) {
184                 errno = ENOMEM;
185                 return (NULL);
186         }
187
188         if (size < size_arg) {
189                 errno = ENOMEM;                 /* overflow */
190                 return (NULL);
191         }
192
193         buf = vmem_xalloc(umem_memalign_arena, size, align, phase,
194             0, NULL, NULL, VM_NOSLEEP);
195
196         if (buf == NULL) {
197                 if ((size_arg + align) <= UMEM_MAXBUF)
198                         errno = EAGAIN;
199                 else
200                         errno = ENOMEM;
201
202                 return (NULL);
203         }
204
205         ret = (malloc_data_t *)buf;
206         {
207                 uint32_t low_size = (uint32_t)size;
208
209 #ifdef _LP64
210                 uint32_t high_size = (uint32_t)(size >> 32);
211
212                 ret->malloc_size = high_size;
213                 ret->malloc_stat = UMEM_MALLOC_ENCODE(MEMALIGN_MAGIC,
214                     high_size);
215                 ret++;
216 #endif
217
218                 ret->malloc_size = low_size;
219                 ret->malloc_stat = UMEM_MALLOC_ENCODE(MEMALIGN_MAGIC, low_size);
220                 ret++;
221         }
222
223         ASSERT(P2PHASE((uintptr_t)ret, align) == 0);
224         ASSERT((void *)((uintptr_t)ret - overhead) == buf);
225
226         return ((void *)ret);
227 }
228
229 int
230 posix_memalign(void **memptr, size_t alignment, size_t size)
231 {
232         *memptr = memalign(alignment, size);
233         if (*memptr) {
234                 return 0;
235         }
236         return errno;
237 }
238
239 void *
240 valloc(size_t size)
241 {
242         return (memalign(pagesize, size));
243 }
244
245 /*
246  * process_free:
247  *
248  * Pulls information out of a buffer pointer, and optionally free it.
249  * This is used by free() and realloc() to process buffers.
250  *
251  * On failure, calls umem_err_recoverable() with an appropriate message
252  * On success, returns the data size through *data_size_arg, if (!is_free).
253  *
254  * Preserves errno, since free()'s semantics require it.
255  */
256
257 static int
258 process_free(void *buf_arg,
259     int do_free,                /* free the buffer, or just get its size? */
260     size_t *data_size_arg)      /* output: bytes of data in buf_arg */
261 {
262         malloc_data_t *buf;
263
264         void *base;
265         size_t size;
266         size_t data_size;
267
268         const char *message;
269         int old_errno = errno;
270
271         buf = (malloc_data_t *)buf_arg;
272
273         buf--;
274         size = buf->malloc_size;
275
276         switch (UMEM_MALLOC_DECODE(buf->malloc_stat, size)) {
277
278         case MALLOC_MAGIC:
279                 base = (void *)buf;
280                 data_size = size - sizeof (malloc_data_t);
281
282                 if (do_free)
283                         buf->malloc_stat = UMEM_FREE_PATTERN_32;
284
285                 goto process_malloc;
286
287 #ifdef _LP64
288         case MALLOC_SECOND_MAGIC:
289                 base = (void *)(buf - 1);
290                 data_size = size - 2 * sizeof (malloc_data_t);
291
292                 if (do_free)
293                         buf->malloc_stat = UMEM_FREE_PATTERN_32;
294
295                 goto process_malloc;
296
297         case MALLOC_OVERSIZE_MAGIC: {
298                 size_t high_size;
299
300                 buf--;
301                 high_size = buf->malloc_size;
302
303                 if (UMEM_MALLOC_DECODE(buf->malloc_stat, high_size) !=
304                     MALLOC_MAGIC) {
305                         message = "invalid or corrupted buffer";
306                         break;
307                 }
308
309                 size += high_size << 32;
310
311                 base = (void *)buf;
312                 data_size = size - 2 * sizeof (malloc_data_t);
313
314                 if (do_free) {
315                         buf->malloc_stat = UMEM_FREE_PATTERN_32;
316                         (buf + 1)->malloc_stat = UMEM_FREE_PATTERN_32;
317                 }
318
319                 goto process_malloc;
320         }
321 #endif
322
323         case MEMALIGN_MAGIC: {
324                 size_t overhead = sizeof (malloc_data_t);
325
326 #ifdef _LP64
327                 size_t high_size;
328
329                 overhead += sizeof (malloc_data_t);
330
331                 buf--;
332                 high_size = buf->malloc_size;
333
334                 if (UMEM_MALLOC_DECODE(buf->malloc_stat, high_size) !=
335                     MEMALIGN_MAGIC) {
336                         message = "invalid or corrupted buffer";
337                         break;
338                 }
339                 size += high_size << 32;
340
341                 /*
342                  * destroy the main tag's malloc_stat
343                  */
344                 if (do_free)
345                         (buf + 1)->malloc_stat = UMEM_FREE_PATTERN_32;
346 #endif
347
348                 base = (void *)buf;
349                 data_size = size - overhead;
350
351                 if (do_free)
352                         buf->malloc_stat = UMEM_FREE_PATTERN_32;
353
354                 goto process_memalign;
355         }
356         default:
357                 if (buf->malloc_stat == UMEM_FREE_PATTERN_32)
358                         message = "double-free or invalid buffer";
359                 else
360                         message = "invalid or corrupted buffer";
361                 break;
362         }
363
364         umem_err_recoverable("%s(%p): %s\n",
365             do_free? "free" : "realloc", buf_arg, message);
366
367         errno = old_errno;
368         return (0);
369
370 process_malloc:
371         if (do_free)
372                 _umem_free(base, size);
373         else
374                 *data_size_arg = data_size;
375
376         errno = old_errno;
377         return (1);
378
379 process_memalign:
380         if (do_free)
381                 vmem_xfree(umem_memalign_arena, base, size);
382         else
383                 *data_size_arg = data_size;
384
385         errno = old_errno;
386         return (1);
387 }
388
389 void
390 free(void *buf)
391 {
392         if (buf == NULL)
393                 return;
394
395         /*
396          * Process buf, freeing it if it is not corrupt.
397          */
398         (void) process_free(buf, 1, NULL);
399 }
400
401 void *
402 realloc(void *buf_arg, size_t newsize)
403 {
404         size_t oldsize;
405         void *buf;
406
407         if (buf_arg == NULL)
408                 return (malloc(newsize));
409
410         if (newsize == 0) {
411                 free(buf_arg);
412                 return (NULL);
413         }
414
415         /*
416          * get the old data size without freeing the buffer
417          */
418         if (process_free(buf_arg, 0, &oldsize) == 0) {
419                 errno = EINVAL;
420                 return (NULL);
421         }
422
423         if (newsize == oldsize)         /* size didn't change */
424                 return (buf_arg);
425
426         buf = malloc(newsize);
427         if (buf == NULL)
428                 return (NULL);
429
430         (void) memcpy(buf, buf_arg, MIN(newsize, oldsize));
431         free(buf_arg);
432         return (buf);
433 }
434
435
Note: See TracBrowser for help on using the browser.