/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 | } |