Coverage Report

Created: 2023-03-26 06:28

/src/httpd/srclib/apr/buckets/apr_buckets_alloc.c
Line
Count
Source (jump to first uncovered line)
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
 * contributor license agreements.  See the NOTICE file distributed with
3
 * this work for additional information regarding copyright ownership.
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * (the "License"); you may not use this file except in compliance with
6
 * the License.  You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include <stdlib.h>
18
19
#include "apr_buckets.h"
20
#include "apr_allocator.h"
21
#include "apr_support.h"
22
23
1.59k
#define ALLOC_AMT (8192 - APR_MEMNODE_T_SIZE)
24
25
typedef struct node_header_t {
26
    apr_size_t size;
27
    apr_bucket_alloc_t *alloc;
28
    apr_memnode_t *memnode;
29
    struct node_header_t *next;
30
} node_header_t;
31
32
79.7k
#define SIZEOF_NODE_HEADER_T  APR_ALIGN_DEFAULT(sizeof(node_header_t))
33
38.8k
#define SMALL_NODE_SIZE       (APR_BUCKET_ALLOC_SIZE + SIZEOF_NODE_HEADER_T)
34
35
/** A list of free memory from which new buckets or private bucket
36
 *  structures can be allocated.
37
 */
38
struct apr_bucket_alloc_t {
39
    apr_pool_t *pool;
40
    apr_allocator_t *allocator;
41
    node_header_t *freelist;
42
    apr_memnode_t *blocks;
43
};
44
45
static apr_status_t alloc_cleanup(void *data)
46
1.59k
{
47
1.59k
    apr_bucket_alloc_t *list = data;
48
1.59k
#if APR_POOL_DEBUG
49
1.59k
    apr_allocator_t *allocator = NULL;
50
1.59k
#endif
51
52
1.59k
#if APR_POOL_DEBUG
53
1.59k
    if (list->pool && list->allocator != apr_pool_allocator_get(list->pool)) {
54
1.59k
        allocator = list->allocator;
55
1.59k
    }
56
1.59k
#endif
57
58
1.59k
    apr_allocator_free(list->allocator, list->blocks);
59
60
1.59k
#if APR_POOL_DEBUG
61
1.59k
    if (allocator) {
62
1.59k
        apr_allocator_destroy(allocator);
63
1.59k
    }
64
1.59k
#endif
65
66
1.59k
    return APR_SUCCESS;
67
1.59k
}
68
69
APR_DECLARE_NONSTD(apr_bucket_alloc_t *) apr_bucket_alloc_create(apr_pool_t *p)
70
1.59k
{
71
1.59k
    apr_allocator_t *allocator = apr_pool_allocator_get(p);
72
1.59k
    apr_bucket_alloc_t *list;
73
74
1.59k
#if APR_POOL_DEBUG
75
    /* may be NULL for debug mode. */
76
1.59k
    if (allocator == NULL) {
77
1.59k
        if (apr_allocator_create(&allocator) != APR_SUCCESS) {
78
0
            apr_abortfunc_t fn = apr_pool_abort_get(p);
79
0
            if (fn)
80
0
                (fn)(APR_ENOMEM);
81
0
            abort();
82
0
        }
83
1.59k
    }
84
1.59k
#endif
85
1.59k
    list = apr_bucket_alloc_create_ex(allocator);
86
1.59k
    if (list == NULL) {
87
0
            apr_abortfunc_t fn = apr_pool_abort_get(p);
88
0
            if (fn)
89
0
                (fn)(APR_ENOMEM);
90
0
            abort();
91
0
    }
92
1.59k
    list->pool = p;
93
1.59k
    apr_pool_cleanup_register(list->pool, list, alloc_cleanup,
94
1.59k
                              apr_pool_cleanup_null);
95
96
1.59k
    return list;
97
1.59k
}
98
99
APR_DECLARE_NONSTD(apr_bucket_alloc_t *) apr_bucket_alloc_create_ex(
100
                                             apr_allocator_t *allocator)
101
1.59k
{
102
1.59k
    apr_bucket_alloc_t *list;
103
1.59k
    apr_memnode_t *block;
104
105
1.59k
    block = apr_allocator_alloc(allocator, ALLOC_AMT);
106
1.59k
    if (!block) {
107
0
        return NULL;
108
0
    }
109
1.59k
    list = (apr_bucket_alloc_t *)block->first_avail;
110
1.59k
    list->pool = NULL;
111
1.59k
    list->allocator = allocator;
112
1.59k
    list->freelist = NULL;
113
1.59k
    list->blocks = block;
114
1.59k
    block->first_avail += APR_ALIGN_DEFAULT(sizeof(*list));
115
1.59k
    APR_VALGRIND_NOACCESS(block->first_avail,
116
1.59k
                          block->endp - block->first_avail);
117
1.59k
    return list;
118
1.59k
}
119
120
APR_DECLARE_NONSTD(void) apr_bucket_alloc_destroy(apr_bucket_alloc_t *list)
121
0
{
122
0
    if (list->pool) {
123
0
        apr_pool_cleanup_kill(list->pool, list, alloc_cleanup);
124
0
    }
125
126
0
    apr_allocator_free(list->allocator, list->blocks);
127
128
0
#if APR_POOL_DEBUG
129
0
    if (list->pool && list->allocator != apr_pool_allocator_get(list->pool)) {
130
0
        apr_allocator_destroy(list->allocator);
131
0
    }
132
0
#endif
133
0
}
134
135
APR_DECLARE_NONSTD(apr_size_t) apr_bucket_alloc_aligned_floor(apr_bucket_alloc_t *list,
136
                                                              apr_size_t size)
137
0
{
138
0
    if (size <= SMALL_NODE_SIZE) {
139
0
        size = SMALL_NODE_SIZE;
140
0
    }
141
0
    else {
142
0
        if (size < APR_MEMNODE_T_SIZE) {
143
0
            size = apr_allocator_align(list->allocator, 0);
144
0
        }
145
0
        else {
146
0
            size = apr_allocator_align(list->allocator,
147
0
                                       size - APR_MEMNODE_T_SIZE);
148
0
        }
149
0
        size -= APR_MEMNODE_T_SIZE;
150
0
    }
151
0
    size -= SIZEOF_NODE_HEADER_T;
152
0
    return size;
153
0
}
154
155
APR_DECLARE_NONSTD(void *) apr_bucket_alloc(apr_size_t in_size,
156
                                            apr_bucket_alloc_t *list)
157
13.9k
{
158
13.9k
    node_header_t *node;
159
13.9k
    apr_memnode_t *active = list->blocks;
160
13.9k
    char *endp;
161
13.9k
    apr_size_t size;
162
163
13.9k
    size = in_size + SIZEOF_NODE_HEADER_T;
164
13.9k
    if (size <= SMALL_NODE_SIZE) {
165
12.8k
        if (list->freelist) {
166
6.90k
            node = list->freelist;
167
6.90k
            list->freelist = node->next;
168
6.90k
            APR_VALGRIND_UNDEFINED((char *)node + SIZEOF_NODE_HEADER_T,
169
6.90k
                                   SMALL_NODE_SIZE - SIZEOF_NODE_HEADER_T);
170
6.90k
        }
171
5.96k
        else {
172
5.96k
            endp = active->first_avail + SMALL_NODE_SIZE;
173
5.96k
            if (endp >= active->endp) {
174
0
                list->blocks = apr_allocator_alloc(list->allocator, ALLOC_AMT);
175
0
                if (!list->blocks) {
176
0
                    list->blocks = active;
177
0
                    return NULL;
178
0
                }
179
0
                list->blocks->next = active;
180
0
                active = list->blocks;
181
0
                endp = active->first_avail + SMALL_NODE_SIZE;
182
0
                APR_VALGRIND_NOACCESS(active->first_avail,
183
0
                                      active->endp - active->first_avail);
184
0
            }
185
5.96k
            node = (node_header_t *)active->first_avail;
186
5.96k
            APR_VALGRIND_UNDEFINED(node, SMALL_NODE_SIZE);
187
5.96k
            node->alloc = list;
188
5.96k
            node->memnode = active;
189
5.96k
            node->size = SMALL_NODE_SIZE;
190
5.96k
            active->first_avail = endp;
191
5.96k
        }
192
12.8k
    }
193
1.06k
    else {
194
1.06k
        apr_memnode_t *memnode = apr_allocator_alloc(list->allocator, size);
195
1.06k
        if (!memnode) {
196
0
            return NULL;
197
0
        }
198
1.06k
        node = (node_header_t *)memnode->first_avail;
199
1.06k
        node->alloc = list;
200
1.06k
        node->memnode = memnode;
201
1.06k
        node->size = size;
202
1.06k
    }
203
13.9k
    return ((char *)node) + SIZEOF_NODE_HEADER_T;
204
13.9k
}
205
206
#ifdef APR_BUCKET_DEBUG
207
#if APR_HAVE_STDLIB_H
208
#include <stdlib.h>
209
#endif
210
static void check_not_already_free(node_header_t *node)
211
{
212
    apr_bucket_alloc_t *list = node->alloc;
213
    node_header_t *curr = list->freelist;
214
215
    while (curr) {
216
        if (node == curr) {
217
            abort();
218
        }
219
        curr = curr->next;
220
    }
221
}
222
#else
223
#define check_not_already_free(node)
224
#endif
225
226
APR_DECLARE_NONSTD(void) apr_bucket_free(void *mem)
227
13.0k
{
228
13.0k
    node_header_t *node = (node_header_t *)((char *)mem - SIZEOF_NODE_HEADER_T);
229
13.0k
    apr_bucket_alloc_t *list = node->alloc;
230
231
13.0k
    if (node->size == SMALL_NODE_SIZE) {
232
11.9k
        check_not_already_free(node);
233
11.9k
        node->next = list->freelist;
234
11.9k
        list->freelist = node;
235
11.9k
        APR_VALGRIND_NOACCESS(mem, SMALL_NODE_SIZE - SIZEOF_NODE_HEADER_T);
236
11.9k
    }
237
1.06k
    else {
238
1.06k
        apr_allocator_free(list->allocator, node->memnode);
239
1.06k
    }
240
13.0k
}