Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Allow dlsym to call free() on memory that is allocated before mmalloc init
[simgrid.git] / src / xbt / mmalloc / mfree.c
1 /* Free a block of memory allocated by `mmalloc'. */
2
3 /* Copyright (c) 2010-2022. The SimGrid Team. All rights reserved.          */
4
5 /* This program is free software; you can redistribute it and/or modify it
6  * under the terms of the license (GNU LGPL) which comes with this package. */
7
8 /* Copyright 1990, 1991, 1992 Free Software Foundation
9
10    Written May 1989 by Mike Haertel.
11    Heavily modified Mar 1992 by Fred Fish.  (fnf@cygnus.com) */
12
13 #include "mmprivate.h"
14 #include "mc/mc.h"
15
16 /* Return memory to the heap.
17    Like `mfree' but don't call a mfree_hook if there is one.  */
18
19 /* Return memory to the heap.  */
20 void mfree(struct mdesc *mdp, void *ptr)
21 {
22   size_t frag_nb;
23   size_t i;
24   int it;
25
26   if (ptr == NULL)
27     return;
28
29   size_t block = BLOCK(ptr);
30
31   if ((char *) ptr < (char *) mdp->heapbase || block > mdp->heapsize) {
32     if ((char*)ptr <= (char*)mmalloc_preinit_buffer + mmalloc_preinit_buffer_size &&
33         (char*)ptr >= (char*)mmalloc_preinit_buffer)
34       /* This points to the static buffer for fake mallocs done by dlsym before mmalloc initialization, ignore it */
35       return;
36
37     fprintf(stderr,"Ouch, this pointer is not mine, I refuse to free it. Give me valid pointers, or give me death!!\n");
38     abort();
39   }
40
41   int type = mdp->heapinfo[block].type;
42
43   switch (type) {
44   case MMALLOC_TYPE_HEAPINFO:
45     UNLOCK(mdp);
46     fprintf(stderr, "Asked to free a fragment in a heapinfo block. I'm confused.\n");
47     abort();
48     break;
49
50   case MMALLOC_TYPE_FREE: /* Already free */
51     UNLOCK(mdp);
52     fprintf(stderr, "Asked to free a fragment in a block that is already free. I'm puzzled.\n");
53     abort();
54     break;
55
56   case MMALLOC_TYPE_UNFRAGMENTED:
57     /* Get as many statistics as early as we can.  */
58     mdp -> heapstats.chunks_used--;
59     mdp -> heapstats.bytes_used -=
60       mdp -> heapinfo[block].busy_block.size * BLOCKSIZE;
61     mdp -> heapstats.bytes_free +=
62       mdp -> heapinfo[block].busy_block.size * BLOCKSIZE;
63
64     if (MC_is_active() && mdp->heapinfo[block].busy_block.ignore > 0)
65       MC_unignore_heap(ptr, mdp->heapinfo[block].busy_block.busy_size);
66
67     /* Find the free cluster previous to this one in the free list.
68        Start searching at the last block referenced; this may benefit
69        programs with locality of allocation.  */
70     i = mdp->heapindex;
71     if (i > block) {
72       while (i > block) {
73         i = mdp->heapinfo[i].free_block.prev;
74       }
75     } else {
76       do {
77         i = mdp->heapinfo[i].free_block.next;
78       }
79       while ((i != 0) && (i < block));
80       i = mdp->heapinfo[i].free_block.prev;
81     }
82
83     /* Determine how to link this block into the free list.  */
84     if (block == i + mdp->heapinfo[i].free_block.size) {
85
86       /* Coalesce this block with its predecessor.  */
87       mdp->heapinfo[i].free_block.size += mdp->heapinfo[block].busy_block.size;
88       /* Mark all my ex-blocks as free */
89       for (it=0; it<mdp->heapinfo[block].busy_block.size; it++) {
90         if (mdp->heapinfo[block+it].type < 0) {
91           fprintf(stderr,
92                   "Internal Error: Asked to free a block already marked as free (block=%zu it=%d type=%d). "
93                   "Please report this bug.\n",
94                   block, it, mdp->heapinfo[block].type);
95           abort();
96         }
97         mdp->heapinfo[block+it].type = MMALLOC_TYPE_FREE;
98       }
99
100       block = i;
101     } else {
102       /* Really link this block back into the free list.  */
103       mdp->heapinfo[block].free_block.size = mdp->heapinfo[block].busy_block.size;
104       mdp->heapinfo[block].free_block.next = mdp->heapinfo[i].free_block.next;
105       mdp->heapinfo[block].free_block.prev = i;
106       mdp->heapinfo[i].free_block.next = block;
107       mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev = block;
108       mdp -> heapstats.chunks_free++;
109       /* Mark all my ex-blocks as free */
110       for (it=0; it<mdp->heapinfo[block].free_block.size; it++) {
111         if (mdp->heapinfo[block+it].type <0) {
112           fprintf(stderr,
113                   "Internal error: Asked to free a block already marked as free (block=%zu it=%d/%zu type=%d). "
114                   "Please report this bug.\n",
115                   block, it, mdp->heapinfo[block].free_block.size, mdp->heapinfo[block].type);
116           abort();
117         }
118         mdp->heapinfo[block+it].type = MMALLOC_TYPE_FREE;
119       }
120     }
121
122     /* Now that the block is linked in, see if we can coalesce it
123        with its successor (by deleting its successor from the list
124        and adding in its size).  */
125     if (block + mdp->heapinfo[block].free_block.size ==
126         mdp->heapinfo[block].free_block.next) {
127       mdp->heapinfo[block].free_block.size
128         += mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.size;
129       mdp->heapinfo[block].free_block.next
130         = mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.next;
131       mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev = block;
132       mdp -> heapstats.chunks_free--;
133     }
134
135     /* Now see if we can return stuff to the system.  */
136 #if 0
137           blocks = mdp -> heapinfo[block].free.size;
138           if (blocks >= FINAL_FREE_BLOCKS && block + blocks == mdp -> heaplimit
139           && mdp -> morecore (mdp, 0) == ADDRESS (block + blocks))
140           {
141           register size_t bytes = blocks * BLOCKSIZE;
142           mdp -> heaplimit -= blocks;
143           mdp -> morecore (mdp, -bytes);
144           mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
145           = mdp -> heapinfo[block].free.next;
146           mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
147           = mdp -> heapinfo[block].free.prev;
148           block = mdp -> heapinfo[block].free.prev;
149           mdp -> heapstats.chunks_free--;
150           mdp -> heapstats.bytes_free -= bytes;
151           }
152 #endif
153
154     /* Set the next search to begin at this block.
155        This is probably important to the trick where realloc returns the block to
156        the system before reasking for the same block with a bigger size.  */
157     mdp->heapindex = block;
158     break;
159
160   default:
161     if (type < 0) {
162       fprintf(stderr, "Unknown mmalloc block type.\n");
163       abort();
164     }
165
166     /* Do some of the statistics.  */
167     mdp -> heapstats.chunks_used--;
168     mdp -> heapstats.bytes_used -= 1 << type;
169     mdp -> heapstats.chunks_free++;
170     mdp -> heapstats.bytes_free += 1 << type;
171
172     frag_nb = RESIDUAL(ptr, BLOCKSIZE) >> type;
173
174     if( mdp->heapinfo[block].busy_frag.frag_size[frag_nb] == -1){
175       UNLOCK(mdp);
176       fprintf(stderr, "Asked to free a fragment that is already free. I'm puzzled\n");
177       abort();
178     }
179
180     if (MC_is_active() && mdp->heapinfo[block].busy_frag.ignore[frag_nb] > 0)
181       MC_unignore_heap(ptr, mdp->heapinfo[block].busy_frag.frag_size[frag_nb]);
182
183     /* Set size used in the fragment to -1 */
184     mdp->heapinfo[block].busy_frag.frag_size[frag_nb] = -1;
185     mdp->heapinfo[block].busy_frag.ignore[frag_nb] = 0;
186
187     if (mdp->heapinfo[block].busy_frag.nfree ==
188         (BLOCKSIZE >> type) - 1) {
189       /* If all fragments of this block are free, remove this block from its swag and free the whole block.  */
190       xbt_swag_remove(&mdp->heapinfo[block],&mdp->fraghead[type]);
191
192       /* pretend that this block is used and free it so that it gets properly coalesced with adjacent free blocks */
193       mdp->heapinfo[block].type = MMALLOC_TYPE_UNFRAGMENTED;
194       mdp->heapinfo[block].busy_block.size = 1;
195       mdp->heapinfo[block].busy_block.busy_size = 0;
196
197       /* Keep the statistics accurate.  */
198       mdp -> heapstats.chunks_used++;
199       mdp -> heapstats.bytes_used += BLOCKSIZE;
200       mdp -> heapstats.chunks_free -= BLOCKSIZE >> type;
201       mdp -> heapstats.bytes_free -= BLOCKSIZE;
202
203       mfree(mdp, ADDRESS(block));
204     } else if (mdp->heapinfo[block].busy_frag.nfree != 0) {
205       /* If some fragments of this block are free, you know what? I'm already happy. */
206       ++mdp->heapinfo[block].busy_frag.nfree;
207     } else {
208       /* No fragments of this block were free before the one we just released,
209        * so add this block to the swag and announce that
210        it is the first free fragment of this block. */
211       mdp->heapinfo[block].busy_frag.nfree = 1;
212       mdp->heapinfo[block].freehook.prev = NULL;
213       mdp->heapinfo[block].freehook.next = NULL;
214
215       xbt_swag_insert(&mdp->heapinfo[block],&mdp->fraghead[type]);
216     }
217     break;
218   }
219 }