xref: /freebsd-src/stand/libsa/zalloc_malloc.c (revision 3e15b01d6914c927e37d1699645783acf286655c)
1ca987d46SWarner Losh /*
2ca987d46SWarner Losh  * This module derived from code donated to the FreeBSD Project by
3ca987d46SWarner Losh  * Matthew Dillon <dillon@backplane.com>
4ca987d46SWarner Losh  *
5ca987d46SWarner Losh  * Copyright (c) 1998 The FreeBSD Project
6ca987d46SWarner Losh  * All rights reserved.
7ca987d46SWarner Losh  *
8ca987d46SWarner Losh  * Redistribution and use in source and binary forms, with or without
9ca987d46SWarner Losh  * modification, are permitted provided that the following conditions
10ca987d46SWarner Losh  * are met:
11ca987d46SWarner Losh  * 1. Redistributions of source code must retain the above copyright
12ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer.
13ca987d46SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
14ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
15ca987d46SWarner Losh  *    documentation and/or other materials provided with the distribution.
16ca987d46SWarner Losh  *
17ca987d46SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18ca987d46SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19ca987d46SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20ca987d46SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21ca987d46SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22ca987d46SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23ca987d46SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24ca987d46SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25ca987d46SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26ca987d46SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27ca987d46SWarner Losh  * SUCH DAMAGE.
28ca987d46SWarner Losh  */
29ca987d46SWarner Losh 
30ca987d46SWarner Losh /*
31ca987d46SWarner Losh  * MALLOC.C - malloc equivalent, runs on top of zalloc and uses sbrk
32ca987d46SWarner Losh  */
33ca987d46SWarner Losh 
34ca987d46SWarner Losh #include "zalloc_defs.h"
35ca987d46SWarner Losh 
36ca987d46SWarner Losh static MemPool	MallocPool;
37ca987d46SWarner Losh 
38ca987d46SWarner Losh #ifdef DMALLOCDEBUG
39ca987d46SWarner Losh static int MallocMax;
40ca987d46SWarner Losh static int MallocCount;
41ca987d46SWarner Losh 
42ca987d46SWarner Losh void mallocstats(void);
43ca987d46SWarner Losh #endif
44ca987d46SWarner Losh 
45ca987d46SWarner Losh #ifdef malloc
46ca987d46SWarner Losh #undef malloc
47ca987d46SWarner Losh #undef free
48ca987d46SWarner Losh #endif
49ca987d46SWarner Losh 
5011db1a16SToomas Soome static void *Malloc_align(size_t, size_t);
5111db1a16SToomas Soome 
52*ed19b7c5SSimon J. Gerraty #ifndef MIN
53*ed19b7c5SSimon J. Gerraty # define MIN(a,b) ((a) <= (b)) ? (a) : (b)
54*ed19b7c5SSimon J. Gerraty #endif
55*ed19b7c5SSimon J. Gerraty 
56ca987d46SWarner Losh void *
Malloc(size_t bytes,const char * file __unused,int line __unused)5711db1a16SToomas Soome Malloc(size_t bytes, const char *file __unused, int line __unused)
5811db1a16SToomas Soome {
5911db1a16SToomas Soome 	return (Malloc_align(bytes, 1));
6011db1a16SToomas Soome }
6111db1a16SToomas Soome 
6211db1a16SToomas Soome void *
Memalign(size_t alignment,size_t bytes,const char * file __unused,int line __unused)6311db1a16SToomas Soome Memalign(size_t alignment, size_t bytes, const char *file __unused,
6411db1a16SToomas Soome     int line __unused)
6511db1a16SToomas Soome {
6611db1a16SToomas Soome 	if (alignment == 0)
6711db1a16SToomas Soome 		alignment = 1;
6811db1a16SToomas Soome 
6911db1a16SToomas Soome 	return (Malloc_align(bytes, alignment));
7011db1a16SToomas Soome }
7111db1a16SToomas Soome 
7211db1a16SToomas Soome static void *
Malloc_align(size_t bytes,size_t alignment)7311db1a16SToomas Soome Malloc_align(size_t bytes, size_t alignment)
74ca987d46SWarner Losh {
75ca987d46SWarner Losh 	Guard *res;
76ca987d46SWarner Losh 
77ca987d46SWarner Losh #ifdef USEENDGUARD
78ca987d46SWarner Losh 	bytes += MALLOCALIGN + 1;
79ca987d46SWarner Losh #else
80ca987d46SWarner Losh 	bytes += MALLOCALIGN;
81ca987d46SWarner Losh #endif
82ca987d46SWarner Losh 
8311db1a16SToomas Soome 	while ((res = znalloc(&MallocPool, bytes, alignment)) == NULL) {
84ca987d46SWarner Losh 		int incr = (bytes + BLKEXTENDMASK) & ~BLKEXTENDMASK;
85ca987d46SWarner Losh 		char *base;
86ca987d46SWarner Losh 
87ca987d46SWarner Losh 		if ((base = sbrk(incr)) == (char *)-1)
88ca987d46SWarner Losh 			return (NULL);
89ca987d46SWarner Losh 		zextendPool(&MallocPool, base, incr);
90ca987d46SWarner Losh 		zfree(&MallocPool, base, incr);
91ca987d46SWarner Losh 	}
92ca987d46SWarner Losh #ifdef DMALLOCDEBUG
93ca987d46SWarner Losh 	if (++MallocCount > MallocMax)
94ca987d46SWarner Losh 		MallocMax = MallocCount;
95ca987d46SWarner Losh #endif
96ca987d46SWarner Losh #ifdef USEGUARD
97ca987d46SWarner Losh 	res->ga_Magic = GAMAGIC;
98ca987d46SWarner Losh #endif
99ca987d46SWarner Losh 	res->ga_Bytes = bytes;
100ca987d46SWarner Losh #ifdef USEENDGUARD
101ca987d46SWarner Losh 	*((signed char *)res + bytes - 1) = -2;
102ca987d46SWarner Losh #endif
103ca987d46SWarner Losh 
104ca987d46SWarner Losh 	return ((char *)res + MALLOCALIGN);
105ca987d46SWarner Losh }
106ca987d46SWarner Losh 
107ca987d46SWarner Losh void
Free(void * ptr,const char * file,int line)108ca987d46SWarner Losh Free(void *ptr, const char *file, int line)
109ca987d46SWarner Losh {
110ca987d46SWarner Losh 	size_t bytes;
111ca987d46SWarner Losh 
112ca987d46SWarner Losh 	if (ptr != NULL) {
113ca987d46SWarner Losh 		Guard *res = (void *)((char *)ptr - MALLOCALIGN);
114ca987d46SWarner Losh 
115ca987d46SWarner Losh 		if (file == NULL)
116ca987d46SWarner Losh 			file = "unknown";
117ca987d46SWarner Losh #ifdef USEGUARD
118ca987d46SWarner Losh 		if (res->ga_Magic == GAFREE) {
119e57c0c2aSToomas Soome 			printf("free: duplicate free @ %p from %s:%d\n",
120e57c0c2aSToomas Soome 			    ptr, file, line);
121ca987d46SWarner Losh 			return;
122ca987d46SWarner Losh 		}
123*ed19b7c5SSimon J. Gerraty 		if (res->ga_Magic != GAMAGIC) {
124*ed19b7c5SSimon J. Gerraty 			size_t dump_bytes;
125*ed19b7c5SSimon J. Gerraty 
126*ed19b7c5SSimon J. Gerraty 			dump_bytes = MIN((ptr - MallocPool.mp_Base), 512);
127*ed19b7c5SSimon J. Gerraty 			hexdump(ptr - dump_bytes, dump_bytes);
128e57c0c2aSToomas Soome 			panic("free: guard1 fail @ %p from %s:%d",
129e57c0c2aSToomas Soome 			    ptr, file, line);
130*ed19b7c5SSimon J. Gerraty 		}
131ca987d46SWarner Losh 		res->ga_Magic = GAFREE;
132ca987d46SWarner Losh #endif
133ca987d46SWarner Losh #ifdef USEENDGUARD
134ca987d46SWarner Losh 		if (*((signed char *)res + res->ga_Bytes - 1) == -1) {
135e57c0c2aSToomas Soome 			printf("free: duplicate2 free @ %p from %s:%d\n",
136e57c0c2aSToomas Soome 			    ptr, file, line);
137ca987d46SWarner Losh 			return;
138ca987d46SWarner Losh 		}
139ca987d46SWarner Losh 		if (*((signed char *)res + res->ga_Bytes - 1) != -2)
140e57c0c2aSToomas Soome 			panic("free: guard2 fail @ %p + %zu from %s:%d",
141e57c0c2aSToomas Soome 			    ptr, res->ga_Bytes - MALLOCALIGN, file, line);
142ca987d46SWarner Losh 		*((signed char *)res + res->ga_Bytes - 1) = -1;
143ca987d46SWarner Losh #endif
144ca987d46SWarner Losh 
145ca987d46SWarner Losh 		bytes = res->ga_Bytes;
146ca987d46SWarner Losh 		zfree(&MallocPool, res, bytes);
147ca987d46SWarner Losh #ifdef DMALLOCDEBUG
148ca987d46SWarner Losh 		--MallocCount;
149ca987d46SWarner Losh #endif
150ca987d46SWarner Losh 	}
151ca987d46SWarner Losh }
152ca987d46SWarner Losh 
153ca987d46SWarner Losh 
154ca987d46SWarner Losh void *
Calloc(size_t n1,size_t n2,const char * file,int line)155ca987d46SWarner Losh Calloc(size_t n1, size_t n2, const char *file, int line)
156ca987d46SWarner Losh {
157ca987d46SWarner Losh 	uintptr_t bytes = (uintptr_t)n1 * (uintptr_t)n2;
158ca987d46SWarner Losh 	void *res;
159ca987d46SWarner Losh 
160ca987d46SWarner Losh 	if ((res = Malloc(bytes, file, line)) != NULL) {
161ca987d46SWarner Losh 		bzero(res, bytes);
162ca987d46SWarner Losh #ifdef DMALLOCDEBUG
163ca987d46SWarner Losh 		if (++MallocCount > MallocMax)
164ca987d46SWarner Losh 			MallocMax = MallocCount;
165ca987d46SWarner Losh #endif
166ca987d46SWarner Losh 	}
167ca987d46SWarner Losh 	return (res);
168ca987d46SWarner Losh }
169ca987d46SWarner Losh 
170ca987d46SWarner Losh /*
171ca987d46SWarner Losh  * realloc() - I could be fancier here and free the old buffer before
172ca987d46SWarner Losh  *	       allocating the new one (saving potential fragmentation
173ca987d46SWarner Losh  *	       and potential buffer copies).  But I don't bother.
174ca987d46SWarner Losh  */
175ca987d46SWarner Losh 
176ca987d46SWarner Losh void *
Realloc(void * ptr,size_t size,const char * file,int line)177ca987d46SWarner Losh Realloc(void *ptr, size_t size, const char *file, int line)
178ca987d46SWarner Losh {
179ca987d46SWarner Losh 	void *res;
180ca987d46SWarner Losh 	size_t old;
181ca987d46SWarner Losh 
182ca987d46SWarner Losh 	if ((res = Malloc(size, file, line)) != NULL) {
183e57c0c2aSToomas Soome 		if (ptr != NULL) {
184144c4ca0SToomas Soome 			Guard *g = (Guard *)((char *)ptr - MALLOCALIGN);
185144c4ca0SToomas Soome 
186144c4ca0SToomas Soome 			old = g->ga_Bytes - MALLOCALIGN;
187ca987d46SWarner Losh 			if (old < size)
188ca987d46SWarner Losh 				bcopy(ptr, res, old);
189ca987d46SWarner Losh 			else
190ca987d46SWarner Losh 				bcopy(ptr, res, size);
191ca987d46SWarner Losh 			Free(ptr, file, line);
192ca987d46SWarner Losh 		} else {
193ca987d46SWarner Losh #ifdef DMALLOCDEBUG
194ca987d46SWarner Losh 			if (++MallocCount > MallocMax)
195ca987d46SWarner Losh 				MallocMax = MallocCount;
196ca987d46SWarner Losh #ifdef EXITSTATS
197ca987d46SWarner Losh 			if (DidAtExit == 0) {
198ca987d46SWarner Losh 				DidAtExit = 1;
199ca987d46SWarner Losh 				atexit(mallocstats);
200ca987d46SWarner Losh 			}
201ca987d46SWarner Losh #endif
202ca987d46SWarner Losh #endif
203ca987d46SWarner Losh 		}
204ca987d46SWarner Losh 	}
205ca987d46SWarner Losh 	return (res);
206ca987d46SWarner Losh }
207ca987d46SWarner Losh 
208ca987d46SWarner Losh void *
Reallocf(void * ptr,size_t size,const char * file,int line)209ca987d46SWarner Losh Reallocf(void *ptr, size_t size, const char *file, int line)
210ca987d46SWarner Losh {
211ca987d46SWarner Losh 	void *res;
212ca987d46SWarner Losh 
213ca987d46SWarner Losh 	if ((res = Realloc(ptr, size, file, line)) == NULL)
214ca987d46SWarner Losh 		Free(ptr, file, line);
215ca987d46SWarner Losh 	return (res);
216ca987d46SWarner Losh }
217ca987d46SWarner Losh 
218ca987d46SWarner Losh #ifdef DMALLOCDEBUG
219ca987d46SWarner Losh 
220ca987d46SWarner Losh void
mallocstats(void)221ca987d46SWarner Losh mallocstats(void)
222ca987d46SWarner Losh {
223ca987d46SWarner Losh 	printf("Active Allocations: %d/%d\n", MallocCount, MallocMax);
224ca987d46SWarner Losh #ifdef ZALLOCDEBUG
225ca987d46SWarner Losh 	zallocstats(&MallocPool);
226ca987d46SWarner Losh #endif
227ca987d46SWarner Losh }
228ca987d46SWarner Losh 
229ca987d46SWarner Losh #endif
230