Coverage Report

Created: 2023-08-28 06:26

/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
1.90M
  ((sizeof (struct objalloc_chunk) + OBJALLOC_ALIGN - 1) \
72
1.90M
   &~ (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
4.27M
#define CHUNK_SIZE (4096 - 32)
78
79
/* A request for this amount or more is just passed through to malloc.  */
80
81
510k
#define BIG_REQUEST (512)
82
83
/* Create an objalloc structure.  */
84
85
struct objalloc *
86
objalloc_create (void)
87
23.6k
{
88
23.6k
  struct objalloc *ret;
89
23.6k
  struct objalloc_chunk *chunk;
90
91
23.6k
  ret = (struct objalloc *) malloc (sizeof *ret);
92
23.6k
  if (ret == NULL)
93
0
    return NULL;
94
95
23.6k
  ret->chunks = (void *) malloc (CHUNK_SIZE);
96
23.6k
  if (ret->chunks == NULL)
97
0
    {
98
0
      free (ret);
99
0
      return NULL;
100
0
    }
101
102
23.6k
  chunk = (struct objalloc_chunk *) ret->chunks;
103
23.6k
  chunk->next = NULL;
104
23.6k
  chunk->current_ptr = NULL;
105
106
23.6k
  ret->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE;
107
23.6k
  ret->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE;
108
109
23.6k
  return ret;
110
23.6k
}
111
112
/* Allocate space from an objalloc structure.  */
113
114
void *
115
_objalloc_alloc (struct objalloc *o, unsigned long original_len)
116
510k
{
117
510k
  unsigned long len = original_len;
118
119
  /* We avoid confusion from zero sized objects by always allocating
120
     at least 1 byte.  */
121
510k
  if (len == 0)
122
0
    len = 1;
123
124
510k
  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
510k
  if (len + CHUNK_HEADER_SIZE < original_len)
129
0
    return NULL;
130
131
510k
  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
510k
  if (len >= BIG_REQUEST)
139
259k
    {
140
259k
      char *ret;
141
259k
      struct objalloc_chunk *chunk;
142
143
259k
      ret = (char *) malloc (CHUNK_HEADER_SIZE + len);
144
259k
      if (ret == NULL)
145
0
  return NULL;
146
147
259k
      chunk = (struct objalloc_chunk *) ret;
148
259k
      chunk->next = (struct objalloc_chunk *) o->chunks;
149
259k
      chunk->current_ptr = o->current_ptr;
150
151
259k
      o->chunks = (void *) chunk;
152
153
259k
      return (void *) (ret + CHUNK_HEADER_SIZE);
154
259k
    }
155
250k
  else
156
250k
    {
157
250k
      struct objalloc_chunk *chunk;
158
159
250k
      chunk = (struct objalloc_chunk *) malloc (CHUNK_SIZE);
160
250k
      if (chunk == NULL)
161
0
  return NULL;
162
250k
      chunk->next = (struct objalloc_chunk *) o->chunks;
163
250k
      chunk->current_ptr = NULL;
164
165
250k
      o->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE;
166
250k
      o->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE;
167
168
250k
      o->chunks = (void *) chunk;
169
170
250k
      return objalloc_alloc (o, len);
171
250k
    }
172
510k
}
173
174
/* Free an entire objalloc structure.  */
175
176
void
177
objalloc_free (struct objalloc *o)
178
23.6k
{
179
23.6k
  struct objalloc_chunk *l;
180
181
23.6k
  l = (struct objalloc_chunk *) o->chunks;
182
470k
  while (l != NULL)
183
446k
    {
184
446k
      struct objalloc_chunk *next;
185
186
446k
      next = l->next;
187
446k
      free (l);
188
446k
      l = next;
189
446k
    }
190
191
23.6k
  free (o);
192
23.6k
}
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
1.86M
{
200
1.86M
  struct objalloc_chunk *p, *small;
201
1.86M
  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
1.86M
  small = NULL;
206
2.21M
  for (p = (struct objalloc_chunk *) o->chunks; p != NULL; p = p->next)
207
2.21M
    {
208
2.21M
      if (p->current_ptr == NULL)
209
1.89M
  {
210
1.89M
    if (b > (char *) p && b < (char *) p + CHUNK_SIZE)
211
1.86M
      break;
212
34.3k
    small = p;
213
34.3k
  }
214
322k
      else
215
322k
  {
216
322k
    if (b == (char *) p + CHUNK_HEADER_SIZE)
217
1.36k
      break;
218
322k
  }
219
2.21M
    }
220
221
  /* If we can't find the chunk, the caller has made a mistake.  */
222
1.86M
  if (p == NULL)
223
0
    abort ();
224
225
1.86M
  if (p->current_ptr == NULL)
226
1.86M
    {
227
1.86M
      struct objalloc_chunk *q;
228
1.86M
      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
1.86M
      first = NULL;
238
1.86M
      q = (struct objalloc_chunk *) o->chunks;
239
2.21M
      while (q != p)
240
352k
  {
241
352k
    struct objalloc_chunk *next;
242
243
352k
    next = q->next;
244
352k
    if (small != NULL)
245
74.3k
      {
246
74.3k
        if (small == q)
247
2.84k
    small = NULL;
248
74.3k
        free (q);
249
74.3k
      }
250
278k
    else if (q->current_ptr > b)
251
10.0k
      free (q);
252
268k
    else if (first == NULL)
253
121k
      first = q;
254
255
352k
    q = next;
256
352k
  }
257
258
1.86M
      if (first == NULL)
259
1.73M
  first = p;
260
1.86M
      o->chunks = (void *) first;
261
262
      /* Now start allocating from this small block again.  */
263
1.86M
      o->current_ptr = b;
264
1.86M
      o->current_space = ((char *) p + CHUNK_SIZE) - b;
265
1.86M
    }
266
1.36k
  else
267
1.36k
    {
268
1.36k
      struct objalloc_chunk *q;
269
1.36k
      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
1.36k
      current_ptr = p->current_ptr;
278
1.36k
      p = p->next;
279
280
1.36k
      q = (struct objalloc_chunk *) o->chunks;
281
4.70k
      while (q != p)
282
3.34k
  {
283
3.34k
    struct objalloc_chunk *next;
284
285
3.34k
    next = q->next;
286
3.34k
    free (q);
287
3.34k
    q = next;
288
3.34k
  }
289
290
1.36k
      o->chunks = (void *) p;
291
292
4.21k
      while (p->current_ptr != NULL)
293
2.85k
  p = p->next;
294
295
1.36k
      o->current_ptr = current_ptr;
296
1.36k
      o->current_space = ((char *) p + CHUNK_SIZE) - current_ptr;
297
1.36k
    }
298
1.86M
}