4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
32 #include <sys/sysmacros.h>
33 #include "umem_base.h"
37 * malloc_data_t is an 8-byte structure which is located "before" the pointer
38 * returned from {m,c,re}alloc and memalign. The first four bytes give
39 * information about the buffer, and the second four bytes are a status byte.
41 * See umem_impl.h for the various magic numbers used, and the size
42 * encode/decode macros.
44 * The 'size' of the buffer includes the tags. That is, we encode the
45 * argument to umem_alloc(), not the argument to malloc().
48 typedef struct malloc_data {
50 uint32_t malloc_stat; /* = UMEM_MALLOC_ENCODE(state, malloc_size) */
54 malloc(size_t size_arg)
57 uint32_t high_size = 0;
62 size = size_arg + sizeof (malloc_data_t);
65 if (size > UMEM_SECOND_ALIGN) {
66 size += sizeof (malloc_data_t);
67 high_size = (size >> 32);
70 if (size < size_arg) {
71 errno = ENOMEM; /* overflow */
74 ret = (malloc_data_t *)_umem_alloc(size, UMEM_DEFAULT);
76 if (size <= UMEM_MAXBUF)
82 } else if (high_size > 0) {
83 uint32_t low_size = (uint32_t)size;
86 * uses different magic numbers to make it harder to
87 * undetectably corrupt
89 ret->malloc_size = high_size;
90 ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_MAGIC, high_size);
93 ret->malloc_size = low_size;
94 ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_OVERSIZE_MAGIC,
97 } else if (size > UMEM_SECOND_ALIGN) {
98 uint32_t low_size = (uint32_t)size;
100 ret++; /* leave the first 8 bytes alone */
102 ret->malloc_size = low_size;
103 ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_SECOND_MAGIC,
108 ret->malloc_size = size;
109 ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_MAGIC, size);
112 return ((void *)ret);
116 calloc(size_t nelem, size_t elsize)
118 size_t size = nelem * elsize;
121 if (nelem > 0 && elsize > 0 && size/nelem != elsize) {
122 errno = ENOMEM; /* overflow */
126 retval = malloc(size);
130 (void) memset(retval, 0, size);
135 * memalign uses vmem_xalloc to do its work.
137 * in 64-bit, the memaligned buffer always has two tags. This simplifies the
142 memalign(size_t align, size_t size_arg)
152 if (size_arg == 0 || align == 0 || (align & (align - 1)) != 0) {
158 * if malloc provides the required alignment, use it.
160 if (align <= UMEM_ALIGN ||
161 (align <= UMEM_SECOND_ALIGN && size_arg >= UMEM_SECOND_ALIGN))
162 return (malloc(size_arg));
165 overhead = 2 * sizeof (malloc_data_t);
167 overhead = sizeof (malloc_data_t);
170 ASSERT(overhead <= align);
172 size = size_arg + overhead;
173 phase = align - overhead;
175 if (umem_memalign_arena == NULL && umem_init() == 0) {
180 if (size < size_arg) {
181 errno = ENOMEM; /* overflow */
185 buf = vmem_xalloc(umem_memalign_arena, size, align, phase,
186 0, NULL, NULL, VM_NOSLEEP);
189 if ((size_arg + align) <= UMEM_MAXBUF)
197 ret = (malloc_data_t *)buf;
199 uint32_t low_size = (uint32_t)size;
202 uint32_t high_size = (uint32_t)(size >> 32);
204 ret->malloc_size = high_size;
205 ret->malloc_stat = UMEM_MALLOC_ENCODE(MEMALIGN_MAGIC,
210 ret->malloc_size = low_size;
211 ret->malloc_stat = UMEM_MALLOC_ENCODE(MEMALIGN_MAGIC, low_size);
215 ASSERT(P2PHASE((uintptr_t)ret, align) == 0);
216 ASSERT((void *)((uintptr_t)ret - overhead) == buf);
218 return ((void *)ret);
224 return (memalign(pagesize, size));
230 * Pulls information out of a buffer pointer, and optionally free it.
231 * This is used by free() and realloc() to process buffers.
233 * On failure, calls umem_err_recoverable() with an appropriate message
234 * On success, returns the data size through *data_size_arg, if (!is_free).
236 * Preserves errno, since free()'s semantics require it.
240 process_free(void *buf_arg,
241 int do_free, /* free the buffer, or just get its size? */
242 size_t *data_size_arg) /* output: bytes of data in buf_arg */
251 int old_errno = errno;
253 buf = (malloc_data_t *)buf_arg;
256 size = buf->malloc_size;
258 switch (UMEM_MALLOC_DECODE(buf->malloc_stat, size)) {
262 data_size = size - sizeof (malloc_data_t);
265 buf->malloc_stat = UMEM_FREE_PATTERN_32;
270 case MALLOC_SECOND_MAGIC:
271 base = (void *)(buf - 1);
272 data_size = size - 2 * sizeof (malloc_data_t);
275 buf->malloc_stat = UMEM_FREE_PATTERN_32;
279 case MALLOC_OVERSIZE_MAGIC: {
283 high_size = buf->malloc_size;
285 if (UMEM_MALLOC_DECODE(buf->malloc_stat, high_size) !=
287 message = "invalid or corrupted buffer";
291 size += high_size << 32;
294 data_size = size - 2 * sizeof (malloc_data_t);
297 buf->malloc_stat = UMEM_FREE_PATTERN_32;
298 (buf + 1)->malloc_stat = UMEM_FREE_PATTERN_32;
305 case MEMALIGN_MAGIC: {
306 size_t overhead = sizeof (malloc_data_t);
311 overhead += sizeof (malloc_data_t);
314 high_size = buf->malloc_size;
316 if (UMEM_MALLOC_DECODE(buf->malloc_stat, high_size) !=
318 message = "invalid or corrupted buffer";
321 size += high_size << 32;
324 * destroy the main tag's malloc_stat
327 (buf + 1)->malloc_stat = UMEM_FREE_PATTERN_32;
331 data_size = size - overhead;
334 buf->malloc_stat = UMEM_FREE_PATTERN_32;
336 goto process_memalign;
339 if (buf->malloc_stat == UMEM_FREE_PATTERN_32)
340 message = "double-free or invalid buffer";
342 message = "invalid or corrupted buffer";
346 umem_err_recoverable("%s(%p): %s\n",
347 do_free? "free" : "realloc", buf_arg, message);
354 _umem_free(base, size);
356 *data_size_arg = data_size;
363 vmem_xfree(umem_memalign_arena, base, size);
365 *data_size_arg = data_size;
378 * Process buf, freeing it if it is not corrupt.
380 (void) process_free(buf, 1, NULL);
384 realloc(void *buf_arg, size_t newsize)
390 return (malloc(newsize));
398 * get the old data size without freeing the buffer
400 if (process_free(buf_arg, 0, &oldsize) == 0) {
405 if (newsize == oldsize) /* size didn't change */
408 buf = malloc(newsize);
412 (void) memcpy(buf, buf_arg, MIN(newsize, oldsize));