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
55#ifndef MIN
56# define MIN(a,b) ((a) <= (b)) ? (a) : (b)
57#endif
58
59void *
60Malloc(size_t bytes, const char *file __unused, int line __unused)
61{
62	return (Malloc_align(bytes, 1));
63}
64
65void *
66Memalign(size_t alignment, size_t bytes, const char *file __unused,
67    int line __unused)
68{
69	if (alignment == 0)
70		alignment = 1;
71
72	return (Malloc_align(bytes, alignment));
73}
74
75static void *
76Malloc_align(size_t bytes, size_t alignment)
77{
78	Guard *res;
79
80#ifdef USEENDGUARD
81	bytes += MALLOCALIGN + 1;
82#else
83	bytes += MALLOCALIGN;
84#endif
85
86	while ((res = znalloc(&MallocPool, bytes, alignment)) == NULL) {
87		int incr = (bytes + BLKEXTENDMASK) & ~BLKEXTENDMASK;
88		char *base;
89
90		if ((base = sbrk(incr)) == (char *)-1)
91			return (NULL);
92		zextendPool(&MallocPool, base, incr);
93		zfree(&MallocPool, base, incr);
94	}
95#ifdef DMALLOCDEBUG
96	if (++MallocCount > MallocMax)
97		MallocMax = MallocCount;
98#endif
99#ifdef USEGUARD
100	res->ga_Magic = GAMAGIC;
101#endif
102	res->ga_Bytes = bytes;
103#ifdef USEENDGUARD
104	*((signed char *)res + bytes - 1) = -2;
105#endif
106
107	return ((char *)res + MALLOCALIGN);
108}
109
110void
111Free(void *ptr, const char *file, int line)
112{
113	size_t bytes;
114
115	if (ptr != NULL) {
116		Guard *res = (void *)((char *)ptr - MALLOCALIGN);
117
118		if (file == NULL)
119			file = "unknown";
120#ifdef USEGUARD
121		if (res->ga_Magic == GAFREE) {
122			printf("free: duplicate free @ %p from %s:%d\n",
123			    ptr, file, line);
124			return;
125		}
126		if (res->ga_Magic != GAMAGIC) {
127			size_t dump_bytes;
128
129			dump_bytes = MIN((ptr - MallocPool.mp_Base), 512);
130			hexdump(ptr - dump_bytes, dump_bytes);
131			panic("free: guard1 fail @ %p from %s:%d",
132			    ptr, file, line);
133		}
134		res->ga_Magic = GAFREE;
135#endif
136#ifdef USEENDGUARD
137		if (*((signed char *)res + res->ga_Bytes - 1) == -1) {
138			printf("free: duplicate2 free @ %p from %s:%d\n",
139			    ptr, file, line);
140			return;
141		}
142		if (*((signed char *)res + res->ga_Bytes - 1) != -2)
143			panic("free: guard2 fail @ %p + %zu from %s:%d",
144			    ptr, res->ga_Bytes - MALLOCALIGN, file, line);
145		*((signed char *)res + res->ga_Bytes - 1) = -1;
146#endif
147
148		bytes = res->ga_Bytes;
149		zfree(&MallocPool, res, bytes);
150#ifdef DMALLOCDEBUG
151		--MallocCount;
152#endif
153	}
154}
155
156
157void *
158Calloc(size_t n1, size_t n2, const char *file, int line)
159{
160	uintptr_t bytes = (uintptr_t)n1 * (uintptr_t)n2;
161	void *res;
162
163	if ((res = Malloc(bytes, file, line)) != NULL) {
164		bzero(res, bytes);
165#ifdef DMALLOCDEBUG
166		if (++MallocCount > MallocMax)
167			MallocMax = MallocCount;
168#endif
169	}
170	return (res);
171}
172
173/*
174 * realloc() - I could be fancier here and free the old buffer before
175 *	       allocating the new one (saving potential fragmentation
176 *	       and potential buffer copies).  But I don't bother.
177 */
178
179void *
180Realloc(void *ptr, size_t size, const char *file, int line)
181{
182	void *res;
183	size_t old;
184
185	if ((res = Malloc(size, file, line)) != NULL) {
186		if (ptr != NULL) {
187			Guard *g = (Guard *)((char *)ptr - MALLOCALIGN);
188
189			old = g->ga_Bytes - MALLOCALIGN;
190			if (old < size)
191				bcopy(ptr, res, old);
192			else
193				bcopy(ptr, res, size);
194			Free(ptr, file, line);
195		} else {
196#ifdef DMALLOCDEBUG
197			if (++MallocCount > MallocMax)
198				MallocMax = MallocCount;
199#ifdef EXITSTATS
200			if (DidAtExit == 0) {
201				DidAtExit = 1;
202				atexit(mallocstats);
203			}
204#endif
205#endif
206		}
207	}
208	return (res);
209}
210
211void *
212Reallocf(void *ptr, size_t size, const char *file, int line)
213{
214	void *res;
215
216	if ((res = Realloc(ptr, size, file, line)) == NULL)
217		Free(ptr, file, line);
218	return (res);
219}
220
221#ifdef DMALLOCDEBUG
222
223void
224mallocstats(void)
225{
226	printf("Active Allocations: %d/%d\n", MallocCount, MallocMax);
227#ifdef ZALLOCDEBUG
228	zallocstats(&MallocPool);
229#endif
230}
231
232#endif
233