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