malloc.c revision 1.7 1 /* $NetBSD: malloc.c,v 1.7 2023/07/05 10:57:44 riastradh Exp $ */
2
3 /*
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #if defined(LIBC_SCCS) && !defined(lint)
34 #if 0
35 static char sccsid[] = "@(#)malloc.c 8.1 (Berkeley) 6/4/93";
36 #else
37 __RCSID("$NetBSD: malloc.c,v 1.7 2023/07/05 10:57:44 riastradh Exp $");
38 #endif
39 #endif /* LIBC_SCCS and not lint */
40
41 /*
42 * malloc.c (Caltech) 2/21/82
43 * Chris Kingsley, kingsley@cit-20.
44 *
45 * This is a very fast storage allocator. It allocates blocks of a small
46 * number of different sizes, and keeps free lists of each size. Blocks that
47 * don't exactly fit are passed up to the next larger size. In this
48 * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
49 * This is designed for use in a virtual memory environment.
50 */
51
52 #include <sys/types.h>
53 #if defined(DEBUG) || defined(RCHECK)
54 #include <sys/uio.h>
55 #endif
56
57 #include <errno.h>
58 #include <limits.h>
59 #include <stddef.h>
60 #include <stdint.h>
61 #if defined(RCHECK) || defined(MSTATS)
62 #include <stdio.h>
63 #endif
64 #include <stdlib.h>
65 #include <string.h>
66 #include <unistd.h>
67
68 #include "reentrant.h"
69
70
71 /*
72 * The overhead on a block is at least 4 bytes. When free, this space
73 * contains a pointer to the next free block, and the bottom two bits must
74 * be zero. When in use, the first byte is set to MAGIC, and the second
75 * byte is the size index. The remaining bytes are for alignment.
76 * If range checking is enabled then a second word holds the size of the
77 * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
78 * The order of elements is critical: ov_magic must overlay the low order
79 * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
80 */
81 union overhead {
82 union overhead *ov_next; /* when free */
83 struct {
84 u_char ovu_magic; /* magic number */
85 u_char ovu_index; /* bucket # */
86 #ifdef RCHECK
87 u_short ovu_rmagic; /* range magic number */
88 u_long ovu_size; /* actual block size */
89 #endif
90 } ovu;
91 #define ov_magic ovu.ovu_magic
92 #define ov_index ovu.ovu_index
93 #define ov_rmagic ovu.ovu_rmagic
94 #define ov_size ovu.ovu_size
95 };
96
97 #define MAGIC 0xef /* magic # on accounting info */
98 #ifdef RCHECK
99 #define RMAGIC 0x5555 /* magic # on range info */
100 #endif
101
102 #ifdef RCHECK
103 #define RSLOP sizeof (u_short)
104 #else
105 #define RSLOP 0
106 #endif
107
108 /*
109 * nextf[i] is the pointer to the next free block of size 2^(i+3). The
110 * smallest allocatable block is 8 bytes. The overhead information
111 * precedes the data area returned to the user.
112 */
113 #define NBUCKETS 30
114 static union overhead *nextf[NBUCKETS];
115
116 static long pagesz; /* page size */
117 static int pagebucket; /* page size bucket */
118
119 #ifdef MSTATS
120 /*
121 * nmalloc[i] is the difference between the number of mallocs and frees
122 * for a given block size.
123 */
124 static u_int nmalloc[NBUCKETS];
125 #endif
126
127 #ifdef _REENT
128 static mutex_t malloc_mutex = MUTEX_INITIALIZER;
129 #endif
130
131 static void morecore(int);
132 static int findbucket(union overhead *, int);
133 #ifdef MSTATS
134 void mstats(const char *);
135 #endif
136
137 #if defined(DEBUG) || defined(RCHECK)
138 #define ASSERT(p) if (!(p)) botch(__STRING(p))
139
140 static void botch(const char *);
141
142 /*
143 * NOTE: since this may be called while malloc_mutex is locked, stdio must not
144 * be used in this function.
145 */
146 static void
147 botch(const char *s)
148 {
149 struct iovec iov[3];
150
151 iov[0].iov_base = __UNCONST("\nassertion botched: ");
152 iov[0].iov_len = 20;
153 iov[1].iov_base = __UNCONST(s);
154 iov[1].iov_len = strlen(s);
155 iov[2].iov_base = __UNCONST("\n");
156 iov[2].iov_len = 1;
157
158 /*
159 * This place deserves a word of warning: a cancellation point will
160 * occur when executing writev(), and we might be still owning
161 * malloc_mutex. At this point we need to disable cancellation
162 * until `after' abort() because i) establishing a cancellation handler
163 * might, depending on the implementation, result in another malloc()
164 * to be executed, and ii) it is really not desirable to let execution
165 * continue. `Fix me.'
166 *
167 * Note that holding mutex_lock during abort() is safe.
168 */
169
170 (void)writev(STDERR_FILENO, iov, 3);
171 abort();
172 }
173 #else
174 #define ASSERT(p) ((void)sizeof((long)(p)))
175 #endif
176
177 void *
178 malloc(size_t nbytes)
179 {
180 union overhead *op;
181 int bucket;
182 long n;
183 unsigned amt;
184
185 mutex_lock(&malloc_mutex);
186
187 /*
188 * First time malloc is called, setup page size and
189 * align break pointer so all data will be page aligned.
190 */
191 if (pagesz == 0) {
192 pagesz = n = getpagesize();
193 ASSERT(pagesz > 0);
194 op = (union overhead *)(void *)sbrk(0);
195 n = n - sizeof (*op) - ((long)op & (n - 1));
196 if (n < 0)
197 n += pagesz;
198 if (n) {
199 if (sbrk((int)n) == (void *)-1) {
200 mutex_unlock(&malloc_mutex);
201 return (NULL);
202 }
203 }
204 bucket = 0;
205 amt = 8;
206 while (pagesz > amt) {
207 amt <<= 1;
208 bucket++;
209 }
210 pagebucket = bucket;
211 }
212 /*
213 * Convert amount of memory requested into closest block size
214 * stored in hash buckets which satisfies request.
215 * Account for space used per block for accounting.
216 */
217 if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
218 #ifndef RCHECK
219 amt = 8; /* size of first bucket */
220 bucket = 0;
221 #else
222 amt = 16; /* size of first bucket */
223 bucket = 1;
224 #endif
225 n = -((long)sizeof (*op) + RSLOP);
226 } else {
227 amt = (unsigned)pagesz;
228 bucket = pagebucket;
229 }
230 while (nbytes > amt + n) {
231 amt <<= 1;
232 if (amt == 0)
233 return (NULL);
234 bucket++;
235 }
236 /*
237 * If nothing in hash bucket right now,
238 * request more memory from the system.
239 */
240 if ((op = nextf[bucket]) == NULL) {
241 morecore(bucket);
242 if ((op = nextf[bucket]) == NULL) {
243 mutex_unlock(&malloc_mutex);
244 return (NULL);
245 }
246 }
247 /* remove from linked list */
248 nextf[bucket] = op->ov_next;
249 op->ov_magic = MAGIC;
250 op->ov_index = bucket;
251 #ifdef MSTATS
252 nmalloc[bucket]++;
253 #endif
254 mutex_unlock(&malloc_mutex);
255 #ifdef RCHECK
256 /*
257 * Record allocated size of block and
258 * bound space with magic numbers.
259 */
260 op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
261 op->ov_rmagic = RMAGIC;
262 *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
263 #endif
264 return ((void *)(op + 1));
265 }
266
267 /*
268 * Allocate more memory to the indicated bucket.
269 */
270 static void
271 morecore(int bucket)
272 {
273 union overhead *op;
274 long sz; /* size of desired block */
275 long amt; /* amount to allocate */
276 long nblks; /* how many blocks we get */
277
278 /*
279 * sbrk_size <= 0 only for big, FLUFFY, requests (about
280 * 2^30 bytes on a VAX, I think) or for a negative arg.
281 */
282 sz = 1 << (bucket + 3);
283 #ifdef DEBUG
284 ASSERT(sz > 0);
285 #else
286 if (sz <= 0)
287 return;
288 #endif
289 if (sz < pagesz) {
290 amt = pagesz;
291 nblks = amt / sz;
292 } else {
293 amt = sz + pagesz;
294 nblks = 1;
295 }
296 op = (union overhead *)(void *)sbrk((int)amt);
297 /* no more room! */
298 if ((long)op == -1)
299 return;
300 /*
301 * Add new memory allocated to that on
302 * free list for this hash bucket.
303 */
304 nextf[bucket] = op;
305 while (--nblks > 0) {
306 op->ov_next =
307 (union overhead *)(void *)((caddr_t)(void *)op+(size_t)sz);
308 op = op->ov_next;
309 }
310 }
311
312 void
313 free(void *cp)
314 {
315 long size;
316 union overhead *op;
317
318 if (cp == NULL)
319 return;
320 op = (union overhead *)(void *)((caddr_t)cp - sizeof (union overhead));
321 #ifdef DEBUG
322 ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
323 #else
324 if (op->ov_magic != MAGIC)
325 return; /* sanity */
326 #endif
327 #ifdef RCHECK
328 ASSERT(op->ov_rmagic == RMAGIC);
329 ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
330 #endif
331 size = op->ov_index;
332 ASSERT(size < NBUCKETS);
333 mutex_lock(&malloc_mutex);
334 op->ov_next = nextf[(unsigned int)size];/* also clobbers ov_magic */
335 nextf[(unsigned int)size] = op;
336 #ifdef MSTATS
337 nmalloc[(size_t)size]--;
338 #endif
339 mutex_unlock(&malloc_mutex);
340 }
341
342 /*
343 * When a program attempts "storage compaction" as mentioned in the
344 * old malloc man page, it realloc's an already freed block. Usually
345 * this is the last block it freed; occasionally it might be farther
346 * back. We have to search all the free lists for the block in order
347 * to determine its bucket: 1st we make one pass thru the lists
348 * checking only the first block in each; if that fails we search
349 * ``__realloc_srchlen'' blocks in each list for a match (the variable
350 * is extern so the caller can modify it). If that fails we just copy
351 * however many bytes was given to realloc() and hope it's not huge.
352 */
353 int __realloc_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */
354
355 void *
356 realloc(void *cp, size_t nbytes)
357 {
358 u_long onb;
359 long i;
360 union overhead *op;
361 char *res;
362 int was_alloced = 0;
363
364 if (cp == NULL)
365 return (malloc(nbytes));
366 if (nbytes == 0) {
367 free (cp);
368 return (NULL);
369 }
370 op = (union overhead *)(void *)((caddr_t)cp - sizeof (union overhead));
371 mutex_lock(&malloc_mutex);
372 if (op->ov_magic == MAGIC) {
373 was_alloced++;
374 i = op->ov_index;
375 } else {
376 /*
377 * Already free, doing "compaction".
378 *
379 * Search for the old block of memory on the
380 * free list. First, check the most common
381 * case (last element free'd), then (this failing)
382 * the last ``__realloc_srchlen'' items free'd.
383 * If all lookups fail, then assume the size of
384 * the memory block being realloc'd is the
385 * largest possible (so that all "nbytes" of new
386 * memory are copied into). Note that this could cause
387 * a memory fault if the old area was tiny, and the moon
388 * is gibbous. However, that is very unlikely.
389 */
390 if ((i = findbucket(op, 1)) < 0 &&
391 (i = findbucket(op, __realloc_srchlen)) < 0)
392 i = NBUCKETS;
393 }
394 onb = (u_long)1 << (u_long)(i + 3);
395 if (onb < pagesz)
396 onb -= sizeof (*op) + RSLOP;
397 else
398 onb += pagesz - sizeof (*op) - RSLOP;
399 /* avoid the copy if same size block */
400 if (was_alloced) {
401 if (i) {
402 i = (long)1 << (long)(i + 2);
403 if (i < pagesz)
404 i -= sizeof (*op) + RSLOP;
405 else
406 i += pagesz - sizeof (*op) - RSLOP;
407 }
408 if (nbytes <= onb && nbytes > i) {
409 #ifdef RCHECK
410 op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
411 *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
412 #endif
413 mutex_unlock(&malloc_mutex);
414 return (cp);
415
416 }
417 #ifndef _REENT
418 else
419 free(cp);
420 #endif
421 }
422 mutex_unlock(&malloc_mutex);
423 if ((res = malloc(nbytes)) == NULL) {
424 #ifdef _REENT
425 free(cp);
426 #endif
427 return (NULL);
428 }
429 #ifndef _REENT
430 if (cp != res) /* common optimization if "compacting" */
431 (void)memmove(res, cp, (size_t)((nbytes < onb) ? nbytes : onb));
432 #else
433 (void)memmove(res, cp, (size_t)((nbytes < onb) ? nbytes : onb));
434 free(cp);
435 #endif
436 return (res);
437 }
438
439 /*
440 * Search ``srchlen'' elements of each free list for a block whose
441 * header starts at ``freep''. If srchlen is -1 search the whole list.
442 * Return bucket number, or -1 if not found.
443 */
444 static int
445 findbucket(union overhead *freep, int srchlen)
446 {
447 union overhead *p;
448 int i, j;
449
450 for (i = 0; i < NBUCKETS; i++) {
451 j = 0;
452 for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
453 if (p == freep)
454 return (i);
455 j++;
456 }
457 }
458 return (-1);
459 }
460
461 #ifdef MSTATS
462 /*
463 * mstats - print out statistics about malloc
464 *
465 * Prints two lines of numbers, one showing the length of the free list
466 * for each size category, the second showing the number of mallocs -
467 * frees for each size category.
468 */
469 void
470 mstats(char *s)
471 {
472 int i, j;
473 union overhead *p;
474 int totfree = 0,
475 totused = 0;
476
477 fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
478 for (i = 0; i < NBUCKETS; i++) {
479 for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
480 ;
481 fprintf(stderr, " %d", j);
482 totfree += j * (1 << (i + 3));
483 }
484 fprintf(stderr, "\nused:\t");
485 for (i = 0; i < NBUCKETS; i++) {
486 fprintf(stderr, " %d", nmalloc[i]);
487 totused += nmalloc[i] * (1 << (i + 3));
488 }
489 fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
490 totused, totfree);
491 }
492 #endif
493
494 /*
495 * Additional front ends:
496 * - aligned_alloc (C11)
497 * - calloc(n,m) = malloc(n*m) without overflow
498 * - posix_memalign (POSIX)
499 *
500 * These must all be in the same compilation unit as malloc, realloc,
501 * and free (or -lbsdmalloc must be surrounded by -Wl,--whole-archive
502 * -lbsdmalloc -Wl,--no-whole-archive) in order to override the libc
503 * built-in malloc implementation.
504 *
505 * Allocations of size n, up to and including the page size, are
506 * already aligned by malloc on multiples of n. Larger alignment is
507 * not supported.
508 */
509
510 static long __constfunc
511 cachedpagesize(void)
512 {
513 long n;
514
515 /* XXX atomic_load_relaxed, but that's not defined in userland atm */
516 if (__predict_false((n = pagesz) == 0)) {
517 mutex_lock(&malloc_mutex);
518 if ((n = pagesz) == 0)
519 n = pagesz = getpagesize();
520 mutex_unlock(&malloc_mutex);
521 }
522
523 return n;
524 }
525
526 void *
527 aligned_alloc(size_t alignment, size_t size)
528 {
529 char *p;
530
531 if (alignment == 0 ||
532 (alignment & (alignment - 1)) != 0 ||
533 alignment > cachedpagesize()) {
534 errno = EINVAL;
535 return NULL;
536 }
537 p = malloc(size);
538 if (__predict_false(p == NULL))
539 ASSERT((uintptr_t)p % alignment == 0);
540 return p;
541 }
542
543 void *
544 calloc(size_t nmemb, size_t size)
545 {
546 void *p;
547 size_t n;
548
549 if (__builtin_mul_overflow_p(nmemb, size, (size_t)0)) {
550 errno = ENOMEM;
551 return NULL;
552 }
553 n = nmemb * size;
554 p = malloc(n);
555 if (__predict_false(p == NULL))
556 return NULL;
557 memset(p, 0, n);
558 return p;
559 }
560
561 int
562 posix_memalign(void **memptr, size_t alignment, size_t size)
563 {
564 char *p;
565
566 if (alignment < sizeof(void *) ||
567 (alignment & (alignment - 1)) != 0 ||
568 alignment > cachedpagesize())
569 return EINVAL;
570 p = malloc(size < alignment ? alignment : size);
571 if (__predict_false(p == NULL))
572 return ENOMEM;
573 ASSERT((uintptr_t)p % alignment == 0);
574 *memptr = p;
575 return 0;
576 }
577
578 /*
579 * libc hooks required by fork
580 */
581
582 #include "../libc/include/extern.h"
583
584 void
585 _malloc_prefork(void)
586 {
587
588 mutex_lock(&malloc_mutex);
589 }
590
591 void
592 _malloc_postfork(void)
593 {
594
595 mutex_unlock(&malloc_mutex);
596 }
597
598 void
599 _malloc_postfork_child(void)
600 {
601
602 mutex_unlock(&malloc_mutex);
603 }
604