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.
30 #include <sys/sysmacros.h>
31 #include "umem_base.h"
35 * malloc_data_t is an 8-byte structure which is located "before" the pointer
36 * returned from {m,c,re}alloc and memalign. The first four bytes give
37 * information about the buffer, and the second four bytes are a status byte.
39 * See umem_impl.h for the various magic numbers used, and the size
40 * encode/decode macros.
42 * The 'size' of the buffer includes the tags. That is, we encode the
43 * argument to umem_alloc(), not the argument to malloc().
46 typedef struct malloc_data
{
48 uint32_t malloc_stat
; /* = UMEM_MALLOC_ENCODE(state, malloc_size) */
52 * Because we do not support ptcumem on non-x86 today, we have to create these
56 #pragma weak malloc = umem_malloc
57 #pragma weak free = umem_malloc_free
61 umem_malloc(size_t size_arg
)
64 uint32_t high_size
= 0;
69 size
= size_arg
+ sizeof (malloc_data_t
);
72 if (size
> UMEM_SECOND_ALIGN
) {
73 size
+= sizeof (malloc_data_t
);
74 high_size
= (size
>> 32);
77 if (size
< size_arg
) {
78 errno
= ENOMEM
; /* overflow */
81 ret
= (malloc_data_t
*)_umem_alloc(size
, UMEM_DEFAULT
);
83 if (size
<= UMEM_MAXBUF
)
89 } else if (high_size
> 0) {
90 uint32_t low_size
= (uint32_t)size
;
93 * uses different magic numbers to make it harder to
94 * undetectably corrupt
96 ret
->malloc_size
= high_size
;
97 ret
->malloc_stat
= UMEM_MALLOC_ENCODE(MALLOC_MAGIC
, high_size
);
100 ret
->malloc_size
= low_size
;
101 ret
->malloc_stat
= UMEM_MALLOC_ENCODE(MALLOC_OVERSIZE_MAGIC
,
104 } else if (size
> UMEM_SECOND_ALIGN
) {
105 uint32_t low_size
= (uint32_t)size
;
107 ret
++; /* leave the first 8 bytes alone */
109 ret
->malloc_size
= low_size
;
110 ret
->malloc_stat
= UMEM_MALLOC_ENCODE(MALLOC_SECOND_MAGIC
,
115 ret
->malloc_size
= size
;
116 ret
->malloc_stat
= UMEM_MALLOC_ENCODE(MALLOC_MAGIC
, size
);
119 return ((void *)ret
);
123 calloc(size_t nelem
, size_t elsize
)
125 size_t size
= nelem
* elsize
;
128 if (nelem
> 0 && elsize
> 0 && size
/nelem
!= elsize
) {
129 errno
= ENOMEM
; /* overflow */
133 retval
= malloc(size
);
137 (void) memset(retval
, 0, size
);
142 * memalign uses vmem_xalloc to do its work.
144 * in 64-bit, the memaligned buffer always has two tags. This simplifies the
149 memalign(size_t align
, size_t size_arg
)
159 if (size_arg
== 0 || align
== 0 || (align
& (align
- 1)) != 0) {
165 * if malloc provides the required alignment, use it.
167 if (align
<= UMEM_ALIGN
||
168 (align
<= UMEM_SECOND_ALIGN
&& size_arg
>= UMEM_SECOND_ALIGN
))
169 return (malloc(size_arg
));
172 overhead
= 2 * sizeof (malloc_data_t
);
174 overhead
= sizeof (malloc_data_t
);
177 ASSERT(overhead
<= align
);
179 size
= size_arg
+ overhead
;
180 phase
= align
- overhead
;
182 if (umem_memalign_arena
== NULL
&& umem_init() == 0) {
187 if (size
< size_arg
) {
188 errno
= ENOMEM
; /* overflow */
192 buf
= vmem_xalloc(umem_memalign_arena
, size
, align
, phase
,
193 0, NULL
, NULL
, VM_NOSLEEP
);
196 if ((size_arg
+ align
) <= UMEM_MAXBUF
)
204 ret
= (malloc_data_t
*)buf
;
206 uint32_t low_size
= (uint32_t)size
;
209 uint32_t high_size
= (uint32_t)(size
>> 32);
211 ret
->malloc_size
= high_size
;
212 ret
->malloc_stat
= UMEM_MALLOC_ENCODE(MEMALIGN_MAGIC
,
217 ret
->malloc_size
= low_size
;
218 ret
->malloc_stat
= UMEM_MALLOC_ENCODE(MEMALIGN_MAGIC
, low_size
);
222 ASSERT(P2PHASE((uintptr_t)ret
, align
) == 0);
223 ASSERT((void *)((uintptr_t)ret
- overhead
) == buf
);
225 return ((void *)ret
);
231 return (memalign(pagesize
, size
));
237 * Pulls information out of a buffer pointer, and optionally free it.
238 * This is used by free() and realloc() to process buffers.
240 * On failure, calls umem_err_recoverable() with an appropriate message
241 * On success, returns the data size through *data_size_arg, if (!is_free).
243 * Preserves errno, since free()'s semantics require it.
247 process_free(void *buf_arg
,
248 int do_free
, /* free the buffer, or just get its size? */
249 size_t *data_size_arg
) /* output: bytes of data in buf_arg */
258 int old_errno
= errno
;
260 buf
= (malloc_data_t
*)buf_arg
;
263 size
= buf
->malloc_size
;
265 switch (UMEM_MALLOC_DECODE(buf
->malloc_stat
, size
)) {
269 data_size
= size
- sizeof (malloc_data_t
);
272 buf
->malloc_stat
= UMEM_FREE_PATTERN_32
;
277 case MALLOC_SECOND_MAGIC
:
278 base
= (void *)(buf
- 1);
279 data_size
= size
- 2 * sizeof (malloc_data_t
);
282 buf
->malloc_stat
= UMEM_FREE_PATTERN_32
;
286 case MALLOC_OVERSIZE_MAGIC
: {
290 high_size
= buf
->malloc_size
;
292 if (UMEM_MALLOC_DECODE(buf
->malloc_stat
, high_size
) !=
294 message
= "invalid or corrupted buffer";
298 size
+= high_size
<< 32;
301 data_size
= size
- 2 * sizeof (malloc_data_t
);
304 buf
->malloc_stat
= UMEM_FREE_PATTERN_32
;
305 (buf
+ 1)->malloc_stat
= UMEM_FREE_PATTERN_32
;
312 case MEMALIGN_MAGIC
: {
313 size_t overhead
= sizeof (malloc_data_t
);
318 overhead
+= sizeof (malloc_data_t
);
321 high_size
= buf
->malloc_size
;
323 if (UMEM_MALLOC_DECODE(buf
->malloc_stat
, high_size
) !=
325 message
= "invalid or corrupted buffer";
328 size
+= high_size
<< 32;
331 * destroy the main tag's malloc_stat
334 (buf
+ 1)->malloc_stat
= UMEM_FREE_PATTERN_32
;
338 data_size
= size
- overhead
;
341 buf
->malloc_stat
= UMEM_FREE_PATTERN_32
;
343 goto process_memalign
;
346 if (buf
->malloc_stat
== UMEM_FREE_PATTERN_32
)
347 message
= "double-free or invalid buffer";
349 message
= "invalid or corrupted buffer";
353 umem_err_recoverable("%s(%p): %s\n",
354 do_free
? "free" : "realloc", buf_arg
, message
);
361 _umem_free(base
, size
);
363 *data_size_arg
= data_size
;
370 vmem_xfree(umem_memalign_arena
, base
, size
);
372 *data_size_arg
= data_size
;
379 umem_malloc_free(void *buf
)
385 * Process buf, freeing it if it is not corrupt.
387 (void) process_free(buf
, 1, NULL
);
391 realloc(void *buf_arg
, size_t newsize
)
397 return (malloc(newsize
));
405 * get the old data size without freeing the buffer
407 if (process_free(buf_arg
, 0, &oldsize
) == 0) {
412 if (newsize
== oldsize
) /* size didn't change */
415 buf
= malloc(newsize
);
419 (void) memcpy(buf
, buf_arg
, MIN(newsize
, oldsize
));