Coverage Report

Created: 2023-08-28 06:30

/src/binutils-gdb/libiberty/objalloc.c
Line
Count
Source (jump to first uncovered line)
1
/* objalloc.c -- routines to allocate memory for objects
2
   Copyright (C) 1997-2023 Free Software Foundation, Inc.
3
   Written by Ian Lance Taylor, Cygnus Solutions.
4
5
This program is free software; you can redistribute it and/or modify it
6
under the terms of the GNU General Public License as published by the
7
Free Software Foundation; either version 2, or (at your option) any
8
later version.
9
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, 51 Franklin Street - Fifth Floor,
18
Boston, MA 02110-1301, USA.  */
19
20
#include "config.h"
21
#include "ansidecl.h"
22
23
#include "objalloc.h"
24
25
/* Get a definition for NULL.  */
26
#include <stdio.h>
27
28
#if VMS
29
#include <stdlib.h>
30
#include <unixlib.h>
31
#else
32
33
/* Get a definition for size_t.  */
34
#include <stddef.h>
35
36
#ifdef HAVE_STDLIB_H
37
#include <stdlib.h>
38
#else
39
/* For systems with larger pointers than ints, this must be declared.  */
40
extern void *malloc (size_t);
41
extern void free (void *);
42
#endif
43
44
#endif
45
46
/* These routines allocate space for an object.  Freeing allocated
47
   space may or may not free all more recently allocated space.
48
49
   We handle large and small allocation requests differently.  If we
50
   don't have enough space in the current block, and the allocation
51
   request is for more than 512 bytes, we simply pass it through to
52
   malloc.  */
53
54
/* The objalloc structure is defined in objalloc.h.  */
55
56
/* This structure appears at the start of each chunk.  */
57
58
struct objalloc_chunk
59
{
60
  /* Next chunk.  */
61
  struct objalloc_chunk *next;
62
  /* If this chunk contains large objects, this is the value of
63
     current_ptr when this chunk was allocated.  If this chunk
64
     contains small objects, this is NULL.  */
65
  char *current_ptr;
66
};
67
68
/* The aligned size of objalloc_chunk.  */
69
70
#define CHUNK_HEADER_SIZE         \
71
5.32M
  ((sizeof (struct objalloc_chunk) + OBJALLOC_ALIGN - 1) \
72
5.32M
   &~ (OBJALLOC_ALIGN - 1))
73
74
/* We ask for this much memory each time we create a chunk which is to
75
   hold small objects.  */
76
77
37.3M
#define CHUNK_SIZE (4096 - 32)
78
79
/* A request for this amount or more is just passed through to malloc.  */
80
81
932k
#define BIG_REQUEST (512)
82
83
/* Create an objalloc structure.  */
84
85
struct objalloc *
86
objalloc_create (void)
87
151k
{
88
151k
  struct objalloc *ret;
89
151k
  struct objalloc_chunk *chunk;
90
91
151k
  ret = (struct objalloc *) malloc (sizeof *ret);
92
151k
  if (ret == NULL)
93
0
    return NULL;
94
95
151k
  ret->chunks = (void *) malloc (CHUNK_SIZE);
96
151k
  if (ret->chunks == NULL)
97
0
    {
98
0
      free (ret);
99
0
      return NULL;
100
0
    }
101
102
151k
  chunk = (struct objalloc_chunk *) ret->chunks;
103
151k
  chunk->next = NULL;
104
151k
  chunk->current_ptr = NULL;
105
106
151k
  ret->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE;
107
151k
  ret->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE;
108
109
151k
  return ret;
110
151k
}
111
112
/* Allocate space from an objalloc structure.  */
113
114
void *
115
_objalloc_alloc (struct objalloc *o, unsigned long original_len)
116
932k
{
117
932k
  unsigned long len = original_len;
118
119
  /* We avoid confusion from zero sized objects by always allocating
120
     at least 1 byte.  */
121
932k
  if (len == 0)
122
0
    len = 1;
123
124
932k
  len = (len + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1);
125
126
  /* Check for overflow in the alignment operation above and the
127
     malloc argument below. */
128
932k
  if (len + CHUNK_HEADER_SIZE < original_len)
129
0
    return NULL;
130
131
932k
  if (len <= o->current_space)
132
0
    {
133
0
      o->current_ptr += len;
134
0
      o->current_space -= len;
135
0
      return (void *) (o->current_ptr - len);
136
0
    }
137
138
932k
  if (len >= BIG_REQUEST)
139
623k
    {
140
623k
      char *ret;
141
623k
      struct objalloc_chunk *chunk;
142
143
623k
      ret = (char *) malloc (CHUNK_HEADER_SIZE + len);
144
623k
      if (ret == NULL)
145
0
  return NULL;
146
147
623k
      chunk = (struct objalloc_chunk *) ret;
148
623k
      chunk->next = (struct objalloc_chunk *) o->chunks;
149
623k
      chunk->current_ptr = o->current_ptr;
150
151
623k
      o->chunks = (void *) chunk;
152
153
623k
      return (void *) (ret + CHUNK_HEADER_SIZE);
154
623k
    }
155
308k
  else
156
308k
    {
157
308k
      struct objalloc_chunk *chunk;
158
159
308k
      chunk = (struct objalloc_chunk *) malloc (CHUNK_SIZE);
160
308k
      if (chunk == NULL)
161
0
  return NULL;
162
308k
      chunk->next = (struct objalloc_chunk *) o->chunks;
163
308k
      chunk->current_ptr = NULL;
164
165
308k
      o->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE;
166
308k
      o->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE;
167
168
308k
      o->chunks = (void *) chunk;
169
170
308k
      return objalloc_alloc (o, len);
171
308k
    }
172
932k
}
173
174
/* Free an entire objalloc structure.  */
175
176
void
177
objalloc_free (struct objalloc *o)
178
151k
{
179
151k
  struct objalloc_chunk *l;
180
181
151k
  l = (struct objalloc_chunk *) o->chunks;
182
626k
  while (l != NULL)
183
474k
    {
184
474k
      struct objalloc_chunk *next;
185
186
474k
      next = l->next;
187
474k
      free (l);
188
474k
      l = next;
189
474k
    }
190
191
151k
  free (o);
192
151k
}
193
194
/* Free a block from an objalloc structure.  This also frees all more
195
   recently allocated blocks.  */
196
197
void
198
objalloc_free_block (struct objalloc *o, void *block)
199
18.2M
{
200
18.2M
  struct objalloc_chunk *p, *small;
201
18.2M
  char *b = (char *) block;
202
203
  /* First set P to the chunk which contains the block we are freeing,
204
     and set Q to the last small object chunk we see before P.  */
205
18.2M
  small = NULL;
206
20.5M
  for (p = (struct objalloc_chunk *) o->chunks; p != NULL; p = p->next)
207
20.5M
    {
208
20.5M
      if (p->current_ptr == NULL)
209
18.3M
  {
210
18.3M
    if (b > (char *) p && b < (char *) p + CHUNK_SIZE)
211
18.2M
      break;
212
132k
    small = p;
213
132k
  }
214
2.22M
      else
215
2.22M
  {
216
2.22M
    if (b == (char *) p + CHUNK_HEADER_SIZE)
217
662
      break;
218
2.22M
  }
219
20.5M
    }
220
221
  /* If we can't find the chunk, the caller has made a mistake.  */
222
18.2M
  if (p == NULL)
223
0
    abort ();
224
225
18.2M
  if (p->current_ptr == NULL)
226
18.2M
    {
227
18.2M
      struct objalloc_chunk *q;
228
18.2M
      struct objalloc_chunk *first;
229
230
      /* The block is in a chunk containing small objects.  We can
231
   free every chunk through SMALL, because they have certainly
232
   been allocated more recently.  After SMALL, we will not see
233
   any chunks containing small objects; we can free any big
234
   chunk if the current_ptr is greater than or equal to B.  We
235
   can then reset the new current_ptr to B.  */
236
237
18.2M
      first = NULL;
238
18.2M
      q = (struct objalloc_chunk *) o->chunks;
239
20.5M
      while (q != p)
240
2.35M
  {
241
2.35M
    struct objalloc_chunk *next;
242
243
2.35M
    next = q->next;
244
2.35M
    if (small != NULL)
245
138k
      {
246
138k
        if (small == q)
247
66.4k
    small = NULL;
248
138k
        free (q);
249
138k
      }
250
2.21M
    else if (q->current_ptr > b)
251
469k
      free (q);
252
1.74M
    else if (first == NULL)
253
911k
      first = q;
254
255
2.35M
    q = next;
256
2.35M
  }
257
258
18.2M
      if (first == NULL)
259
17.2M
  first = p;
260
18.2M
      o->chunks = (void *) first;
261
262
      /* Now start allocating from this small block again.  */
263
18.2M
      o->current_ptr = b;
264
18.2M
      o->current_space = ((char *) p + CHUNK_SIZE) - b;
265
18.2M
    }
266
662
  else
267
662
    {
268
662
      struct objalloc_chunk *q;
269
662
      char *current_ptr;
270
271
      /* This block is in a large chunk by itself.  We can free
272
         everything on the list up to and including this block.  We
273
         then start allocating from the next chunk containing small
274
         objects, setting current_ptr from the value stored with the
275
         large chunk we are freeing.  */
276
277
662
      current_ptr = p->current_ptr;
278
662
      p = p->next;
279
280
662
      q = (struct objalloc_chunk *) o->chunks;
281
2.31k
      while (q != p)
282
1.65k
  {
283
1.65k
    struct objalloc_chunk *next;
284
285
1.65k
    next = q->next;
286
1.65k
    free (q);
287
1.65k
    q = next;
288
1.65k
  }
289
290
662
      o->chunks = (void *) p;
291
292
964
      while (p->current_ptr != NULL)
293
302
  p = p->next;
294
295
662
      o->current_ptr = current_ptr;
296
662
      o->current_space = ((char *) p + CHUNK_SIZE) - current_ptr;
297
662
    }
298
18.2M
}