blob: 8de00665f5c04d2efe592cb4d4b28d27bd0039b2 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/*
2 * libc/stdlib/malloc/realloc.c -- realloc function
3 *
4 * Copyright (C) 2002 NEC Corporation
5 * Copyright (C) 2002 Miles Bader <miles@gnu.org>
6 *
7 * This file is subject to the terms and conditions of the GNU Lesser
8 * General Public License. See the file COPYING.LIB in the main
9 * directory of this archive for more details.
10 *
11 * Written by Miles Bader <miles@gnu.org>
12 */
13
14#include <stdlib.h>
15#include <string.h>
16#include <errno.h>
17
18
19#include "malloc.h"
20#include "heap.h"
21
22
23void *
24realloc (void *mem, size_t new_size)
25{
26 size_t size;
27 char *base_mem;
28
29 /* Check for special cases. */
30 if (! new_size)
31 {
32 free (mem);
33 return malloc (new_size);
34 }
35 if (! mem)
36 return malloc (new_size);
37 /* This matches the check in malloc() */
38 if (unlikely(((unsigned long)new_size > (unsigned long)(MALLOC_HEADER_SIZE*-2))))
39 return NULL;
40
41 /* Normal realloc. */
42
43 base_mem = MALLOC_BASE (mem);
44 size = MALLOC_SIZE (mem);
45
46 /* Include extra space to record the size of the allocated block.
47 Also make sure that we're dealing in a multiple of the heap
48 allocation unit (SIZE is already guaranteed to be so).*/
49 new_size = HEAP_ADJUST_SIZE (new_size + MALLOC_HEADER_SIZE);
50
51 if (new_size < sizeof (struct heap_free_area))
52 /* Because we sometimes must use a freed block to hold a free-area node,
53 we must make sure that every allocated block can hold one. */
54 new_size = HEAP_ADJUST_SIZE (sizeof (struct heap_free_area));
55
56 MALLOC_DEBUG (1, "realloc: 0x%lx, %d (base = 0x%lx, total_size = %d)",
57 (long)mem, new_size, (long)base_mem, size);
58
59 if (new_size > size)
60 /* Grow the block. */
61 {
62 size_t extra = new_size - size;
63
64 __heap_lock (&__malloc_heap_lock);
65 extra = __heap_alloc_at (&__malloc_heap, base_mem + size, extra);
66 __heap_unlock (&__malloc_heap_lock);
67
68 if (extra)
69 /* Record the changed size. */
70 MALLOC_SET_SIZE (base_mem, size + extra);
71 else
72 /* Our attempts to extend MEM in place failed, just
73 allocate-and-copy. */
74 {
75 void *new_mem = malloc (new_size - MALLOC_HEADER_SIZE);
76 if (new_mem)
77 {
78 memcpy (new_mem, mem, size - MALLOC_HEADER_SIZE);
79 free (mem);
80 }
81 mem = new_mem;
82 }
83 }
84 else if (new_size + MALLOC_REALLOC_MIN_FREE_SIZE <= size)
85 /* Shrink the block. */
86 {
87 __heap_lock (&__malloc_heap_lock);
88 __heap_free (&__malloc_heap, base_mem + new_size, size - new_size);
89 __heap_unlock (&__malloc_heap_lock);
90 MALLOC_SET_SIZE (base_mem, new_size);
91 }
92
93 if (mem)
94 MALLOC_DEBUG (-1, "realloc: returning 0x%lx (base:0x%lx, total_size:%d)",
95 (long)mem, (long)MALLOC_BASE(mem), (long)MALLOC_SIZE(mem));
96 else
97 MALLOC_DEBUG (-1, "realloc: returning 0");
98
99 return mem;
100}