Coverage Report

Created: 2023-06-07 06:25

/src/unbound/util/regional.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * regional.c -- region based memory allocator.
3
 *
4
 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5
 *
6
 * Copyright (c) 2007, NLnet Labs. All rights reserved.
7
 * 
8
 * This software is open source.
9
 * 
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 
14
 * Redistributions of source code must retain the above copyright notice,
15
 * this list of conditions and the following disclaimer.
16
 * 
17
 * Redistributions in binary form must reproduce the above copyright notice,
18
 * this list of conditions and the following disclaimer in the documentation
19
 * and/or other materials provided with the distribution.
20
 * 
21
 * Neither the name of the NLNET LABS nor the names of its contributors may
22
 * be used to endorse or promote products derived from this software without
23
 * specific prior written permission.
24
 * 
25
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
31
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
 */
37
38
/**
39
 * \file
40
 * Regional allocator. Allocates small portions of of larger chunks.
41
 */
42
43
#include "config.h"
44
#include "util/log.h"
45
#include "util/regional.h"
46
47
#ifdef ALIGNMENT
48
#  undef ALIGNMENT
49
#endif
50
/** increase size until it fits alignment of s bytes */
51
719k
#define ALIGN_UP(x, s)     (((x) + s - 1) & (~(s - 1)))
52
/** what size to align on; make sure a char* fits in it. */
53
5.83k
#define ALIGNMENT          (sizeof(uint64_t))
54
55
/** Default reasonable size for chunks */
56
9.85k
#define REGIONAL_CHUNK_SIZE         8192
57
#ifdef UNBOUND_ALLOC_NONREGIONAL
58
/** All objects allocated outside of chunks, for debug */
59
#define REGIONAL_LARGE_OBJECT_SIZE  0
60
#else
61
/** Default size for large objects - allocated outside of chunks. */
62
4.32k
#define REGIONAL_LARGE_OBJECT_SIZE  2048
63
#endif
64
65
struct regional* 
66
regional_create(void)
67
4.32k
{
68
4.32k
  return regional_create_custom(REGIONAL_CHUNK_SIZE);
69
4.32k
}
70
71
/** init regional struct with first block */
72
static void
73
regional_init(struct regional* r)
74
8.64k
{
75
8.64k
  size_t a = ALIGN_UP(sizeof(struct regional), ALIGNMENT);
76
8.64k
  r->data = (char*)r + a;
77
8.64k
  r->available = r->first_size - a;
78
8.64k
  r->next = NULL;
79
8.64k
  r->large_list = NULL;
80
8.64k
  r->total_large = 0;
81
8.64k
}
82
83
/**
84
 * Create a new region, with custom first block and large-object sizes.
85
 * @param size: length of first block.
86
 * @param large_object_size: outside of chunk allocation threshold.
87
 * @return: newly allocated regional.
88
 */
89
static struct regional*
90
regional_create_custom_large_object(size_t size, size_t large_object_size)
91
4.32k
{
92
4.32k
  struct regional* r;
93
4.32k
  size = ALIGN_UP(size, ALIGNMENT);
94
4.32k
  r = (struct regional*)malloc(size);
95
4.32k
  log_assert(sizeof(struct regional) <= size);
96
4.32k
  if(!r) return NULL;
97
4.32k
  r->first_size = size;
98
4.32k
  r->large_object_size = large_object_size;
99
4.32k
  regional_init(r);
100
4.32k
  return r;
101
4.32k
}
102
103
struct regional*
104
regional_create_custom(size_t size)
105
4.32k
{
106
4.32k
  if(size < sizeof(struct regional))
107
0
    size = sizeof(struct regional);
108
4.32k
  return regional_create_custom_large_object(size,
109
4.32k
    REGIONAL_LARGE_OBJECT_SIZE);
110
4.32k
}
111
112
struct regional*
113
regional_create_nochunk(size_t size)
114
0
{
115
0
  return regional_create_custom_large_object(size, 0);
116
0
}
117
118
void 
119
regional_free_all(struct regional *r)
120
4.32k
{
121
4.32k
  char* p = r->next, *np;
122
7.08k
  while(p) {
123
2.76k
    np = *(char**)p;
124
2.76k
    free(p);
125
2.76k
    p = np;
126
2.76k
  }
127
4.32k
  p = r->large_list;
128
4.42k
  while(p) {
129
103
    np = *(char**)p;
130
103
    free(p);
131
103
    p = np;
132
103
  }
133
4.32k
  regional_init(r);
134
4.32k
}
135
136
void 
137
regional_destroy(struct regional *r)
138
4.32k
{
139
4.32k
  if(!r) return;
140
4.32k
  regional_free_all(r);
141
4.32k
  free(r);
142
4.32k
}
143
144
void *
145
regional_alloc(struct regional *r, size_t size)
146
707k
{
147
707k
  size_t a;
148
707k
  void *s;
149
707k
  if(
150
707k
#if SIZEOF_SIZE_T == 8
151
707k
    (unsigned long long)size >= 0xffffffffffffff00ULL
152
#else
153
    (unsigned)size >= (unsigned)0xffffff00UL
154
#endif
155
707k
    )
156
0
    return NULL; /* protect against integer overflow in
157
      malloc and ALIGN_UP */
158
707k
  a = ALIGN_UP(size, ALIGNMENT);
159
  /* large objects */
160
707k
  if(a > r->large_object_size) {
161
103
    s = malloc(ALIGNMENT + size);
162
103
    if(!s) return NULL;
163
103
    r->total_large += ALIGNMENT+size;
164
103
    *(char**)s = r->large_list;
165
103
    r->large_list = (char*)s;
166
103
    return (char*)s+ALIGNMENT;
167
103
  }
168
  /* create a new chunk */
169
706k
  if(a > r->available) {
170
2.76k
    s = malloc(REGIONAL_CHUNK_SIZE);
171
2.76k
    if(!s) return NULL;
172
2.76k
    *(char**)s = r->next;
173
2.76k
    r->next = (char*)s;
174
2.76k
    r->data = (char*)s + ALIGNMENT;
175
2.76k
    r->available = REGIONAL_CHUNK_SIZE - ALIGNMENT;
176
2.76k
  }
177
  /* put in this chunk */
178
706k
  r->available -= a;
179
706k
  s = r->data;
180
706k
  r->data += a;
181
706k
  return s;
182
706k
}
183
184
void *
185
regional_alloc_init(struct regional* r, const void *init, size_t size)
186
696
{
187
696
  void *s = regional_alloc(r, size);
188
696
  if(!s) return NULL;
189
696
  memcpy(s, init, size);
190
696
  return s;
191
696
}
192
193
void *
194
regional_alloc_zero(struct regional *r, size_t size)
195
0
{
196
0
  void *s = regional_alloc(r, size);
197
0
  if(!s) return NULL;
198
0
  memset(s, 0, size);
199
0
  return s;
200
0
}
201
202
char *
203
regional_strdup(struct regional *r, const char *string)
204
0
{
205
0
  return (char*)regional_alloc_init(r, string, strlen(string)+1);
206
0
}
207
208
/**
209
 * reasonably slow, but stats and get_mem are not supposed to be fast
210
 * count the number of chunks in use
211
 */
212
static size_t
213
count_chunks(struct regional* r)
214
0
{
215
0
  size_t c = 1;
216
0
  char* p = r->next;
217
0
  while(p) {
218
0
    c++;
219
0
    p = *(char**)p;
220
0
  }
221
0
  return c;
222
0
}
223
224
/**
225
 * also reasonably slow, counts the number of large objects
226
 */
227
static size_t
228
count_large(struct regional* r)
229
0
{
230
0
  size_t c = 0;
231
0
  char* p = r->large_list;
232
0
  while(p) {
233
0
    c++;
234
0
    p = *(char**)p;
235
0
  }
236
0
  return c;
237
0
}
238
239
void 
240
regional_log_stats(struct regional *r)
241
0
{
242
  /* some basic assertions put here (non time critical code) */
243
0
  log_assert(ALIGNMENT >= sizeof(char*));
244
0
  log_assert(REGIONAL_CHUNK_SIZE > ALIGNMENT);
245
0
  log_assert(REGIONAL_CHUNK_SIZE-ALIGNMENT > r->large_object_size);
246
0
  log_assert(REGIONAL_CHUNK_SIZE >= sizeof(struct regional));
247
  /* debug print */
248
0
  log_info("regional %u chunks, %u large",
249
0
    (unsigned)count_chunks(r), (unsigned)count_large(r));
250
0
}
251
252
size_t 
253
regional_get_mem(struct regional* r)
254
0
{
255
0
  return r->first_size + (count_chunks(r)-1)*REGIONAL_CHUNK_SIZE 
256
0
    + r->total_large;
257
0
}