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