1 /*
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
23 void *
realloc(void * mem,size_t new_size)24 realloc (void *mem, size_t new_size)
25 {
26 size_t size;
27 char *base_mem;
28
29 if (! mem)
30 return malloc (new_size);
31
32 /* Check for special cases. */
33 if (! new_size)
34 {
35 free (mem);
36 return NULL;
37 }
38
39 /* This matches the check in malloc() */
40 if (unlikely(((unsigned long)new_size > (unsigned long)(MALLOC_HEADER_SIZE*-2))))
41 return NULL;
42
43 /* Normal realloc. */
44
45 base_mem = MALLOC_BASE (mem);
46 size = MALLOC_SIZE (mem);
47
48 /* Include extra space to record the size of the allocated block.
49 Also make sure that we're dealing in a multiple of the heap
50 allocation unit (SIZE is already guaranteed to be so).*/
51 new_size = HEAP_ADJUST_SIZE (new_size + MALLOC_HEADER_SIZE);
52
53 if (new_size < sizeof (struct heap_free_area))
54 /* Because we sometimes must use a freed block to hold a free-area node,
55 we must make sure that every allocated block can hold one. */
56 new_size = HEAP_ADJUST_SIZE (sizeof (struct heap_free_area));
57
58 MALLOC_DEBUG (1, "realloc: 0x%lx, %d (base = 0x%lx, total_size = %d)",
59 (long)mem, new_size, (long)base_mem, size);
60
61 if (new_size > size)
62 /* Grow the block. */
63 {
64 size_t extra = new_size - size;
65
66 __heap_lock (&__malloc_heap_lock);
67 extra = __heap_alloc_at (&__malloc_heap, base_mem + size, extra);
68 __heap_unlock (&__malloc_heap_lock);
69
70 if (extra)
71 /* Record the changed size. */
72 MALLOC_SET_SIZE (base_mem, size + extra);
73 else
74 /* Our attempts to extend MEM in place failed, just
75 allocate-and-copy. */
76 {
77 void *new_mem = malloc (new_size - MALLOC_HEADER_SIZE);
78 if (new_mem)
79 {
80 memcpy (new_mem, mem, size - MALLOC_HEADER_SIZE);
81 free (mem);
82 }
83 mem = new_mem;
84 }
85 }
86 else if (new_size + MALLOC_REALLOC_MIN_FREE_SIZE <= size)
87 /* Shrink the block. */
88 {
89 __heap_lock (&__malloc_heap_lock);
90 __heap_free (&__malloc_heap, base_mem + new_size, size - new_size);
91 __heap_unlock (&__malloc_heap_lock);
92 MALLOC_SET_SIZE (base_mem, new_size);
93 }
94
95 if (mem)
96 MALLOC_DEBUG (-1, "realloc: returning 0x%lx (base:0x%lx, total_size:%d)",
97 (long)mem, (long)MALLOC_BASE(mem), (long)MALLOC_SIZE(mem));
98 else
99 MALLOC_DEBUG (-1, "realloc: returning 0");
100
101 return mem;
102 }
103