| File: | libs/apr/memory/unix/apr_pools.c |
| Location: | line 823, column 21 |
| Description: | Access to field 'allocator' results in a dereference of a null pointer (loaded from variable 'parent') |
| 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 "apr.h" | |||
| 18 | #include "apr_private.h" | |||
| 19 | ||||
| 20 | #include "apr_atomic.h" | |||
| 21 | #include "apr_portable.h" /* for get_os_proc */ | |||
| 22 | #include "apr_strings.h" | |||
| 23 | #include "apr_general.h" | |||
| 24 | #include "apr_pools.h" | |||
| 25 | #include "apr_allocator.h" | |||
| 26 | #include "apr_lib.h" | |||
| 27 | #include "apr_thread_mutex.h" | |||
| 28 | #include "apr_hash.h" | |||
| 29 | #include "apr_time.h" | |||
| 30 | #define APR_WANT_MEMFUNC | |||
| 31 | #include "apr_want.h" | |||
| 32 | #include "apr_env.h" | |||
| 33 | ||||
| 34 | #if APR_HAVE_STDLIB_H1 | |||
| 35 | #include <stdlib.h> /* for malloc, free and abort */ | |||
| 36 | #endif | |||
| 37 | ||||
| 38 | #if APR_HAVE_UNISTD_H1 | |||
| 39 | #include <unistd.h> /* for getpid */ | |||
| 40 | #endif | |||
| 41 | ||||
| 42 | ||||
| 43 | /* | |||
| 44 | * Magic numbers | |||
| 45 | */ | |||
| 46 | ||||
| 47 | #define MIN_ALLOC8192 8192 | |||
| 48 | #define MAX_INDEX20 20 | |||
| 49 | ||||
| 50 | #define BOUNDARY_INDEX12 12 | |||
| 51 | #define BOUNDARY_SIZE(1 << 12) (1 << BOUNDARY_INDEX12) | |||
| 52 | ||||
| 53 | /* | |||
| 54 | * Timing constants for killing subprocesses | |||
| 55 | * There is a total 3-second delay between sending a SIGINT | |||
| 56 | * and sending of the final SIGKILL. | |||
| 57 | * TIMEOUT_INTERVAL should be set to TIMEOUT_USECS / 64 | |||
| 58 | * for the exponetial timeout alogrithm. | |||
| 59 | */ | |||
| 60 | #define TIMEOUT_USECS3000000 3000000 | |||
| 61 | #define TIMEOUT_INTERVAL46875 46875 | |||
| 62 | ||||
| 63 | /* | |||
| 64 | * Allocator | |||
| 65 | */ | |||
| 66 | ||||
| 67 | struct apr_allocator_t { | |||
| 68 | apr_uint32_t max_index; | |||
| 69 | apr_uint32_t max_free_index; | |||
| 70 | apr_uint32_t current_free_index; | |||
| 71 | #if APR_HAS_THREADS1 | |||
| 72 | apr_thread_mutex_t *mutex; | |||
| 73 | #endif /* APR_HAS_THREADS */ | |||
| 74 | apr_pool_t *owner; | |||
| 75 | apr_memnode_t *free[MAX_INDEX20]; | |||
| 76 | }; | |||
| 77 | ||||
| 78 | #define SIZEOF_ALLOCATOR_T(((sizeof(apr_allocator_t)) + ((8) - 1)) & ~((8) - 1)) APR_ALIGN_DEFAULT(sizeof(apr_allocator_t))(((sizeof(apr_allocator_t)) + ((8) - 1)) & ~((8) - 1)) | |||
| 79 | ||||
| 80 | ||||
| 81 | /* | |||
| 82 | * Allocator | |||
| 83 | */ | |||
| 84 | ||||
| 85 | APR_DECLARE(apr_status_t)apr_status_t apr_allocator_create(apr_allocator_t **allocator) | |||
| 86 | { | |||
| 87 | apr_allocator_t *new_allocator; | |||
| 88 | ||||
| 89 | *allocator = NULL((void*)0); | |||
| 90 | ||||
| 91 | if ((new_allocator = malloc(SIZEOF_ALLOCATOR_T(((sizeof(apr_allocator_t)) + ((8) - 1)) & ~((8) - 1)))) == NULL((void*)0)) | |||
| 92 | return APR_ENOMEM12; | |||
| 93 | ||||
| 94 | memset(new_allocator, 0, SIZEOF_ALLOCATOR_T(((sizeof(apr_allocator_t)) + ((8) - 1)) & ~((8) - 1))); | |||
| 95 | new_allocator->max_free_index = APR_ALLOCATOR_MAX_FREE_UNLIMITED0; | |||
| 96 | ||||
| 97 | *allocator = new_allocator; | |||
| 98 | ||||
| 99 | return APR_SUCCESS0; | |||
| 100 | } | |||
| 101 | ||||
| 102 | APR_DECLARE(void)void apr_allocator_destroy(apr_allocator_t *allocator) | |||
| 103 | { | |||
| 104 | apr_uint32_t index; | |||
| 105 | apr_memnode_t *node, **ref; | |||
| 106 | ||||
| 107 | for (index = 0; index < MAX_INDEX20; index++) { | |||
| 108 | ref = &allocator->free[index]; | |||
| 109 | while ((node = *ref) != NULL((void*)0)) { | |||
| 110 | *ref = node->next; | |||
| 111 | free(node); | |||
| 112 | } | |||
| 113 | } | |||
| 114 | ||||
| 115 | free(allocator); | |||
| 116 | } | |||
| 117 | ||||
| 118 | #if APR_HAS_THREADS1 | |||
| 119 | APR_DECLARE(void)void apr_allocator_mutex_set(apr_allocator_t *allocator, | |||
| 120 | apr_thread_mutex_t *mutex) | |||
| 121 | { | |||
| 122 | allocator->mutex = mutex; | |||
| 123 | } | |||
| 124 | ||||
| 125 | APR_DECLARE(apr_thread_mutex_t *)apr_thread_mutex_t * apr_allocator_mutex_get( | |||
| 126 | apr_allocator_t *allocator) | |||
| 127 | { | |||
| 128 | return allocator->mutex; | |||
| 129 | } | |||
| 130 | #endif /* APR_HAS_THREADS */ | |||
| 131 | ||||
| 132 | APR_DECLARE(void)void apr_allocator_owner_set(apr_allocator_t *allocator, | |||
| 133 | apr_pool_t *pool) | |||
| 134 | { | |||
| 135 | allocator->owner = pool; | |||
| 136 | } | |||
| 137 | ||||
| 138 | APR_DECLARE(apr_pool_t *)apr_pool_t * apr_allocator_owner_get(apr_allocator_t *allocator) | |||
| 139 | { | |||
| 140 | return allocator->owner; | |||
| 141 | } | |||
| 142 | ||||
| 143 | APR_DECLARE(void)void apr_allocator_max_free_set(apr_allocator_t *allocator, | |||
| 144 | apr_size_t in_size) | |||
| 145 | { | |||
| 146 | apr_uint32_t max_free_index; | |||
| 147 | apr_uint32_t size = (APR_UINT32_TRUNC_CASTapr_uint32_t)in_size; | |||
| 148 | ||||
| 149 | #if APR_HAS_THREADS1 | |||
| 150 | apr_thread_mutex_t *mutex; | |||
| 151 | ||||
| 152 | mutex = apr_allocator_mutex_get(allocator); | |||
| 153 | if (mutex != NULL((void*)0)) | |||
| 154 | apr_thread_mutex_lock(mutex); | |||
| 155 | #endif /* APR_HAS_THREADS */ | |||
| 156 | ||||
| 157 | max_free_index = APR_ALIGN(size, BOUNDARY_SIZE)(((size) + (((1 << 12)) - 1)) & ~(((1 << 12)) - 1)) >> BOUNDARY_INDEX12; | |||
| 158 | allocator->current_free_index += max_free_index; | |||
| 159 | allocator->current_free_index -= allocator->max_free_index; | |||
| 160 | allocator->max_free_index = max_free_index; | |||
| 161 | if (allocator->current_free_index > max_free_index) | |||
| 162 | allocator->current_free_index = max_free_index; | |||
| 163 | ||||
| 164 | #if APR_HAS_THREADS1 | |||
| 165 | if (mutex != NULL((void*)0)) | |||
| 166 | apr_thread_mutex_unlock(mutex); | |||
| 167 | #endif | |||
| 168 | } | |||
| 169 | ||||
| 170 | static APR_INLINE__inline__ | |||
| 171 | apr_memnode_t *allocator_alloc(apr_allocator_t *allocator, apr_size_t size) | |||
| 172 | { | |||
| 173 | apr_memnode_t *node, **ref; | |||
| 174 | apr_uint32_t max_index; | |||
| 175 | apr_size_t i, index; | |||
| 176 | ||||
| 177 | /* Round up the block size to the next boundary, but always | |||
| 178 | * allocate at least a certain size (MIN_ALLOC). | |||
| 179 | */ | |||
| 180 | size = APR_ALIGN(size + APR_MEMNODE_T_SIZE, BOUNDARY_SIZE)(((size + (((sizeof(apr_memnode_t)) + ((8) - 1)) & ~((8) - 1))) + (((1 << 12)) - 1)) & ~(((1 << 12)) - 1 )); | |||
| 181 | if (size < MIN_ALLOC8192) | |||
| 182 | size = MIN_ALLOC8192; | |||
| 183 | ||||
| 184 | /* Find the index for this node size by | |||
| 185 | * dividing its size by the boundary size | |||
| 186 | */ | |||
| 187 | index = (size >> BOUNDARY_INDEX12) - 1; | |||
| 188 | ||||
| 189 | if (index > APR_UINT32_MAX0xFFFFFFFFUL) { | |||
| 190 | return NULL((void*)0); | |||
| 191 | } | |||
| 192 | ||||
| 193 | /* First see if there are any nodes in the area we know | |||
| 194 | * our node will fit into. | |||
| 195 | */ | |||
| 196 | if (index <= allocator->max_index) { | |||
| 197 | #if APR_HAS_THREADS1 | |||
| 198 | if (allocator->mutex) | |||
| 199 | apr_thread_mutex_lock(allocator->mutex); | |||
| 200 | #endif /* APR_HAS_THREADS */ | |||
| 201 | ||||
| 202 | /* Walk the free list to see if there are | |||
| 203 | * any nodes on it of the requested size | |||
| 204 | * | |||
| 205 | * NOTE: an optimization would be to check | |||
| 206 | * allocator->free[index] first and if no | |||
| 207 | * node is present, directly use | |||
| 208 | * allocator->free[max_index]. This seems | |||
| 209 | * like overkill though and could cause | |||
| 210 | * memory waste. | |||
| 211 | */ | |||
| 212 | max_index = allocator->max_index; | |||
| 213 | ref = &allocator->free[index]; | |||
| 214 | i = index; | |||
| 215 | while (*ref == NULL((void*)0) && i < max_index) { | |||
| 216 | ref++; | |||
| 217 | i++; | |||
| 218 | } | |||
| 219 | ||||
| 220 | if ((node = *ref) != NULL((void*)0)) { | |||
| 221 | /* If we have found a node and it doesn't have any | |||
| 222 | * nodes waiting in line behind it _and_ we are on | |||
| 223 | * the highest available index, find the new highest | |||
| 224 | * available index | |||
| 225 | */ | |||
| 226 | if ((*ref = node->next) == NULL((void*)0) && i >= max_index) { | |||
| 227 | do { | |||
| 228 | ref--; | |||
| 229 | max_index--; | |||
| 230 | } | |||
| 231 | while (*ref == NULL((void*)0) && max_index > 0); | |||
| 232 | ||||
| 233 | allocator->max_index = max_index; | |||
| 234 | } | |||
| 235 | ||||
| 236 | allocator->current_free_index += node->index; | |||
| 237 | if (allocator->current_free_index > allocator->max_free_index) | |||
| 238 | allocator->current_free_index = allocator->max_free_index; | |||
| 239 | ||||
| 240 | #if APR_HAS_THREADS1 | |||
| 241 | if (allocator->mutex) | |||
| 242 | apr_thread_mutex_unlock(allocator->mutex); | |||
| 243 | #endif /* APR_HAS_THREADS */ | |||
| 244 | ||||
| 245 | node->next = NULL((void*)0); | |||
| 246 | node->first_avail = (char *)node + APR_MEMNODE_T_SIZE(((sizeof(apr_memnode_t)) + ((8) - 1)) & ~((8) - 1)); | |||
| 247 | ||||
| 248 | return node; | |||
| 249 | } | |||
| 250 | ||||
| 251 | #if APR_HAS_THREADS1 | |||
| 252 | if (allocator->mutex) | |||
| 253 | apr_thread_mutex_unlock(allocator->mutex); | |||
| 254 | #endif /* APR_HAS_THREADS */ | |||
| 255 | } | |||
| 256 | ||||
| 257 | /* If we found nothing, seek the sink (at index 0), if | |||
| 258 | * it is not empty. | |||
| 259 | */ | |||
| 260 | else if (allocator->free[0]) { | |||
| 261 | #if APR_HAS_THREADS1 | |||
| 262 | if (allocator->mutex) | |||
| 263 | apr_thread_mutex_lock(allocator->mutex); | |||
| 264 | #endif /* APR_HAS_THREADS */ | |||
| 265 | ||||
| 266 | /* Walk the free list to see if there are | |||
| 267 | * any nodes on it of the requested size | |||
| 268 | */ | |||
| 269 | ref = &allocator->free[0]; | |||
| 270 | while ((node = *ref) != NULL((void*)0) && index > node->index) | |||
| 271 | ref = &node->next; | |||
| 272 | ||||
| 273 | if (node) { | |||
| 274 | *ref = node->next; | |||
| 275 | ||||
| 276 | allocator->current_free_index += node->index; | |||
| 277 | if (allocator->current_free_index > allocator->max_free_index) | |||
| 278 | allocator->current_free_index = allocator->max_free_index; | |||
| 279 | ||||
| 280 | #if APR_HAS_THREADS1 | |||
| 281 | if (allocator->mutex) | |||
| 282 | apr_thread_mutex_unlock(allocator->mutex); | |||
| 283 | #endif /* APR_HAS_THREADS */ | |||
| 284 | ||||
| 285 | node->next = NULL((void*)0); | |||
| 286 | node->first_avail = (char *)node + APR_MEMNODE_T_SIZE(((sizeof(apr_memnode_t)) + ((8) - 1)) & ~((8) - 1)); | |||
| 287 | ||||
| 288 | return node; | |||
| 289 | } | |||
| 290 | ||||
| 291 | #if APR_HAS_THREADS1 | |||
| 292 | if (allocator->mutex) | |||
| 293 | apr_thread_mutex_unlock(allocator->mutex); | |||
| 294 | #endif /* APR_HAS_THREADS */ | |||
| 295 | } | |||
| 296 | ||||
| 297 | /* If we haven't got a suitable node, malloc a new one | |||
| 298 | * and initialize it. | |||
| 299 | */ | |||
| 300 | if ((node = malloc(size)) == NULL((void*)0)) | |||
| 301 | return NULL((void*)0); | |||
| 302 | ||||
| 303 | node->next = NULL((void*)0); | |||
| 304 | node->index = (APR_UINT32_TRUNC_CASTapr_uint32_t)index; | |||
| 305 | node->first_avail = (char *)node + APR_MEMNODE_T_SIZE(((sizeof(apr_memnode_t)) + ((8) - 1)) & ~((8) - 1)); | |||
| 306 | node->endp = (char *)node + size; | |||
| 307 | ||||
| 308 | return node; | |||
| 309 | } | |||
| 310 | ||||
| 311 | static APR_INLINE__inline__ | |||
| 312 | void allocator_free(apr_allocator_t *allocator, apr_memnode_t *node) | |||
| 313 | { | |||
| 314 | apr_memnode_t *next, *freelist = NULL((void*)0); | |||
| 315 | apr_uint32_t index, max_index; | |||
| 316 | apr_uint32_t max_free_index, current_free_index; | |||
| 317 | ||||
| 318 | #if APR_HAS_THREADS1 | |||
| 319 | if (allocator->mutex) | |||
| 320 | apr_thread_mutex_lock(allocator->mutex); | |||
| 321 | #endif /* APR_HAS_THREADS */ | |||
| 322 | ||||
| 323 | max_index = allocator->max_index; | |||
| 324 | max_free_index = allocator->max_free_index; | |||
| 325 | current_free_index = allocator->current_free_index; | |||
| 326 | ||||
| 327 | /* Walk the list of submitted nodes and free them one by one, | |||
| 328 | * shoving them in the right 'size' buckets as we go. | |||
| 329 | */ | |||
| 330 | do { | |||
| 331 | next = node->next; | |||
| 332 | index = node->index; | |||
| 333 | ||||
| 334 | if (max_free_index != APR_ALLOCATOR_MAX_FREE_UNLIMITED0 | |||
| 335 | && index > current_free_index) { | |||
| 336 | node->next = freelist; | |||
| 337 | freelist = node; | |||
| 338 | } | |||
| 339 | else if (index < MAX_INDEX20) { | |||
| 340 | /* Add the node to the appropiate 'size' bucket. Adjust | |||
| 341 | * the max_index when appropiate. | |||
| 342 | */ | |||
| 343 | if ((node->next = allocator->free[index]) == NULL((void*)0) | |||
| 344 | && index > max_index) { | |||
| 345 | max_index = index; | |||
| 346 | } | |||
| 347 | allocator->free[index] = node; | |||
| 348 | current_free_index -= index; | |||
| 349 | } | |||
| 350 | else { | |||
| 351 | /* This node is too large to keep in a specific size bucket, | |||
| 352 | * just add it to the sink (at index 0). | |||
| 353 | */ | |||
| 354 | node->next = allocator->free[0]; | |||
| 355 | allocator->free[0] = node; | |||
| 356 | current_free_index -= index; | |||
| 357 | } | |||
| 358 | } while ((node = next) != NULL((void*)0)); | |||
| 359 | ||||
| 360 | allocator->max_index = max_index; | |||
| 361 | allocator->current_free_index = current_free_index; | |||
| 362 | ||||
| 363 | #if APR_HAS_THREADS1 | |||
| 364 | if (allocator->mutex) | |||
| 365 | apr_thread_mutex_unlock(allocator->mutex); | |||
| 366 | #endif /* APR_HAS_THREADS */ | |||
| 367 | ||||
| 368 | while (freelist != NULL((void*)0)) { | |||
| 369 | node = freelist; | |||
| 370 | freelist = node->next; | |||
| 371 | free(node); | |||
| 372 | } | |||
| 373 | } | |||
| 374 | ||||
| 375 | APR_DECLARE(apr_memnode_t *)apr_memnode_t * apr_allocator_alloc(apr_allocator_t *allocator, | |||
| 376 | apr_size_t size) | |||
| 377 | { | |||
| 378 | return allocator_alloc(allocator, size); | |||
| 379 | } | |||
| 380 | ||||
| 381 | APR_DECLARE(void)void apr_allocator_free(apr_allocator_t *allocator, | |||
| 382 | apr_memnode_t *node) | |||
| 383 | { | |||
| 384 | allocator_free(allocator, node); | |||
| 385 | } | |||
| 386 | ||||
| 387 | ||||
| 388 | ||||
| 389 | /* | |||
| 390 | * Debug level | |||
| 391 | */ | |||
| 392 | ||||
| 393 | #define APR_POOL_DEBUG_GENERAL0x01 0x01 | |||
| 394 | #define APR_POOL_DEBUG_VERBOSE0x02 0x02 | |||
| 395 | #define APR_POOL_DEBUG_LIFETIME0x04 0x04 | |||
| 396 | #define APR_POOL_DEBUG_OWNER0x08 0x08 | |||
| 397 | #define APR_POOL_DEBUG_VERBOSE_ALLOC0x10 0x10 | |||
| 398 | ||||
| 399 | #define APR_POOL_DEBUG_VERBOSE_ALL(0x02 | 0x10) (APR_POOL_DEBUG_VERBOSE0x02 \ | |||
| 400 | | APR_POOL_DEBUG_VERBOSE_ALLOC0x10) | |||
| 401 | ||||
| 402 | ||||
| 403 | /* | |||
| 404 | * Structures | |||
| 405 | */ | |||
| 406 | ||||
| 407 | typedef struct cleanup_t cleanup_t; | |||
| 408 | ||||
| 409 | /** A list of processes */ | |||
| 410 | struct process_chain { | |||
| 411 | /** The process ID */ | |||
| 412 | apr_proc_t *proc; | |||
| 413 | apr_kill_conditions_e kill_how; | |||
| 414 | /** The next process in the list */ | |||
| 415 | struct process_chain *next; | |||
| 416 | }; | |||
| 417 | ||||
| 418 | ||||
| 419 | #if APR_POOL_DEBUG0 | |||
| 420 | ||||
| 421 | typedef struct debug_node_t debug_node_t; | |||
| 422 | ||||
| 423 | struct debug_node_t { | |||
| 424 | debug_node_t *next; | |||
| 425 | apr_uint32_t index; | |||
| 426 | void *beginp[64]; | |||
| 427 | void *endp[64]; | |||
| 428 | }; | |||
| 429 | ||||
| 430 | #define SIZEOF_DEBUG_NODE_T APR_ALIGN_DEFAULT(sizeof(debug_node_t))(((sizeof(debug_node_t)) + ((8) - 1)) & ~((8) - 1)) | |||
| 431 | ||||
| 432 | #endif /* APR_POOL_DEBUG */ | |||
| 433 | ||||
| 434 | /* The ref field in the apr_pool_t struct holds a | |||
| 435 | * pointer to the pointer referencing this pool. | |||
| 436 | * It is used for parent, child, sibling management. | |||
| 437 | * Look at apr_pool_create_ex() and apr_pool_destroy() | |||
| 438 | * to see how it is used. | |||
| 439 | */ | |||
| 440 | struct apr_pool_t { | |||
| 441 | apr_pool_t *parent; | |||
| 442 | apr_pool_t *child; | |||
| 443 | apr_pool_t *sibling; | |||
| 444 | apr_pool_t **ref; | |||
| 445 | cleanup_t *cleanups; | |||
| 446 | cleanup_t *free_cleanups; | |||
| 447 | apr_allocator_t *allocator; | |||
| 448 | struct process_chain *subprocesses; | |||
| 449 | apr_abortfunc_t abort_fn; | |||
| 450 | apr_hash_t *user_data; | |||
| 451 | const char *tag; | |||
| 452 | #if APR_HAS_THREADS1 | |||
| 453 | apr_thread_mutex_t *user_mutex; | |||
| 454 | #endif | |||
| 455 | #if !APR_POOL_DEBUG0 | |||
| 456 | apr_memnode_t *active; | |||
| 457 | apr_memnode_t *self; /* The node containing the pool itself */ | |||
| 458 | char *self_first_avail; | |||
| 459 | ||||
| 460 | #else /* APR_POOL_DEBUG */ | |||
| 461 | apr_pool_t *joined; /* the caller has guaranteed that this pool | |||
| 462 | * will survive as long as ->joined */ | |||
| 463 | debug_node_t *nodes; | |||
| 464 | const char *file_line; | |||
| 465 | apr_uint32_t creation_flags; | |||
| 466 | unsigned int stat_alloc; | |||
| 467 | unsigned int stat_total_alloc; | |||
| 468 | unsigned int stat_clear; | |||
| 469 | #if APR_HAS_THREADS1 | |||
| 470 | apr_os_thread_t owner; | |||
| 471 | apr_thread_mutex_t *mutex; | |||
| 472 | #endif /* APR_HAS_THREADS */ | |||
| 473 | #endif /* APR_POOL_DEBUG */ | |||
| 474 | #ifdef NETWARE | |||
| 475 | apr_os_proc_t owner_proc; | |||
| 476 | ||||
| 477 | #endif /* defined(NETWARE) */ | |||
| 478 | }; | |||
| 479 | ||||
| 480 | #define SIZEOF_POOL_T(((sizeof(apr_pool_t)) + ((8) - 1)) & ~((8) - 1)) APR_ALIGN_DEFAULT(sizeof(apr_pool_t))(((sizeof(apr_pool_t)) + ((8) - 1)) & ~((8) - 1)) | |||
| 481 | ||||
| 482 | ||||
| 483 | /* | |||
| 484 | * Variables | |||
| 485 | */ | |||
| 486 | ||||
| 487 | static apr_byte_t apr_pools_initialized = 0; | |||
| 488 | static apr_pool_t *global_pool = NULL((void*)0); | |||
| 489 | ||||
| 490 | #if !APR_POOL_DEBUG0 | |||
| 491 | static apr_allocator_t *global_allocator = NULL((void*)0); | |||
| 492 | #endif /* !APR_POOL_DEBUG */ | |||
| 493 | ||||
| 494 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE_ALL(0x02 | 0x10)) | |||
| 495 | static apr_file_t *file_stderr = NULL((void*)0); | |||
| 496 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ | |||
| 497 | ||||
| 498 | /* | |||
| 499 | * Local functions | |||
| 500 | */ | |||
| 501 | ||||
| 502 | static void run_cleanups(cleanup_t **c); | |||
| 503 | static void run_child_cleanups(cleanup_t **c); | |||
| 504 | static void free_proc_chain(struct process_chain *procs); | |||
| 505 | ||||
| 506 | #if APR_POOL_DEBUG0 | |||
| 507 | static void pool_destroy_debug(apr_pool_t *pool, const char *file_line); | |||
| 508 | #endif | |||
| 509 | ||||
| 510 | #if !APR_POOL_DEBUG0 | |||
| 511 | /* | |||
| 512 | * Initialization | |||
| 513 | */ | |||
| 514 | ||||
| 515 | APR_DECLARE(apr_status_t)apr_status_t apr_pool_initialize(void) | |||
| 516 | { | |||
| 517 | apr_status_t rv; | |||
| 518 | ||||
| 519 | if (apr_pools_initialized++) | |||
| 520 | return APR_SUCCESS0; | |||
| 521 | ||||
| 522 | if ((rv = apr_allocator_create(&global_allocator)) != APR_SUCCESS0) { | |||
| 523 | apr_pools_initialized = 0; | |||
| 524 | return rv; | |||
| 525 | } | |||
| 526 | ||||
| 527 | if ((rv = apr_pool_create_ex(&global_pool, NULL((void*)0), NULL((void*)0), | |||
| 528 | global_allocator)) != APR_SUCCESS0) { | |||
| 529 | apr_allocator_destroy(global_allocator); | |||
| 530 | global_allocator = NULL((void*)0); | |||
| 531 | apr_pools_initialized = 0; | |||
| 532 | return rv; | |||
| 533 | } | |||
| 534 | ||||
| 535 | apr_pool_tag(global_pool, "apr_global_pool"); | |||
| 536 | ||||
| 537 | /* This has to happen here because mutexes might be backed by | |||
| 538 | * atomics. It used to be snug and safe in apr_initialize(). | |||
| 539 | */ | |||
| 540 | if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS0) { | |||
| 541 | return rv; | |||
| 542 | } | |||
| 543 | ||||
| 544 | #if APR_HAS_THREADS1 | |||
| 545 | { | |||
| 546 | apr_thread_mutex_t *mutex; | |||
| 547 | ||||
| 548 | if ((rv = apr_thread_mutex_create(&mutex, | |||
| 549 | APR_THREAD_MUTEX_DEFAULT0x0, | |||
| 550 | global_pool)) != APR_SUCCESS0) { | |||
| 551 | return rv; | |||
| 552 | } | |||
| 553 | ||||
| 554 | apr_allocator_mutex_set(global_allocator, mutex); | |||
| 555 | } | |||
| 556 | #endif /* APR_HAS_THREADS */ | |||
| 557 | ||||
| 558 | apr_allocator_owner_set(global_allocator, global_pool); | |||
| 559 | ||||
| 560 | return APR_SUCCESS0; | |||
| 561 | } | |||
| 562 | ||||
| 563 | APR_DECLARE(void)void apr_pool_terminate(void) | |||
| 564 | { | |||
| 565 | if (!apr_pools_initialized) | |||
| 566 | return; | |||
| 567 | ||||
| 568 | if (--apr_pools_initialized) | |||
| 569 | return; | |||
| 570 | ||||
| 571 | apr_pool_destroy(global_pool); /* This will also destroy the mutex */ | |||
| 572 | global_pool = NULL((void*)0); | |||
| 573 | ||||
| 574 | global_allocator = NULL((void*)0); | |||
| 575 | } | |||
| 576 | ||||
| 577 | ||||
| 578 | /* Node list management helper macros; list_insert() inserts 'node' | |||
| 579 | * before 'point'. */ | |||
| 580 | #define list_insert(node, point)do { node->ref = point->ref; *node->ref = node; node ->next = point; point->ref = &node->next; } while (0) do { \ | |||
| 581 | node->ref = point->ref; \ | |||
| 582 | *node->ref = node; \ | |||
| 583 | node->next = point; \ | |||
| 584 | point->ref = &node->next; \ | |||
| 585 | } while (0) | |||
| 586 | ||||
| 587 | /* list_remove() removes 'node' from its list. */ | |||
| 588 | #define list_remove(node)do { *node->ref = node->next; node->next->ref = node ->ref; } while (0) do { \ | |||
| 589 | *node->ref = node->next; \ | |||
| 590 | node->next->ref = node->ref; \ | |||
| 591 | } while (0) | |||
| 592 | ||||
| 593 | /* | |||
| 594 | * Memory allocation | |||
| 595 | */ | |||
| 596 | ||||
| 597 | APR_DECLARE(void *)void * apr_palloc(apr_pool_t *pool, apr_size_t size) | |||
| 598 | { | |||
| 599 | apr_memnode_t *active, *node; | |||
| 600 | void *mem = NULL((void*)0); | |||
| 601 | apr_size_t free_index; | |||
| 602 | #if APR_HAS_THREADS1 | |||
| 603 | if (pool->user_mutex) apr_thread_mutex_lock(pool->user_mutex); | |||
| 604 | #endif | |||
| 605 | size = APR_ALIGN_DEFAULT(size)(((size) + ((8) - 1)) & ~((8) - 1)); | |||
| 606 | active = pool->active; | |||
| 607 | ||||
| 608 | /* If the active node has enough bytes left, use it. */ | |||
| 609 | if (size < (apr_size_t)(active->endp - active->first_avail)) { | |||
| 610 | mem = active->first_avail; | |||
| 611 | active->first_avail += size; | |||
| 612 | ||||
| 613 | goto end; | |||
| 614 | } | |||
| 615 | ||||
| 616 | node = active->next; | |||
| 617 | if (size < (apr_size_t)(node->endp - node->first_avail)) { | |||
| 618 | list_remove(node)do { *node->ref = node->next; node->next->ref = node ->ref; } while (0); | |||
| 619 | } | |||
| 620 | else { | |||
| 621 | if ((node = allocator_alloc(pool->allocator, size)) == NULL((void*)0)) { | |||
| 622 | if (pool->abort_fn) | |||
| 623 | pool->abort_fn(APR_ENOMEM12); | |||
| 624 | ||||
| 625 | mem = NULL((void*)0); | |||
| 626 | goto end; | |||
| 627 | } | |||
| 628 | } | |||
| 629 | ||||
| 630 | node->free_index = 0; | |||
| 631 | ||||
| 632 | mem = node->first_avail; | |||
| 633 | node->first_avail += size; | |||
| 634 | ||||
| 635 | list_insert(node, active)do { node->ref = active->ref; *node->ref = node; node ->next = active; active->ref = &node->next; } while (0); | |||
| 636 | ||||
| 637 | pool->active = node; | |||
| 638 | ||||
| 639 | free_index = (APR_ALIGN(active->endp - active->first_avail + 1,(((active->endp - active->first_avail + 1) + (((1 << 12)) - 1)) & ~(((1 << 12)) - 1)) | |||
| 640 | BOUNDARY_SIZE)(((active->endp - active->first_avail + 1) + (((1 << 12)) - 1)) & ~(((1 << 12)) - 1)) - BOUNDARY_SIZE(1 << 12)) >> BOUNDARY_INDEX12; | |||
| 641 | ||||
| 642 | active->free_index = (APR_UINT32_TRUNC_CASTapr_uint32_t)free_index; | |||
| 643 | node = active->next; | |||
| 644 | if (free_index >= node->free_index) | |||
| 645 | goto end; | |||
| 646 | ||||
| 647 | do { | |||
| 648 | node = node->next; | |||
| 649 | } | |||
| 650 | while (free_index < node->free_index); | |||
| 651 | ||||
| 652 | list_remove(active)do { *active->ref = active->next; active->next->ref = active->ref; } while (0); | |||
| 653 | list_insert(active, node)do { active->ref = node->ref; *active->ref = active; active->next = node; node->ref = &active->next; } while (0); | |||
| 654 | ||||
| 655 | end: | |||
| 656 | #if APR_HAS_THREADS1 | |||
| 657 | if (pool->user_mutex) apr_thread_mutex_unlock(pool->user_mutex); | |||
| 658 | #endif | |||
| 659 | return mem; | |||
| 660 | } | |||
| 661 | ||||
| 662 | /* Provide an implementation of apr_pcalloc for backward compatibility | |||
| 663 | * with code built before apr_pcalloc was a macro | |||
| 664 | */ | |||
| 665 | ||||
| 666 | #ifdef apr_pcalloc | |||
| 667 | #undef apr_pcalloc | |||
| 668 | #endif | |||
| 669 | ||||
| 670 | APR_DECLARE(void *)void * apr_pcalloc(apr_pool_t *pool, apr_size_t size); | |||
| 671 | APR_DECLARE(void *)void * apr_pcalloc(apr_pool_t *pool, apr_size_t size) | |||
| 672 | { | |||
| 673 | void *mem; | |||
| 674 | ||||
| 675 | size = APR_ALIGN_DEFAULT(size)(((size) + ((8) - 1)) & ~((8) - 1)); | |||
| 676 | if ((mem = apr_palloc(pool, size)) != NULL((void*)0)) { | |||
| 677 | memset(mem, 0, size); | |||
| 678 | } | |||
| 679 | ||||
| 680 | return mem; | |||
| 681 | } | |||
| 682 | ||||
| 683 | ||||
| 684 | /* | |||
| 685 | * Pool creation/destruction | |||
| 686 | */ | |||
| 687 | ||||
| 688 | APR_DECLARE(void)void apr_pool_clear(apr_pool_t *pool) | |||
| 689 | { | |||
| 690 | apr_memnode_t *active; | |||
| 691 | #if APR_HAS_THREADS1 | |||
| 692 | if (pool->user_mutex) apr_thread_mutex_lock(pool->user_mutex); | |||
| 693 | #endif | |||
| 694 | /* Destroy the subpools. The subpools will detach themselves from | |||
| 695 | * this pool thus this loop is safe and easy. | |||
| 696 | */ | |||
| 697 | while (pool->child) | |||
| 698 | apr_pool_destroy(pool->child); | |||
| 699 | ||||
| 700 | /* Run cleanups */ | |||
| 701 | run_cleanups(&pool->cleanups); | |||
| 702 | pool->cleanups = NULL((void*)0); | |||
| 703 | pool->free_cleanups = NULL((void*)0); | |||
| 704 | ||||
| 705 | /* Free subprocesses */ | |||
| 706 | free_proc_chain(pool->subprocesses); | |||
| 707 | pool->subprocesses = NULL((void*)0); | |||
| 708 | ||||
| 709 | /* Clear the user data. */ | |||
| 710 | pool->user_data = NULL((void*)0); | |||
| 711 | ||||
| 712 | /* Find the node attached to the pool structure, reset it, make | |||
| 713 | * it the active node and free the rest of the nodes. | |||
| 714 | */ | |||
| 715 | active = pool->active = pool->self; | |||
| 716 | active->first_avail = pool->self_first_avail; | |||
| 717 | ||||
| 718 | if (active->next == active) | |||
| 719 | goto end; | |||
| 720 | ||||
| 721 | *active->ref = NULL((void*)0); | |||
| 722 | allocator_free(pool->allocator, active->next); | |||
| 723 | active->next = active; | |||
| 724 | active->ref = &active->next; | |||
| 725 | ||||
| 726 | end: | |||
| 727 | #if APR_HAS_THREADS1 | |||
| 728 | if (pool->user_mutex) apr_thread_mutex_unlock(pool->user_mutex); | |||
| 729 | #endif | |||
| 730 | } | |||
| 731 | ||||
| 732 | #if APR_HAS_THREADS1 | |||
| 733 | APR_DECLARE(void)void apr_pool_mutex_set(apr_pool_t *pool, | |||
| 734 | apr_thread_mutex_t *mutex) | |||
| 735 | { | |||
| 736 | pool->user_mutex = mutex; | |||
| 737 | } | |||
| 738 | #endif | |||
| 739 | ||||
| 740 | APR_DECLARE(void)void apr_pool_destroy(apr_pool_t *pool) | |||
| 741 | { | |||
| 742 | apr_memnode_t *active; | |||
| 743 | apr_allocator_t *allocator; | |||
| 744 | ||||
| 745 | /* Destroy the subpools. The subpools will detach themselve from | |||
| 746 | * this pool thus this loop is safe and easy. | |||
| 747 | */ | |||
| 748 | while (pool->child) | |||
| 749 | apr_pool_destroy(pool->child); | |||
| 750 | ||||
| 751 | /* Run cleanups */ | |||
| 752 | run_cleanups(&pool->cleanups); | |||
| 753 | ||||
| 754 | /* Free subprocesses */ | |||
| 755 | free_proc_chain(pool->subprocesses); | |||
| 756 | ||||
| 757 | /* Remove the pool from the parents child list */ | |||
| 758 | if (pool->parent) { | |||
| 759 | #if APR_HAS_THREADS1 | |||
| 760 | apr_thread_mutex_t *mutex; | |||
| 761 | ||||
| 762 | if ((mutex = apr_allocator_mutex_get(pool->parent->allocator)) != NULL((void*)0)) | |||
| 763 | apr_thread_mutex_lock(mutex); | |||
| 764 | #endif /* APR_HAS_THREADS */ | |||
| 765 | ||||
| 766 | if ((*pool->ref = pool->sibling) != NULL((void*)0)) | |||
| 767 | pool->sibling->ref = pool->ref; | |||
| 768 | ||||
| 769 | #if APR_HAS_THREADS1 | |||
| 770 | if (mutex) | |||
| 771 | apr_thread_mutex_unlock(mutex); | |||
| 772 | #endif /* APR_HAS_THREADS */ | |||
| 773 | } | |||
| 774 | ||||
| 775 | /* Find the block attached to the pool structure. Save a copy of the | |||
| 776 | * allocator pointer, because the pool struct soon will be no more. | |||
| 777 | */ | |||
| 778 | allocator = pool->allocator; | |||
| 779 | active = pool->self; | |||
| 780 | *active->ref = NULL((void*)0); | |||
| 781 | ||||
| 782 | #if APR_HAS_THREADS1 | |||
| 783 | if (apr_allocator_owner_get(allocator) == pool) { | |||
| 784 | /* Make sure to remove the lock, since it is highly likely to | |||
| 785 | * be invalid now. | |||
| 786 | */ | |||
| 787 | apr_allocator_mutex_set(allocator, NULL((void*)0)); | |||
| 788 | } | |||
| 789 | #endif /* APR_HAS_THREADS */ | |||
| 790 | ||||
| 791 | /* Free all the nodes in the pool (including the node holding the | |||
| 792 | * pool struct), by giving them back to the allocator. | |||
| 793 | */ | |||
| 794 | allocator_free(allocator, active); | |||
| 795 | ||||
| 796 | /* If this pool happens to be the owner of the allocator, free | |||
| 797 | * everything in the allocator (that includes the pool struct | |||
| 798 | * and the allocator). Don't worry about destroying the optional mutex | |||
| 799 | * in the allocator, it will have been destroyed by the cleanup function. | |||
| 800 | */ | |||
| 801 | if (apr_allocator_owner_get(allocator) == pool) { | |||
| 802 | apr_allocator_destroy(allocator); | |||
| 803 | } | |||
| 804 | } | |||
| 805 | ||||
| 806 | APR_DECLARE(apr_status_t)apr_status_t apr_pool_create_ex(apr_pool_t **newpool, | |||
| 807 | apr_pool_t *parent, | |||
| 808 | apr_abortfunc_t abort_fn, | |||
| 809 | apr_allocator_t *allocator) | |||
| 810 | { | |||
| 811 | apr_pool_t *pool; | |||
| 812 | apr_memnode_t *node; | |||
| 813 | ||||
| 814 | *newpool = NULL((void*)0); | |||
| 815 | ||||
| 816 | if (!parent) | |||
| 817 | parent = global_pool; | |||
| 818 | ||||
| 819 | if (!abort_fn && parent) | |||
| 820 | abort_fn = parent->abort_fn; | |||
| 821 | ||||
| 822 | if (allocator == NULL((void*)0)) | |||
| 823 | allocator = parent->allocator; | |||
| ||||
| 824 | ||||
| 825 | if ((node = allocator_alloc(allocator, | |||
| 826 | MIN_ALLOC8192 - APR_MEMNODE_T_SIZE(((sizeof(apr_memnode_t)) + ((8) - 1)) & ~((8) - 1)))) == NULL((void*)0)) { | |||
| 827 | if (abort_fn) | |||
| 828 | abort_fn(APR_ENOMEM12); | |||
| 829 | ||||
| 830 | return APR_ENOMEM12; | |||
| 831 | } | |||
| 832 | ||||
| 833 | node->next = node; | |||
| 834 | node->ref = &node->next; | |||
| 835 | ||||
| 836 | pool = (apr_pool_t *)node->first_avail; | |||
| 837 | node->first_avail = pool->self_first_avail = (char *)pool + SIZEOF_POOL_T(((sizeof(apr_pool_t)) + ((8) - 1)) & ~((8) - 1)); | |||
| 838 | ||||
| 839 | pool->allocator = allocator; | |||
| 840 | pool->active = pool->self = node; | |||
| 841 | pool->abort_fn = abort_fn; | |||
| 842 | pool->child = NULL((void*)0); | |||
| 843 | pool->cleanups = NULL((void*)0); | |||
| 844 | pool->free_cleanups = NULL((void*)0); | |||
| 845 | pool->subprocesses = NULL((void*)0); | |||
| 846 | pool->user_data = NULL((void*)0); | |||
| 847 | pool->tag = NULL((void*)0); | |||
| 848 | #if APR_HAS_THREADS1 | |||
| 849 | pool->user_mutex = NULL((void*)0); | |||
| 850 | #endif | |||
| 851 | #ifdef NETWARE | |||
| 852 | pool->owner_proc = (apr_os_proc_t)getnlmhandle(); | |||
| 853 | #endif /* defined(NETWARE) */ | |||
| 854 | ||||
| 855 | if ((pool->parent = parent) != NULL((void*)0)) { | |||
| 856 | #if APR_HAS_THREADS1 | |||
| 857 | apr_thread_mutex_t *mutex; | |||
| 858 | ||||
| 859 | if ((mutex = apr_allocator_mutex_get(parent->allocator)) != NULL((void*)0)) | |||
| 860 | apr_thread_mutex_lock(mutex); | |||
| 861 | #endif /* APR_HAS_THREADS */ | |||
| 862 | ||||
| 863 | if ((pool->sibling = parent->child) != NULL((void*)0)) | |||
| 864 | pool->sibling->ref = &pool->sibling; | |||
| 865 | ||||
| 866 | parent->child = pool; | |||
| 867 | pool->ref = &parent->child; | |||
| 868 | ||||
| 869 | #if APR_HAS_THREADS1 | |||
| 870 | if (mutex) | |||
| 871 | apr_thread_mutex_unlock(mutex); | |||
| 872 | #endif /* APR_HAS_THREADS */ | |||
| 873 | } | |||
| 874 | else { | |||
| 875 | pool->sibling = NULL((void*)0); | |||
| 876 | pool->ref = NULL((void*)0); | |||
| 877 | } | |||
| 878 | ||||
| 879 | *newpool = pool; | |||
| 880 | ||||
| 881 | return APR_SUCCESS0; | |||
| 882 | } | |||
| 883 | ||||
| 884 | ||||
| 885 | /* | |||
| 886 | * "Print" functions | |||
| 887 | */ | |||
| 888 | ||||
| 889 | /* | |||
| 890 | * apr_psprintf is implemented by writing directly into the current | |||
| 891 | * block of the pool, starting right at first_avail. If there's | |||
| 892 | * insufficient room, then a new block is allocated and the earlier | |||
| 893 | * output is copied over. The new block isn't linked into the pool | |||
| 894 | * until all the output is done. | |||
| 895 | * | |||
| 896 | * Note that this is completely safe because nothing else can | |||
| 897 | * allocate in this apr_pool_t while apr_psprintf is running. alarms are | |||
| 898 | * blocked, and the only thing outside of apr_pools.c that's invoked | |||
| 899 | * is apr_vformatter -- which was purposefully written to be | |||
| 900 | * self-contained with no callouts. | |||
| 901 | */ | |||
| 902 | ||||
| 903 | struct psprintf_data { | |||
| 904 | apr_vformatter_buff_t vbuff; | |||
| 905 | apr_memnode_t *node; | |||
| 906 | apr_pool_t *pool; | |||
| 907 | apr_byte_t got_a_new_node; | |||
| 908 | apr_memnode_t *free; | |||
| 909 | }; | |||
| 910 | ||||
| 911 | #define APR_PSPRINTF_MIN_STRINGSIZE32 32 | |||
| 912 | ||||
| 913 | static int psprintf_flush(apr_vformatter_buff_t *vbuff) | |||
| 914 | { | |||
| 915 | struct psprintf_data *ps = (struct psprintf_data *)vbuff; | |||
| 916 | apr_memnode_t *node, *active; | |||
| 917 | apr_size_t cur_len, size; | |||
| 918 | char *strp; | |||
| 919 | apr_pool_t *pool; | |||
| 920 | apr_size_t free_index; | |||
| 921 | ||||
| 922 | pool = ps->pool; | |||
| 923 | active = ps->node; | |||
| 924 | strp = ps->vbuff.curpos; | |||
| 925 | cur_len = strp - active->first_avail; | |||
| 926 | size = cur_len << 1; | |||
| 927 | ||||
| 928 | /* Make sure that we don't try to use a block that has less | |||
| 929 | * than APR_PSPRINTF_MIN_STRINGSIZE bytes left in it. This | |||
| 930 | * also catches the case where size == 0, which would result | |||
| 931 | * in reusing a block that can't even hold the NUL byte. | |||
| 932 | */ | |||
| 933 | if (size < APR_PSPRINTF_MIN_STRINGSIZE32) | |||
| 934 | size = APR_PSPRINTF_MIN_STRINGSIZE32; | |||
| 935 | ||||
| 936 | node = active->next; | |||
| 937 | if (!ps->got_a_new_node | |||
| 938 | && size < (apr_size_t)(node->endp - node->first_avail)) { | |||
| 939 | ||||
| 940 | list_remove(node)do { *node->ref = node->next; node->next->ref = node ->ref; } while (0); | |||
| 941 | list_insert(node, active)do { node->ref = active->ref; *node->ref = node; node ->next = active; active->ref = &node->next; } while (0); | |||
| 942 | ||||
| 943 | node->free_index = 0; | |||
| 944 | ||||
| 945 | pool->active = node; | |||
| 946 | ||||
| 947 | free_index = (APR_ALIGN(active->endp - active->first_avail + 1,(((active->endp - active->first_avail + 1) + (((1 << 12)) - 1)) & ~(((1 << 12)) - 1)) | |||
| 948 | BOUNDARY_SIZE)(((active->endp - active->first_avail + 1) + (((1 << 12)) - 1)) & ~(((1 << 12)) - 1)) - BOUNDARY_SIZE(1 << 12)) >> BOUNDARY_INDEX12; | |||
| 949 | ||||
| 950 | active->free_index = (APR_UINT32_TRUNC_CASTapr_uint32_t)free_index; | |||
| 951 | node = active->next; | |||
| 952 | if (free_index < node->free_index) { | |||
| 953 | do { | |||
| 954 | node = node->next; | |||
| 955 | } | |||
| 956 | while (free_index < node->free_index); | |||
| 957 | ||||
| 958 | list_remove(active)do { *active->ref = active->next; active->next->ref = active->ref; } while (0); | |||
| 959 | list_insert(active, node)do { active->ref = node->ref; *active->ref = active; active->next = node; node->ref = &active->next; } while (0); | |||
| 960 | } | |||
| 961 | ||||
| 962 | node = pool->active; | |||
| 963 | } | |||
| 964 | else { | |||
| 965 | if ((node = allocator_alloc(pool->allocator, size)) == NULL((void*)0)) | |||
| 966 | return -1; | |||
| 967 | ||||
| 968 | if (ps->got_a_new_node) { | |||
| 969 | active->next = ps->free; | |||
| 970 | ps->free = active; | |||
| 971 | } | |||
| 972 | ||||
| 973 | ps->got_a_new_node = 1; | |||
| 974 | } | |||
| 975 | ||||
| 976 | memcpy(node->first_avail, active->first_avail, cur_len); | |||
| 977 | ||||
| 978 | ps->node = node; | |||
| 979 | ps->vbuff.curpos = node->first_avail + cur_len; | |||
| 980 | ps->vbuff.endpos = node->endp - 1; /* Save a byte for NUL terminator */ | |||
| 981 | ||||
| 982 | return 0; | |||
| 983 | } | |||
| 984 | ||||
| 985 | APR_DECLARE(char *)char * apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap) | |||
| 986 | { | |||
| 987 | struct psprintf_data ps; | |||
| 988 | char *strp; | |||
| 989 | apr_size_t size; | |||
| 990 | apr_memnode_t *active, *node; | |||
| 991 | apr_size_t free_index; | |||
| 992 | ||||
| 993 | #if APR_HAS_THREADS1 | |||
| 994 | if (pool->user_mutex) apr_thread_mutex_lock(pool->user_mutex); | |||
| 995 | #endif | |||
| 996 | ||||
| 997 | ps.node = active = pool->active; | |||
| 998 | ps.pool = pool; | |||
| 999 | ps.vbuff.curpos = ps.node->first_avail; | |||
| 1000 | ||||
| 1001 | /* Save a byte for the NUL terminator */ | |||
| 1002 | ps.vbuff.endpos = ps.node->endp - 1; | |||
| 1003 | ps.got_a_new_node = 0; | |||
| 1004 | ps.free = NULL((void*)0); | |||
| 1005 | ||||
| 1006 | /* Make sure that the first node passed to apr_vformatter has at least | |||
| 1007 | * room to hold the NUL terminator. | |||
| 1008 | */ | |||
| 1009 | if (ps.node->first_avail == ps.node->endp) { | |||
| 1010 | if (psprintf_flush(&ps.vbuff) == -1) { | |||
| 1011 | if (pool->abort_fn) { | |||
| 1012 | pool->abort_fn(APR_ENOMEM12); | |||
| 1013 | } | |||
| 1014 | ||||
| 1015 | strp = NULL((void*)0); | |||
| 1016 | goto end; | |||
| 1017 | } | |||
| 1018 | } | |||
| 1019 | ||||
| 1020 | if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) { | |||
| 1021 | if (pool->abort_fn) | |||
| 1022 | pool->abort_fn(APR_ENOMEM12); | |||
| 1023 | ||||
| 1024 | strp = NULL((void*)0); | |||
| 1025 | goto end; | |||
| 1026 | } | |||
| 1027 | ||||
| 1028 | strp = ps.vbuff.curpos; | |||
| 1029 | *strp++ = '\0'; | |||
| 1030 | ||||
| 1031 | size = strp - ps.node->first_avail; | |||
| 1032 | size = APR_ALIGN_DEFAULT(size)(((size) + ((8) - 1)) & ~((8) - 1)); | |||
| 1033 | strp = ps.node->first_avail; | |||
| 1034 | ps.node->first_avail += size; | |||
| 1035 | ||||
| 1036 | if (ps.free) | |||
| 1037 | allocator_free(pool->allocator, ps.free); | |||
| 1038 | ||||
| 1039 | /* | |||
| 1040 | * Link the node in if it's a new one | |||
| 1041 | */ | |||
| 1042 | if (!ps.got_a_new_node) | |||
| 1043 | goto end; | |||
| 1044 | ||||
| 1045 | active = pool->active; | |||
| 1046 | node = ps.node; | |||
| 1047 | ||||
| 1048 | node->free_index = 0; | |||
| 1049 | ||||
| 1050 | list_insert(node, active)do { node->ref = active->ref; *node->ref = node; node ->next = active; active->ref = &node->next; } while (0); | |||
| 1051 | ||||
| 1052 | pool->active = node; | |||
| 1053 | ||||
| 1054 | free_index = (APR_ALIGN(active->endp - active->first_avail + 1,(((active->endp - active->first_avail + 1) + (((1 << 12)) - 1)) & ~(((1 << 12)) - 1)) | |||
| 1055 | BOUNDARY_SIZE)(((active->endp - active->first_avail + 1) + (((1 << 12)) - 1)) & ~(((1 << 12)) - 1)) - BOUNDARY_SIZE(1 << 12)) >> BOUNDARY_INDEX12; | |||
| 1056 | ||||
| 1057 | active->free_index = (APR_UINT32_TRUNC_CASTapr_uint32_t)free_index; | |||
| 1058 | node = active->next; | |||
| 1059 | ||||
| 1060 | if (free_index >= node->free_index) | |||
| 1061 | goto end; | |||
| 1062 | ||||
| 1063 | do { | |||
| 1064 | node = node->next; | |||
| 1065 | } | |||
| 1066 | while (free_index < node->free_index); | |||
| 1067 | ||||
| 1068 | list_remove(active)do { *active->ref = active->next; active->next->ref = active->ref; } while (0); | |||
| 1069 | list_insert(active, node)do { active->ref = node->ref; *active->ref = active; active->next = node; node->ref = &active->next; } while (0); | |||
| 1070 | ||||
| 1071 | end: | |||
| 1072 | ||||
| 1073 | #if APR_HAS_THREADS1 | |||
| 1074 | if (pool->user_mutex) apr_thread_mutex_unlock(pool->user_mutex); | |||
| 1075 | #endif | |||
| 1076 | ||||
| 1077 | return strp; | |||
| 1078 | } | |||
| 1079 | ||||
| 1080 | ||||
| 1081 | #else /* APR_POOL_DEBUG */ | |||
| 1082 | /* | |||
| 1083 | * Debug helper functions | |||
| 1084 | */ | |||
| 1085 | ||||
| 1086 | ||||
| 1087 | /* | |||
| 1088 | * Walk the pool tree rooted at pool, depth first. When fn returns | |||
| 1089 | * anything other than 0, abort the traversal and return the value | |||
| 1090 | * returned by fn. | |||
| 1091 | */ | |||
| 1092 | static int apr_pool_walk_tree(apr_pool_t *pool, | |||
| 1093 | int (*fn)(apr_pool_t *pool, void *data), | |||
| 1094 | void *data) | |||
| 1095 | { | |||
| 1096 | int rv; | |||
| 1097 | apr_pool_t *child; | |||
| 1098 | ||||
| 1099 | rv = fn(pool, data); | |||
| 1100 | if (rv) | |||
| 1101 | return rv; | |||
| 1102 | ||||
| 1103 | #if APR_HAS_THREADS1 | |||
| 1104 | if (pool->mutex) { | |||
| 1105 | apr_thread_mutex_lock(pool->mutex); | |||
| 1106 | } | |||
| 1107 | #endif /* APR_HAS_THREADS */ | |||
| 1108 | ||||
| 1109 | child = pool->child; | |||
| 1110 | while (child) { | |||
| 1111 | rv = apr_pool_walk_tree(child, fn, data); | |||
| 1112 | if (rv) | |||
| 1113 | break; | |||
| 1114 | ||||
| 1115 | child = child->sibling; | |||
| 1116 | } | |||
| 1117 | ||||
| 1118 | #if APR_HAS_THREADS1 | |||
| 1119 | if (pool->mutex) { | |||
| 1120 | apr_thread_mutex_unlock(pool->mutex); | |||
| 1121 | } | |||
| 1122 | #endif /* APR_HAS_THREADS */ | |||
| 1123 | ||||
| 1124 | return rv; | |||
| 1125 | } | |||
| 1126 | ||||
| 1127 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE_ALL(0x02 | 0x10)) | |||
| 1128 | static void apr_pool_log_event(apr_pool_t *pool, const char *event, | |||
| 1129 | const char *file_line, int deref) | |||
| 1130 | { | |||
| 1131 | if (file_stderr) { | |||
| 1132 | if (deref) { | |||
| 1133 | apr_file_printf(file_stderr, | |||
| 1134 | "POOL DEBUG: " | |||
| 1135 | "[%lu" | |||
| 1136 | #if APR_HAS_THREADS1 | |||
| 1137 | "/%lu" | |||
| 1138 | #endif /* APR_HAS_THREADS */ | |||
| 1139 | "] " | |||
| 1140 | "%7s " | |||
| 1141 | "(%10lu/%10lu/%10lu) " | |||
| 1142 | "0x%08X \"%s\" " | |||
| 1143 | "<%s> " | |||
| 1144 | "(%u/%u/%u) " | |||
| 1145 | "\n", | |||
| 1146 | (unsigned long)getpid(), | |||
| 1147 | #if APR_HAS_THREADS1 | |||
| 1148 | (unsigned long)apr_os_thread_current(), | |||
| 1149 | #endif /* APR_HAS_THREADS */ | |||
| 1150 | event, | |||
| 1151 | (unsigned long)apr_pool_num_bytes(pool, 0), | |||
| 1152 | (unsigned long)apr_pool_num_bytes(pool, 1), | |||
| 1153 | (unsigned long)apr_pool_num_bytes(global_pool, 1), | |||
| 1154 | (unsigned int)pool, pool->tag, | |||
| 1155 | file_line, | |||
| 1156 | pool->stat_alloc, pool->stat_total_alloc, pool->stat_clear); | |||
| 1157 | } | |||
| 1158 | else { | |||
| 1159 | apr_file_printf(file_stderr, | |||
| 1160 | "POOL DEBUG: " | |||
| 1161 | "[%lu" | |||
| 1162 | #if APR_HAS_THREADS1 | |||
| 1163 | "/%lu" | |||
| 1164 | #endif /* APR_HAS_THREADS */ | |||
| 1165 | "] " | |||
| 1166 | "%7s " | |||
| 1167 | " " | |||
| 1168 | "0x%08X " | |||
| 1169 | "<%s> " | |||
| 1170 | "\n", | |||
| 1171 | (unsigned long)getpid(), | |||
| 1172 | #if APR_HAS_THREADS1 | |||
| 1173 | (unsigned long)apr_os_thread_current(), | |||
| 1174 | #endif /* APR_HAS_THREADS */ | |||
| 1175 | event, | |||
| 1176 | (unsigned int)pool, | |||
| 1177 | file_line); | |||
| 1178 | } | |||
| 1179 | } | |||
| 1180 | } | |||
| 1181 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ | |||
| 1182 | ||||
| 1183 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_LIFETIME0x04) | |||
| 1184 | static int pool_is_child_of(apr_pool_t *parent, void *data) | |||
| 1185 | { | |||
| 1186 | apr_pool_t *pool = (apr_pool_t *)data; | |||
| 1187 | ||||
| 1188 | return (pool == parent); | |||
| 1189 | } | |||
| 1190 | ||||
| 1191 | static int apr_pool_is_child_of(apr_pool_t *pool, apr_pool_t *parent) | |||
| 1192 | { | |||
| 1193 | if (parent == NULL((void*)0)) | |||
| 1194 | return 0; | |||
| 1195 | ||||
| 1196 | return apr_pool_walk_tree(parent, pool_is_child_of, pool); | |||
| 1197 | } | |||
| 1198 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */ | |||
| 1199 | ||||
| 1200 | static void apr_pool_check_integrity(apr_pool_t *pool) | |||
| 1201 | { | |||
| 1202 | /* Rule of thumb: use of the global pool is always | |||
| 1203 | * ok, since the only user is apr_pools.c. Unless | |||
| 1204 | * people have searched for the top level parent and | |||
| 1205 | * started to use that... | |||
| 1206 | */ | |||
| 1207 | if (pool == global_pool || global_pool == NULL((void*)0)) | |||
| 1208 | return; | |||
| 1209 | ||||
| 1210 | /* Lifetime | |||
| 1211 | * This basically checks to see if the pool being used is still | |||
| 1212 | * a relative to the global pool. If not it was previously | |||
| 1213 | * destroyed, in which case we abort(). | |||
| 1214 | */ | |||
| 1215 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_LIFETIME0x04) | |||
| 1216 | if (!apr_pool_is_child_of(pool, global_pool)) { | |||
| 1217 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE_ALL(0x02 | 0x10)) | |||
| 1218 | apr_pool_log_event(pool, "LIFE", | |||
| 1219 | __FILE__"memory/unix/apr_pools.c" ":apr_pool_integrity check", 0); | |||
| 1220 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ | |||
| 1221 | abort(); | |||
| 1222 | } | |||
| 1223 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */ | |||
| 1224 | ||||
| 1225 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_OWNER0x08) | |||
| 1226 | #if APR_HAS_THREADS1 | |||
| 1227 | if (!apr_os_thread_equal(pool->owner, apr_os_thread_current())) { | |||
| 1228 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE_ALL(0x02 | 0x10)) | |||
| 1229 | apr_pool_log_event(pool, "THREAD", | |||
| 1230 | __FILE__"memory/unix/apr_pools.c" ":apr_pool_integrity check", 0); | |||
| 1231 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ | |||
| 1232 | abort(); | |||
| 1233 | } | |||
| 1234 | #endif /* APR_HAS_THREADS */ | |||
| 1235 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) */ | |||
| 1236 | } | |||
| 1237 | ||||
| 1238 | ||||
| 1239 | /* | |||
| 1240 | * Initialization (debug) | |||
| 1241 | */ | |||
| 1242 | ||||
| 1243 | APR_DECLARE(apr_status_t)apr_status_t apr_pool_initialize(void) | |||
| 1244 | { | |||
| 1245 | apr_status_t rv; | |||
| 1246 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE_ALL(0x02 | 0x10)) | |||
| 1247 | char *logpath; | |||
| 1248 | #endif | |||
| 1249 | ||||
| 1250 | if (apr_pools_initialized++) | |||
| 1251 | return APR_SUCCESS0; | |||
| 1252 | ||||
| 1253 | /* Since the debug code works a bit differently then the | |||
| 1254 | * regular pools code, we ask for a lock here. The regular | |||
| 1255 | * pools code has got this lock embedded in the global | |||
| 1256 | * allocator, a concept unknown to debug mode. | |||
| 1257 | */ | |||
| 1258 | if ((rv = apr_pool_create_ex(&global_pool, NULL((void*)0), NULL((void*)0), | |||
| 1259 | NULL((void*)0))) != APR_SUCCESS0) { | |||
| 1260 | return rv; | |||
| 1261 | } | |||
| 1262 | ||||
| 1263 | apr_pool_tag(global_pool, "APR global pool"); | |||
| 1264 | ||||
| 1265 | apr_pools_initialized = 1; | |||
| 1266 | ||||
| 1267 | /* This has to happen here because mutexes might be backed by | |||
| 1268 | * atomics. It used to be snug and safe in apr_initialize(). | |||
| 1269 | */ | |||
| 1270 | if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS0) { | |||
| 1271 | return rv; | |||
| 1272 | } | |||
| 1273 | ||||
| 1274 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE_ALL(0x02 | 0x10)) | |||
| 1275 | rv = apr_env_get(&logpath, "APR_POOL_DEBUG_LOG", global_pool); | |||
| 1276 | ||||
| 1277 | if (rv == APR_SUCCESS0) { | |||
| 1278 | apr_file_open(&file_stderr, logpath, APR_APPEND0x00008|APR_WRITE0x00002|APR_CREATE0x00004, | |||
| 1279 | APR_OS_DEFAULT0x0FFF, global_pool); | |||
| 1280 | } | |||
| 1281 | else { | |||
| 1282 | apr_file_open_stderr(&file_stderr, global_pool); | |||
| 1283 | } | |||
| 1284 | ||||
| 1285 | if (file_stderr) { | |||
| 1286 | apr_file_printf(file_stderr, | |||
| 1287 | "POOL DEBUG: [PID" | |||
| 1288 | #if APR_HAS_THREADS1 | |||
| 1289 | "/TID" | |||
| 1290 | #endif /* APR_HAS_THREADS */ | |||
| 1291 | "] ACTION (SIZE /POOL SIZE /TOTAL SIZE) " | |||
| 1292 | "POOL \"TAG\" <__FILE__:__LINE__> (ALLOCS/TOTAL ALLOCS/CLEARS)\n"); | |||
| 1293 | ||||
| 1294 | apr_pool_log_event(global_pool, "GLOBAL", __FILE__"memory/unix/apr_pools.c" ":apr_pool_initialize", 0); | |||
| 1295 | } | |||
| 1296 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ | |||
| 1297 | ||||
| 1298 | return APR_SUCCESS0; | |||
| 1299 | } | |||
| 1300 | ||||
| 1301 | APR_DECLARE(void)void apr_pool_terminate(void) | |||
| 1302 | { | |||
| 1303 | if (!apr_pools_initialized) | |||
| 1304 | return; | |||
| 1305 | ||||
| 1306 | apr_pools_initialized = 0; | |||
| 1307 | ||||
| 1308 | apr_pool_destroy(global_pool); /* This will also destroy the mutex */ | |||
| 1309 | global_pool = NULL((void*)0); | |||
| 1310 | ||||
| 1311 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE_ALL(0x02 | 0x10)) | |||
| 1312 | file_stderr = NULL((void*)0); | |||
| 1313 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ | |||
| 1314 | } | |||
| 1315 | ||||
| 1316 | ||||
| 1317 | /* | |||
| 1318 | * Memory allocation (debug) | |||
| 1319 | */ | |||
| 1320 | ||||
| 1321 | static void *pool_alloc(apr_pool_t *pool, apr_size_t size) | |||
| 1322 | { | |||
| 1323 | debug_node_t *node; | |||
| 1324 | void *mem; | |||
| 1325 | ||||
| 1326 | if ((mem = malloc(size)) == NULL((void*)0)) { | |||
| 1327 | if (pool->abort_fn) | |||
| 1328 | pool->abort_fn(APR_ENOMEM12); | |||
| 1329 | ||||
| 1330 | return NULL((void*)0); | |||
| 1331 | } | |||
| 1332 | ||||
| 1333 | node = pool->nodes; | |||
| 1334 | if (node == NULL((void*)0) || node->index == 64) { | |||
| 1335 | if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL((void*)0)) { | |||
| 1336 | if (pool->abort_fn) | |||
| 1337 | pool->abort_fn(APR_ENOMEM12); | |||
| 1338 | ||||
| 1339 | return NULL((void*)0); | |||
| 1340 | } | |||
| 1341 | ||||
| 1342 | memset(node, 0, SIZEOF_DEBUG_NODE_T); | |||
| 1343 | ||||
| 1344 | node->next = pool->nodes; | |||
| 1345 | pool->nodes = node; | |||
| 1346 | node->index = 0; | |||
| 1347 | } | |||
| 1348 | ||||
| 1349 | node->beginp[node->index] = mem; | |||
| 1350 | node->endp[node->index] = (char *)mem + size; | |||
| 1351 | node->index++; | |||
| 1352 | ||||
| 1353 | pool->stat_alloc++; | |||
| 1354 | pool->stat_total_alloc++; | |||
| 1355 | ||||
| 1356 | return mem; | |||
| 1357 | } | |||
| 1358 | ||||
| 1359 | APR_DECLARE(void *)void * apr_palloc_debug(apr_pool_t *pool, apr_size_t size, | |||
| 1360 | const char *file_line) | |||
| 1361 | { | |||
| 1362 | void *mem; | |||
| 1363 | ||||
| 1364 | apr_pool_check_integrity(pool); | |||
| 1365 | ||||
| 1366 | mem = pool_alloc(pool, size); | |||
| 1367 | ||||
| 1368 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE_ALLOC0x10) | |||
| 1369 | apr_pool_log_event(pool, "PALLOC", file_line, 1); | |||
| 1370 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */ | |||
| 1371 | ||||
| 1372 | return mem; | |||
| 1373 | } | |||
| 1374 | ||||
| 1375 | APR_DECLARE(void *)void * apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size, | |||
| 1376 | const char *file_line) | |||
| 1377 | { | |||
| 1378 | void *mem; | |||
| 1379 | ||||
| 1380 | apr_pool_check_integrity(pool); | |||
| 1381 | ||||
| 1382 | mem = pool_alloc(pool, size); | |||
| 1383 | memset(mem, 0, size); | |||
| 1384 | ||||
| 1385 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE_ALLOC0x10) | |||
| 1386 | apr_pool_log_event(pool, "PCALLOC", file_line, 1); | |||
| 1387 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */ | |||
| 1388 | ||||
| 1389 | return mem; | |||
| 1390 | } | |||
| 1391 | ||||
| 1392 | ||||
| 1393 | /* | |||
| 1394 | * Pool creation/destruction (debug) | |||
| 1395 | */ | |||
| 1396 | ||||
| 1397 | #define POOL_POISON_BYTE 'A' | |||
| 1398 | ||||
| 1399 | static void pool_clear_debug(apr_pool_t *pool, const char *file_line) | |||
| 1400 | { | |||
| 1401 | debug_node_t *node; | |||
| 1402 | apr_uint32_t index; | |||
| 1403 | ||||
| 1404 | /* Destroy the subpools. The subpools will detach themselves from | |||
| 1405 | * this pool thus this loop is safe and easy. | |||
| 1406 | */ | |||
| 1407 | while (pool->child) | |||
| 1408 | pool_destroy_debug(pool->child, file_line); | |||
| 1409 | ||||
| 1410 | /* Run cleanups */ | |||
| 1411 | run_cleanups(&pool->cleanups); | |||
| 1412 | pool->free_cleanups = NULL((void*)0); | |||
| 1413 | pool->cleanups = NULL((void*)0); | |||
| 1414 | ||||
| 1415 | /* If new child pools showed up, this is a reason to raise a flag */ | |||
| 1416 | if (pool->child) | |||
| 1417 | abort(); | |||
| 1418 | ||||
| 1419 | /* Free subprocesses */ | |||
| 1420 | free_proc_chain(pool->subprocesses); | |||
| 1421 | pool->subprocesses = NULL((void*)0); | |||
| 1422 | ||||
| 1423 | /* Clear the user data. */ | |||
| 1424 | pool->user_data = NULL((void*)0); | |||
| 1425 | ||||
| 1426 | /* Free the blocks, scribbling over them first to help highlight | |||
| 1427 | * use-after-free issues. */ | |||
| 1428 | while ((node = pool->nodes) != NULL((void*)0)) { | |||
| 1429 | pool->nodes = node->next; | |||
| 1430 | ||||
| 1431 | for (index = 0; index < node->index; index++) { | |||
| 1432 | memset(node->beginp[index], POOL_POISON_BYTE, | |||
| 1433 | node->endp[index] - node->beginp[index]); | |||
| 1434 | free(node->beginp[index]); | |||
| 1435 | } | |||
| 1436 | ||||
| 1437 | memset(node, POOL_POISON_BYTE, SIZEOF_DEBUG_NODE_T); | |||
| 1438 | free(node); | |||
| 1439 | } | |||
| 1440 | ||||
| 1441 | pool->stat_alloc = 0; | |||
| 1442 | pool->stat_clear++; | |||
| 1443 | } | |||
| 1444 | ||||
| 1445 | APR_DECLARE(void)void apr_pool_clear_debug(apr_pool_t *pool, | |||
| 1446 | const char *file_line) | |||
| 1447 | { | |||
| 1448 | #if APR_HAS_THREADS1 | |||
| 1449 | apr_thread_mutex_t *mutex = NULL((void*)0); | |||
| 1450 | #endif | |||
| 1451 | ||||
| 1452 | apr_pool_check_integrity(pool); | |||
| 1453 | ||||
| 1454 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE0x02) | |||
| 1455 | apr_pool_log_event(pool, "CLEAR", file_line, 1); | |||
| 1456 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ | |||
| 1457 | ||||
| 1458 | #if APR_HAS_THREADS1 | |||
| 1459 | if (pool->parent != NULL((void*)0)) | |||
| 1460 | mutex = pool->parent->mutex; | |||
| 1461 | ||||
| 1462 | /* Lock the parent mutex before clearing so that if we have our | |||
| 1463 | * own mutex it won't be accessed by apr_pool_walk_tree after | |||
| 1464 | * it has been destroyed. | |||
| 1465 | */ | |||
| 1466 | if (mutex != NULL((void*)0) && mutex != pool->mutex) { | |||
| 1467 | apr_thread_mutex_lock(mutex); | |||
| 1468 | } | |||
| 1469 | #endif | |||
| 1470 | ||||
| 1471 | pool_clear_debug(pool, file_line); | |||
| 1472 | ||||
| 1473 | #if APR_HAS_THREADS1 | |||
| 1474 | /* If we had our own mutex, it will have been destroyed by | |||
| 1475 | * the registered cleanups. Recreate the mutex. Unlock | |||
| 1476 | * the mutex we obtained above. | |||
| 1477 | */ | |||
| 1478 | if (mutex != pool->mutex) { | |||
| 1479 | (void)apr_thread_mutex_create(&pool->mutex, | |||
| 1480 | APR_THREAD_MUTEX_NESTED0x1, pool); | |||
| 1481 | ||||
| 1482 | if (mutex != NULL((void*)0)) | |||
| 1483 | (void)apr_thread_mutex_unlock(mutex); | |||
| 1484 | } | |||
| 1485 | #endif /* APR_HAS_THREADS */ | |||
| 1486 | } | |||
| 1487 | ||||
| 1488 | static void pool_destroy_debug(apr_pool_t *pool, const char *file_line) | |||
| 1489 | { | |||
| 1490 | apr_pool_check_integrity(pool); | |||
| 1491 | ||||
| 1492 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE0x02) | |||
| 1493 | apr_pool_log_event(pool, "DESTROY", file_line, 1); | |||
| 1494 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ | |||
| 1495 | ||||
| 1496 | pool_clear_debug(pool, file_line); | |||
| 1497 | ||||
| 1498 | /* Remove the pool from the parents child list */ | |||
| 1499 | if (pool->parent) { | |||
| 1500 | #if APR_HAS_THREADS1 | |||
| 1501 | apr_thread_mutex_t *mutex; | |||
| 1502 | ||||
| 1503 | if ((mutex = pool->parent->mutex) != NULL((void*)0)) | |||
| 1504 | apr_thread_mutex_lock(mutex); | |||
| 1505 | #endif /* APR_HAS_THREADS */ | |||
| 1506 | ||||
| 1507 | if ((*pool->ref = pool->sibling) != NULL((void*)0)) | |||
| 1508 | pool->sibling->ref = pool->ref; | |||
| 1509 | ||||
| 1510 | #if APR_HAS_THREADS1 | |||
| 1511 | if (mutex) | |||
| 1512 | apr_thread_mutex_unlock(mutex); | |||
| 1513 | #endif /* APR_HAS_THREADS */ | |||
| 1514 | } | |||
| 1515 | ||||
| 1516 | if (pool->allocator != NULL((void*)0) | |||
| 1517 | && apr_allocator_owner_get(pool->allocator) == pool) { | |||
| 1518 | apr_allocator_destroy(pool->allocator); | |||
| 1519 | } | |||
| 1520 | ||||
| 1521 | /* Free the pool itself */ | |||
| 1522 | free(pool); | |||
| 1523 | } | |||
| 1524 | ||||
| 1525 | APR_DECLARE(void)void apr_pool_destroy_debug(apr_pool_t *pool, | |||
| 1526 | const char *file_line) | |||
| 1527 | { | |||
| 1528 | if (pool->joined) { | |||
| 1529 | /* Joined pools must not be explicitly destroyed; the caller | |||
| 1530 | * has broken the guarantee. */ | |||
| 1531 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE_ALL(0x02 | 0x10)) | |||
| 1532 | apr_pool_log_event(pool, "LIFE", | |||
| 1533 | __FILE__"memory/unix/apr_pools.c" ":apr_pool_destroy abort on joined", 0); | |||
| 1534 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ | |||
| 1535 | ||||
| 1536 | abort(); | |||
| 1537 | } | |||
| 1538 | pool_destroy_debug(pool, file_line); | |||
| 1539 | } | |||
| 1540 | ||||
| 1541 | APR_DECLARE(apr_status_t)apr_status_t apr_pool_create_ex_debug(apr_pool_t **newpool, | |||
| 1542 | apr_pool_t *parent, | |||
| 1543 | apr_abortfunc_t abort_fn, | |||
| 1544 | apr_allocator_t *allocator, | |||
| 1545 | const char *file_line) | |||
| 1546 | { | |||
| 1547 | apr_pool_t *pool; | |||
| 1548 | ||||
| 1549 | *newpool = NULL((void*)0); | |||
| 1550 | ||||
| 1551 | if (!parent) { | |||
| 1552 | parent = global_pool; | |||
| 1553 | } | |||
| 1554 | else { | |||
| 1555 | apr_pool_check_integrity(parent); | |||
| 1556 | ||||
| 1557 | if (!allocator) | |||
| 1558 | allocator = parent->allocator; | |||
| 1559 | } | |||
| 1560 | ||||
| 1561 | if (!abort_fn && parent) | |||
| 1562 | abort_fn = parent->abort_fn; | |||
| 1563 | ||||
| 1564 | if ((pool = malloc(SIZEOF_POOL_T(((sizeof(apr_pool_t)) + ((8) - 1)) & ~((8) - 1)))) == NULL((void*)0)) { | |||
| 1565 | if (abort_fn) | |||
| 1566 | abort_fn(APR_ENOMEM12); | |||
| 1567 | ||||
| 1568 | return APR_ENOMEM12; | |||
| 1569 | } | |||
| 1570 | ||||
| 1571 | memset(pool, 0, SIZEOF_POOL_T(((sizeof(apr_pool_t)) + ((8) - 1)) & ~((8) - 1))); | |||
| 1572 | ||||
| 1573 | pool->allocator = allocator; | |||
| 1574 | pool->abort_fn = abort_fn; | |||
| 1575 | pool->tag = file_line; | |||
| 1576 | pool->file_line = file_line; | |||
| 1577 | ||||
| 1578 | if ((pool->parent = parent) != NULL((void*)0)) { | |||
| 1579 | #if APR_HAS_THREADS1 | |||
| 1580 | if (parent->mutex) | |||
| 1581 | apr_thread_mutex_lock(parent->mutex); | |||
| 1582 | #endif /* APR_HAS_THREADS */ | |||
| 1583 | if ((pool->sibling = parent->child) != NULL((void*)0)) | |||
| 1584 | pool->sibling->ref = &pool->sibling; | |||
| 1585 | ||||
| 1586 | parent->child = pool; | |||
| 1587 | pool->ref = &parent->child; | |||
| 1588 | ||||
| 1589 | #if APR_HAS_THREADS1 | |||
| 1590 | if (parent->mutex) | |||
| 1591 | apr_thread_mutex_unlock(parent->mutex); | |||
| 1592 | #endif /* APR_HAS_THREADS */ | |||
| 1593 | } | |||
| 1594 | else { | |||
| 1595 | pool->sibling = NULL((void*)0); | |||
| 1596 | pool->ref = NULL((void*)0); | |||
| 1597 | } | |||
| 1598 | ||||
| 1599 | #if APR_HAS_THREADS1 | |||
| 1600 | pool->owner = apr_os_thread_current(); | |||
| 1601 | #endif /* APR_HAS_THREADS */ | |||
| 1602 | #ifdef NETWARE | |||
| 1603 | pool->owner_proc = (apr_os_proc_t)getnlmhandle(); | |||
| 1604 | #endif /* defined(NETWARE) */ | |||
| 1605 | ||||
| 1606 | ||||
| 1607 | if (parent == NULL((void*)0) || parent->allocator != allocator) { | |||
| 1608 | #if APR_HAS_THREADS1 | |||
| 1609 | apr_status_t rv; | |||
| 1610 | ||||
| 1611 | /* No matter what the creation flags say, always create | |||
| 1612 | * a lock. Without it integrity_check and apr_pool_num_bytes | |||
| 1613 | * blow up (because they traverse pools child lists that | |||
| 1614 | * possibly belong to another thread, in combination with | |||
| 1615 | * the pool having no lock). However, this might actually | |||
| 1616 | * hide problems like creating a child pool of a pool | |||
| 1617 | * belonging to another thread. | |||
| 1618 | */ | |||
| 1619 | if ((rv = apr_thread_mutex_create(&pool->mutex, | |||
| 1620 | APR_THREAD_MUTEX_NESTED0x1, pool)) != APR_SUCCESS0) { | |||
| 1621 | free(pool); | |||
| 1622 | return rv; | |||
| 1623 | } | |||
| 1624 | #endif /* APR_HAS_THREADS */ | |||
| 1625 | } | |||
| 1626 | else { | |||
| 1627 | #if APR_HAS_THREADS1 | |||
| 1628 | if (parent) | |||
| 1629 | pool->mutex = parent->mutex; | |||
| 1630 | #endif /* APR_HAS_THREADS */ | |||
| 1631 | } | |||
| 1632 | ||||
| 1633 | *newpool = pool; | |||
| 1634 | ||||
| 1635 | #if (APR_POOL_DEBUG0 & APR_POOL_DEBUG_VERBOSE0x02) | |||
| 1636 | apr_pool_log_event(pool, "CREATE", file_line, 1); | |||
| 1637 | #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ | |||
| 1638 | ||||
| 1639 | return APR_SUCCESS0; | |||
| 1640 | } | |||
| 1641 | ||||
| 1642 | ||||
| 1643 | /* | |||
| 1644 | * "Print" functions (debug) | |||
| 1645 | */ | |||
| 1646 | ||||
| 1647 | struct psprintf_data { | |||
| 1648 | apr_vformatter_buff_t vbuff; | |||
| 1649 | char *mem; | |||
| 1650 | apr_size_t size; | |||
| 1651 | }; | |||
| 1652 | ||||
| 1653 | static int psprintf_flush(apr_vformatter_buff_t *vbuff) | |||
| 1654 | { | |||
| 1655 | struct psprintf_data *ps = (struct psprintf_data *)vbuff; | |||
| 1656 | apr_size_t size; | |||
| 1657 | ||||
| 1658 | size = ps->vbuff.curpos - ps->mem; | |||
| 1659 | ||||
| 1660 | ps->size <<= 1; | |||
| 1661 | if ((ps->mem = realloc(ps->mem, ps->size)) == NULL((void*)0)) | |||
| 1662 | return -1; | |||
| 1663 | ||||
| 1664 | ps->vbuff.curpos = ps->mem + size; | |||
| 1665 | ps->vbuff.endpos = ps->mem + ps->size - 1; | |||
| 1666 | ||||
| 1667 | return 0; | |||
| 1668 | } | |||
| 1669 | ||||
| 1670 | APR_DECLARE(char *)char * apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap) | |||
| 1671 | { | |||
| 1672 | struct psprintf_data ps; | |||
| 1673 | debug_node_t *node; | |||
| 1674 | ||||
| 1675 | apr_pool_check_integrity(pool); | |||
| 1676 | ||||
| 1677 | ps.size = 64; | |||
| 1678 | ps.mem = malloc(ps.size); | |||
| 1679 | ps.vbuff.curpos = ps.mem; | |||
| 1680 | ||||
| 1681 | /* Save a byte for the NUL terminator */ | |||
| 1682 | ps.vbuff.endpos = ps.mem + ps.size - 1; | |||
| 1683 | ||||
| 1684 | if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) { | |||
| 1685 | if (pool->abort_fn) | |||
| 1686 | pool->abort_fn(APR_ENOMEM12); | |||
| 1687 | ||||
| 1688 | return NULL((void*)0); | |||
| 1689 | } | |||
| 1690 | ||||
| 1691 | *ps.vbuff.curpos++ = '\0'; | |||
| 1692 | ||||
| 1693 | /* | |||
| 1694 | * Link the node in | |||
| 1695 | */ | |||
| 1696 | node = pool->nodes; | |||
| 1697 | if (node == NULL((void*)0) || node->index == 64) { | |||
| 1698 | if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL((void*)0)) { | |||
| 1699 | if (pool->abort_fn) | |||
| 1700 | pool->abort_fn(APR_ENOMEM12); | |||
| 1701 | ||||
| 1702 | return NULL((void*)0); | |||
| 1703 | } | |||
| 1704 | ||||
| 1705 | node->next = pool->nodes; | |||
| 1706 | pool->nodes = node; | |||
| 1707 | node->index = 0; | |||
| 1708 | } | |||
| 1709 | ||||
| 1710 | node->beginp[node->index] = ps.mem; | |||
| 1711 | node->endp[node->index] = ps.mem + ps.size; | |||
| 1712 | node->index++; | |||
| 1713 | ||||
| 1714 | return ps.mem; | |||
| 1715 | } | |||
| 1716 | ||||
| 1717 | ||||
| 1718 | /* | |||
| 1719 | * Debug functions | |||
| 1720 | */ | |||
| 1721 | ||||
| 1722 | APR_DECLARE(void)void apr_pool_join(apr_pool_t *p, apr_pool_t *sub) | |||
| 1723 | { | |||
| 1724 | #if APR_POOL_DEBUG0 | |||
| 1725 | if (sub->parent != p) { | |||
| 1726 | abort(); | |||
| 1727 | } | |||
| 1728 | sub->joined = p; | |||
| 1729 | #endif | |||
| 1730 | } | |||
| 1731 | ||||
| 1732 | static int pool_find(apr_pool_t *pool, void *data) | |||
| 1733 | { | |||
| 1734 | void **pmem = (void **)data; | |||
| 1735 | debug_node_t *node; | |||
| 1736 | apr_uint32_t index; | |||
| 1737 | ||||
| 1738 | node = pool->nodes; | |||
| 1739 | ||||
| 1740 | while (node) { | |||
| 1741 | for (index = 0; index < node->index; index++) { | |||
| 1742 | if (node->beginp[index] <= *pmem | |||
| 1743 | && node->endp[index] > *pmem) { | |||
| 1744 | *pmem = pool; | |||
| 1745 | return 1; | |||
| 1746 | } | |||
| 1747 | } | |||
| 1748 | ||||
| 1749 | node = node->next; | |||
| 1750 | } | |||
| 1751 | ||||
| 1752 | return 0; | |||
| 1753 | } | |||
| 1754 | ||||
| 1755 | APR_DECLARE(apr_pool_t *)apr_pool_t * apr_pool_find(const void *mem) | |||
| 1756 | { | |||
| 1757 | void *pool = (void *)mem; | |||
| 1758 | ||||
| 1759 | if (apr_pool_walk_tree(global_pool, pool_find, &pool)) | |||
| 1760 | return pool; | |||
| 1761 | ||||
| 1762 | return NULL((void*)0); | |||
| 1763 | } | |||
| 1764 | ||||
| 1765 | static int pool_num_bytes(apr_pool_t *pool, void *data) | |||
| 1766 | { | |||
| 1767 | apr_size_t *psize = (apr_size_t *)data; | |||
| 1768 | debug_node_t *node; | |||
| 1769 | apr_uint32_t index; | |||
| 1770 | ||||
| 1771 | node = pool->nodes; | |||
| 1772 | ||||
| 1773 | while (node) { | |||
| 1774 | for (index = 0; index < node->index; index++) { | |||
| 1775 | *psize += (char *)node->endp[index] - (char *)node->beginp[index]; | |||
| 1776 | } | |||
| 1777 | ||||
| 1778 | node = node->next; | |||
| 1779 | } | |||
| 1780 | ||||
| 1781 | return 0; | |||
| 1782 | } | |||
| 1783 | ||||
| 1784 | APR_DECLARE(apr_size_t)apr_size_t apr_pool_num_bytes(apr_pool_t *pool, int recurse) | |||
| 1785 | { | |||
| 1786 | apr_size_t size = 0; | |||
| 1787 | ||||
| 1788 | if (!recurse) { | |||
| 1789 | pool_num_bytes(pool, &size); | |||
| 1790 | ||||
| 1791 | return size; | |||
| 1792 | } | |||
| 1793 | ||||
| 1794 | apr_pool_walk_tree(pool, pool_num_bytes, &size); | |||
| 1795 | ||||
| 1796 | return size; | |||
| 1797 | } | |||
| 1798 | ||||
| 1799 | APR_DECLARE(void)void apr_pool_lock(apr_pool_t *pool, int flag) | |||
| 1800 | { | |||
| 1801 | } | |||
| 1802 | ||||
| 1803 | #endif /* !APR_POOL_DEBUG */ | |||
| 1804 | ||||
| 1805 | #ifdef NETWARE | |||
| 1806 | void netware_pool_proc_cleanup () | |||
| 1807 | { | |||
| 1808 | apr_pool_t *pool = global_pool->child; | |||
| 1809 | apr_os_proc_t owner_proc = (apr_os_proc_t)getnlmhandle(); | |||
| 1810 | ||||
| 1811 | while (pool) { | |||
| 1812 | if (pool->owner_proc == owner_proc) { | |||
| 1813 | apr_pool_destroy (pool); | |||
| 1814 | pool = global_pool->child; | |||
| 1815 | } | |||
| 1816 | else { | |||
| 1817 | pool = pool->sibling; | |||
| 1818 | } | |||
| 1819 | } | |||
| 1820 | return; | |||
| 1821 | } | |||
| 1822 | #endif /* defined(NETWARE) */ | |||
| 1823 | ||||
| 1824 | ||||
| 1825 | /* | |||
| 1826 | * "Print" functions (common) | |||
| 1827 | */ | |||
| 1828 | ||||
| 1829 | APR_DECLARE_NONSTD(char *)char * apr_psprintf(apr_pool_t *p, const char *fmt, ...) | |||
| 1830 | { | |||
| 1831 | va_list ap; | |||
| 1832 | char *res; | |||
| 1833 | ||||
| 1834 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
| 1835 | res = apr_pvsprintf(p, fmt, ap); | |||
| 1836 | va_end(ap)__builtin_va_end(ap); | |||
| 1837 | return res; | |||
| 1838 | } | |||
| 1839 | ||||
| 1840 | /* | |||
| 1841 | * Pool Properties | |||
| 1842 | */ | |||
| 1843 | ||||
| 1844 | APR_DECLARE(void)void apr_pool_abort_set(apr_abortfunc_t abort_fn, | |||
| 1845 | apr_pool_t *pool) | |||
| 1846 | { | |||
| 1847 | pool->abort_fn = abort_fn; | |||
| 1848 | } | |||
| 1849 | ||||
| 1850 | APR_DECLARE(apr_abortfunc_t)apr_abortfunc_t apr_pool_abort_get(apr_pool_t *pool) | |||
| 1851 | { | |||
| 1852 | return pool->abort_fn; | |||
| 1853 | } | |||
| 1854 | ||||
| 1855 | APR_DECLARE(apr_pool_t *)apr_pool_t * apr_pool_parent_get(apr_pool_t *pool) | |||
| 1856 | { | |||
| 1857 | #ifdef NETWARE | |||
| 1858 | /* On NetWare, don't return the global_pool, return the application pool | |||
| 1859 | as the top most pool */ | |||
| 1860 | if (pool->parent == global_pool) | |||
| 1861 | return NULL((void*)0); | |||
| 1862 | else | |||
| 1863 | #endif | |||
| 1864 | return pool->parent; | |||
| 1865 | } | |||
| 1866 | ||||
| 1867 | APR_DECLARE(apr_allocator_t *)apr_allocator_t * apr_pool_allocator_get(apr_pool_t *pool) | |||
| 1868 | { | |||
| 1869 | return pool->allocator; | |||
| 1870 | } | |||
| 1871 | ||||
| 1872 | /* return TRUE if a is an ancestor of b | |||
| 1873 | * NULL is considered an ancestor of all pools | |||
| 1874 | */ | |||
| 1875 | APR_DECLARE(int)int apr_pool_is_ancestor(apr_pool_t *a, apr_pool_t *b) | |||
| 1876 | { | |||
| 1877 | if (a == NULL((void*)0)) | |||
| 1878 | return 1; | |||
| 1879 | ||||
| 1880 | #if APR_POOL_DEBUG0 | |||
| 1881 | /* Find the pool with the longest lifetime guaranteed by the | |||
| 1882 | * caller: */ | |||
| 1883 | while (a->joined) { | |||
| 1884 | a = a->joined; | |||
| 1885 | } | |||
| 1886 | #endif | |||
| 1887 | ||||
| 1888 | while (b) { | |||
| 1889 | if (a == b) | |||
| 1890 | return 1; | |||
| 1891 | ||||
| 1892 | b = b->parent; | |||
| 1893 | } | |||
| 1894 | ||||
| 1895 | return 0; | |||
| 1896 | } | |||
| 1897 | ||||
| 1898 | APR_DECLARE(const char *)const char * apr_pool_tag(apr_pool_t *pool, const char *tag) | |||
| 1899 | { | |||
| 1900 | if (tag) { | |||
| 1901 | pool->tag = tag; | |||
| 1902 | } | |||
| 1903 | ||||
| 1904 | return pool->tag; | |||
| 1905 | } | |||
| 1906 | ||||
| 1907 | ||||
| 1908 | /* | |||
| 1909 | * User data management | |||
| 1910 | */ | |||
| 1911 | ||||
| 1912 | APR_DECLARE(apr_status_t)apr_status_t apr_pool_userdata_set(const void *data, const char *key, | |||
| 1913 | apr_status_t (*cleanup) (void *), | |||
| 1914 | apr_pool_t *pool) | |||
| 1915 | { | |||
| 1916 | #if APR_POOL_DEBUG0 | |||
| 1917 | apr_pool_check_integrity(pool); | |||
| 1918 | #endif /* APR_POOL_DEBUG */ | |||
| 1919 | ||||
| 1920 | if (pool->user_data == NULL((void*)0)) | |||
| 1921 | pool->user_data = apr_hash_make(pool); | |||
| 1922 | ||||
| 1923 | if (apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING(-1)) == NULL((void*)0)) { | |||
| 1924 | char *new_key = apr_pstrdup(pool, key); | |||
| 1925 | apr_hash_set(pool->user_data, new_key, APR_HASH_KEY_STRING(-1), data); | |||
| 1926 | } | |||
| 1927 | else { | |||
| 1928 | apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING(-1), data); | |||
| 1929 | } | |||
| 1930 | ||||
| 1931 | if (cleanup) | |||
| 1932 | apr_pool_cleanup_register(pool, data, cleanup, cleanup); | |||
| 1933 | ||||
| 1934 | return APR_SUCCESS0; | |||
| 1935 | } | |||
| 1936 | ||||
| 1937 | APR_DECLARE(apr_status_t)apr_status_t apr_pool_userdata_setn(const void *data, | |||
| 1938 | const char *key, | |||
| 1939 | apr_status_t (*cleanup)(void *), | |||
| 1940 | apr_pool_t *pool) | |||
| 1941 | { | |||
| 1942 | #if APR_POOL_DEBUG0 | |||
| 1943 | apr_pool_check_integrity(pool); | |||
| 1944 | #endif /* APR_POOL_DEBUG */ | |||
| 1945 | ||||
| 1946 | if (pool->user_data == NULL((void*)0)) | |||
| 1947 | pool->user_data = apr_hash_make(pool); | |||
| 1948 | ||||
| 1949 | apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING(-1), data); | |||
| 1950 | ||||
| 1951 | if (cleanup) | |||
| 1952 | apr_pool_cleanup_register(pool, data, cleanup, cleanup); | |||
| 1953 | ||||
| 1954 | return APR_SUCCESS0; | |||
| 1955 | } | |||
| 1956 | ||||
| 1957 | APR_DECLARE(apr_status_t)apr_status_t apr_pool_userdata_get(void **data, const char *key, | |||
| 1958 | apr_pool_t *pool) | |||
| 1959 | { | |||
| 1960 | #if APR_POOL_DEBUG0 | |||
| 1961 | apr_pool_check_integrity(pool); | |||
| 1962 | #endif /* APR_POOL_DEBUG */ | |||
| 1963 | ||||
| 1964 | if (pool->user_data == NULL((void*)0)) { | |||
| 1965 | *data = NULL((void*)0); | |||
| 1966 | } | |||
| 1967 | else { | |||
| 1968 | *data = apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING(-1)); | |||
| 1969 | } | |||
| 1970 | ||||
| 1971 | return APR_SUCCESS0; | |||
| 1972 | } | |||
| 1973 | ||||
| 1974 | ||||
| 1975 | /* | |||
| 1976 | * Cleanup | |||
| 1977 | */ | |||
| 1978 | ||||
| 1979 | struct cleanup_t { | |||
| 1980 | struct cleanup_t *next; | |||
| 1981 | const void *data; | |||
| 1982 | apr_status_t (*plain_cleanup_fn)(void *data); | |||
| 1983 | apr_status_t (*child_cleanup_fn)(void *data); | |||
| 1984 | }; | |||
| 1985 | ||||
| 1986 | APR_DECLARE(void)void apr_pool_cleanup_register(apr_pool_t *p, const void *data, | |||
| 1987 | apr_status_t (*plain_cleanup_fn)(void *data), | |||
| 1988 | apr_status_t (*child_cleanup_fn)(void *data)) | |||
| 1989 | { | |||
| 1990 | cleanup_t *c; | |||
| 1991 | ||||
| 1992 | #if APR_POOL_DEBUG0 | |||
| 1993 | apr_pool_check_integrity(p); | |||
| 1994 | #endif /* APR_POOL_DEBUG */ | |||
| 1995 | ||||
| 1996 | if (p != NULL((void*)0)) { | |||
| 1997 | if (p->free_cleanups) { | |||
| 1998 | /* reuse a cleanup structure */ | |||
| 1999 | c = p->free_cleanups; | |||
| 2000 | p->free_cleanups = c->next; | |||
| 2001 | } else { | |||
| 2002 | c = apr_palloc(p, sizeof(cleanup_t)); | |||
| 2003 | } | |||
| 2004 | c->data = data; | |||
| 2005 | c->plain_cleanup_fn = plain_cleanup_fn; | |||
| 2006 | c->child_cleanup_fn = child_cleanup_fn; | |||
| 2007 | c->next = p->cleanups; | |||
| 2008 | p->cleanups = c; | |||
| 2009 | } | |||
| 2010 | } | |||
| 2011 | ||||
| 2012 | APR_DECLARE(void)void apr_pool_cleanup_kill(apr_pool_t *p, const void *data, | |||
| 2013 | apr_status_t (*cleanup_fn)(void *)) | |||
| 2014 | { | |||
| 2015 | cleanup_t *c, **lastp; | |||
| 2016 | ||||
| 2017 | #if APR_POOL_DEBUG0 | |||
| 2018 | apr_pool_check_integrity(p); | |||
| 2019 | #endif /* APR_POOL_DEBUG */ | |||
| 2020 | ||||
| 2021 | if (p == NULL((void*)0)) | |||
| 2022 | return; | |||
| 2023 | ||||
| 2024 | c = p->cleanups; | |||
| 2025 | lastp = &p->cleanups; | |||
| 2026 | while (c) { | |||
| 2027 | if (c->data == data && c->plain_cleanup_fn == cleanup_fn) { | |||
| 2028 | *lastp = c->next; | |||
| 2029 | /* move to freelist */ | |||
| 2030 | c->next = p->free_cleanups; | |||
| 2031 | p->free_cleanups = c; | |||
| 2032 | break; | |||
| 2033 | } | |||
| 2034 | ||||
| 2035 | lastp = &c->next; | |||
| 2036 | ||||
| 2037 | if (c == c->next) { | |||
| 2038 | c = NULL((void*)0); | |||
| 2039 | } else { | |||
| 2040 | c = c->next; | |||
| 2041 | } | |||
| 2042 | } | |||
| 2043 | } | |||
| 2044 | ||||
| 2045 | APR_DECLARE(void)void apr_pool_child_cleanup_set(apr_pool_t *p, const void *data, | |||
| 2046 | apr_status_t (*plain_cleanup_fn)(void *), | |||
| 2047 | apr_status_t (*child_cleanup_fn)(void *)) | |||
| 2048 | { | |||
| 2049 | cleanup_t *c; | |||
| 2050 | ||||
| 2051 | #if APR_POOL_DEBUG0 | |||
| 2052 | apr_pool_check_integrity(p); | |||
| 2053 | #endif /* APR_POOL_DEBUG */ | |||
| 2054 | ||||
| 2055 | if (p == NULL((void*)0)) | |||
| 2056 | return; | |||
| 2057 | ||||
| 2058 | c = p->cleanups; | |||
| 2059 | while (c) { | |||
| 2060 | if (c->data == data && c->plain_cleanup_fn == plain_cleanup_fn) { | |||
| 2061 | c->child_cleanup_fn = child_cleanup_fn; | |||
| 2062 | break; | |||
| 2063 | } | |||
| 2064 | ||||
| 2065 | c = c->next; | |||
| 2066 | } | |||
| 2067 | } | |||
| 2068 | ||||
| 2069 | APR_DECLARE(apr_status_t)apr_status_t apr_pool_cleanup_run(apr_pool_t *p, void *data, | |||
| 2070 | apr_status_t (*cleanup_fn)(void *)) | |||
| 2071 | { | |||
| 2072 | apr_pool_cleanup_kill(p, data, cleanup_fn); | |||
| 2073 | return (*cleanup_fn)(data); | |||
| 2074 | } | |||
| 2075 | ||||
| 2076 | static void run_cleanups(cleanup_t **cref) | |||
| 2077 | { | |||
| 2078 | cleanup_t *c = *cref; | |||
| 2079 | ||||
| 2080 | while (c) { | |||
| 2081 | *cref = c->next; | |||
| 2082 | (*c->plain_cleanup_fn)((void *)c->data); | |||
| 2083 | c = *cref; | |||
| 2084 | } | |||
| 2085 | } | |||
| 2086 | ||||
| 2087 | static void run_child_cleanups(cleanup_t **cref) | |||
| 2088 | { | |||
| 2089 | cleanup_t *c = *cref; | |||
| 2090 | ||||
| 2091 | while (c) { | |||
| 2092 | *cref = c->next; | |||
| 2093 | (*c->child_cleanup_fn)((void *)c->data); | |||
| 2094 | c = *cref; | |||
| 2095 | } | |||
| 2096 | } | |||
| 2097 | ||||
| 2098 | static void cleanup_pool_for_exec(apr_pool_t *p) | |||
| 2099 | { | |||
| 2100 | run_child_cleanups(&p->cleanups); | |||
| 2101 | ||||
| 2102 | for (p = p->child; p; p = p->sibling) | |||
| 2103 | cleanup_pool_for_exec(p); | |||
| 2104 | } | |||
| 2105 | ||||
| 2106 | APR_DECLARE(void)void apr_pool_cleanup_for_exec(void) | |||
| 2107 | { | |||
| 2108 | #if !defined(WIN32) && !defined(OS2) | |||
| 2109 | /* | |||
| 2110 | * Don't need to do anything on NT or OS/2, because I | |||
| 2111 | * am actually going to spawn the new process - not | |||
| 2112 | * exec it. All handles that are not inheritable, will | |||
| 2113 | * be automajically closed. The only problem is with | |||
| 2114 | * file handles that are open, but there isn't much | |||
| 2115 | * I can do about that (except if the child decides | |||
| 2116 | * to go out and close them | |||
| 2117 | */ | |||
| 2118 | cleanup_pool_for_exec(global_pool); | |||
| 2119 | #endif /* !defined(WIN32) && !defined(OS2) */ | |||
| 2120 | } | |||
| 2121 | ||||
| 2122 | APR_DECLARE_NONSTD(apr_status_t)apr_status_t apr_pool_cleanup_null(void *data) | |||
| 2123 | { | |||
| 2124 | /* do nothing cleanup routine */ | |||
| 2125 | return APR_SUCCESS0; | |||
| 2126 | } | |||
| 2127 | ||||
| 2128 | /* Subprocesses don't use the generic cleanup interface because | |||
| 2129 | * we don't want multiple subprocesses to result in multiple | |||
| 2130 | * three-second pauses; the subprocesses have to be "freed" all | |||
| 2131 | * at once. If other resources are introduced with the same property, | |||
| 2132 | * we might want to fold support for that into the generic interface. | |||
| 2133 | * For now, it's a special case. | |||
| 2134 | */ | |||
| 2135 | APR_DECLARE(void)void apr_pool_note_subprocess(apr_pool_t *pool, apr_proc_t *proc, | |||
| 2136 | apr_kill_conditions_e how) | |||
| 2137 | { | |||
| 2138 | struct process_chain *pc = apr_palloc(pool, sizeof(struct process_chain)); | |||
| 2139 | ||||
| 2140 | pc->proc = proc; | |||
| 2141 | pc->kill_how = how; | |||
| 2142 | pc->next = pool->subprocesses; | |||
| 2143 | pool->subprocesses = pc; | |||
| 2144 | } | |||
| 2145 | ||||
| 2146 | static void free_proc_chain(struct process_chain *procs) | |||
| 2147 | { | |||
| 2148 | /* Dispose of the subprocesses we've spawned off in the course of | |||
| 2149 | * whatever it was we're cleaning up now. This may involve killing | |||
| 2150 | * some of them off... | |||
| 2151 | */ | |||
| 2152 | struct process_chain *pc; | |||
| 2153 | int need_timeout = 0; | |||
| 2154 | apr_time_t timeout_interval; | |||
| 2155 | ||||
| 2156 | if (!procs) | |||
| 2157 | return; /* No work. Whew! */ | |||
| 2158 | ||||
| 2159 | /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL | |||
| 2160 | * dance with any of the processes we're cleaning up. If we've got | |||
| 2161 | * any kill-on-sight subprocesses, ditch them now as well, so they | |||
| 2162 | * don't waste any more cycles doing whatever it is that they shouldn't | |||
| 2163 | * be doing anymore. | |||
| 2164 | */ | |||
| 2165 | ||||
| 2166 | #ifndef NEED_WAITPID | |||
| 2167 | /* Pick up all defunct processes */ | |||
| 2168 | for (pc = procs; pc; pc = pc->next) { | |||
| 2169 | if (apr_proc_wait(pc->proc, NULL((void*)0), NULL((void*)0), APR_NOWAIT) != APR_CHILD_NOTDONE((20000 + 50000) + 6)) | |||
| 2170 | pc->kill_how = APR_KILL_NEVER; | |||
| 2171 | } | |||
| 2172 | #endif /* !defined(NEED_WAITPID) */ | |||
| 2173 | ||||
| 2174 | for (pc = procs; pc; pc = pc->next) { | |||
| 2175 | #ifndef WIN32 | |||
| 2176 | if ((pc->kill_how == APR_KILL_AFTER_TIMEOUT) | |||
| 2177 | || (pc->kill_how == APR_KILL_ONLY_ONCE)) { | |||
| 2178 | /* | |||
| 2179 | * Subprocess may be dead already. Only need the timeout if not. | |||
| 2180 | * Note: apr_proc_kill on Windows is TerminateProcess(), which is | |||
| 2181 | * similar to a SIGKILL, so always give the process a timeout | |||
| 2182 | * under Windows before killing it. | |||
| 2183 | */ | |||
| 2184 | if (apr_proc_kill(pc->proc, SIGTERM15) == APR_SUCCESS0) | |||
| 2185 | need_timeout = 1; | |||
| 2186 | } | |||
| 2187 | else if (pc->kill_how == APR_KILL_ALWAYS) { | |||
| 2188 | #else /* WIN32 knows only one fast, clean method of killing processes today */ | |||
| 2189 | if (pc->kill_how != APR_KILL_NEVER) { | |||
| 2190 | need_timeout = 1; | |||
| 2191 | pc->kill_how = APR_KILL_ALWAYS; | |||
| 2192 | #endif | |||
| 2193 | apr_proc_kill(pc->proc, SIGKILL9); | |||
| 2194 | } | |||
| 2195 | } | |||
| 2196 | ||||
| 2197 | /* Sleep only if we have to. The sleep algorithm grows | |||
| 2198 | * by a factor of two on each iteration. TIMEOUT_INTERVAL | |||
| 2199 | * is equal to TIMEOUT_USECS / 64. | |||
| 2200 | */ | |||
| 2201 | if (need_timeout) { | |||
| 2202 | timeout_interval = TIMEOUT_INTERVAL46875; | |||
| 2203 | apr_sleep(timeout_interval); | |||
| 2204 | ||||
| 2205 | do { | |||
| 2206 | /* check the status of the subprocesses */ | |||
| 2207 | need_timeout = 0; | |||
| 2208 | for (pc = procs; pc; pc = pc->next) { | |||
| 2209 | if (pc->kill_how == APR_KILL_AFTER_TIMEOUT) { | |||
| 2210 | if (apr_proc_wait(pc->proc, NULL((void*)0), NULL((void*)0), APR_NOWAIT) | |||
| 2211 | == APR_CHILD_NOTDONE((20000 + 50000) + 6)) | |||
| 2212 | need_timeout = 1; /* subprocess is still active */ | |||
| 2213 | else | |||
| 2214 | pc->kill_how = APR_KILL_NEVER; /* subprocess has exited */ | |||
| 2215 | } | |||
| 2216 | } | |||
| 2217 | if (need_timeout) { | |||
| 2218 | if (timeout_interval >= TIMEOUT_USECS3000000) { | |||
| 2219 | break; | |||
| 2220 | } | |||
| 2221 | apr_sleep(timeout_interval); | |||
| 2222 | timeout_interval *= 2; | |||
| 2223 | } | |||
| 2224 | } while (need_timeout); | |||
| 2225 | } | |||
| 2226 | ||||
| 2227 | /* OK, the scripts we just timed out for have had a chance to clean up | |||
| 2228 | * --- now, just get rid of them, and also clean up the system accounting | |||
| 2229 | * goop... | |||
| 2230 | */ | |||
| 2231 | for (pc = procs; pc; pc = pc->next) { | |||
| 2232 | if (pc->kill_how == APR_KILL_AFTER_TIMEOUT) | |||
| 2233 | apr_proc_kill(pc->proc, SIGKILL9); | |||
| 2234 | } | |||
| 2235 | ||||
| 2236 | /* Now wait for all the signaled processes to die */ | |||
| 2237 | for (pc = procs; pc; pc = pc->next) { | |||
| 2238 | if (pc->kill_how != APR_KILL_NEVER) | |||
| 2239 | (void)apr_proc_wait(pc->proc, NULL((void*)0), NULL((void*)0), APR_WAIT); | |||
| 2240 | } | |||
| 2241 | } | |||
| 2242 | ||||
| 2243 | ||||
| 2244 | /* | |||
| 2245 | * Pool creation/destruction stubs, for people who are running | |||
| 2246 | * mixed release/debug enviroments. | |||
| 2247 | */ | |||
| 2248 | ||||
| 2249 | #if !APR_POOL_DEBUG0 | |||
| 2250 | APR_DECLARE(void *)void * apr_palloc_debug(apr_pool_t *pool, apr_size_t size, | |||
| 2251 | const char *file_line) | |||
| 2252 | { | |||
| 2253 | return apr_palloc(pool, size); | |||
| 2254 | } | |||
| 2255 | ||||
| 2256 | APR_DECLARE(void *)void * apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size, | |||
| 2257 | const char *file_line) | |||
| 2258 | { | |||
| 2259 | return apr_pcalloc(pool, size); | |||
| 2260 | } | |||
| 2261 | ||||
| 2262 | APR_DECLARE(void)void apr_pool_clear_debug(apr_pool_t *pool, | |||
| 2263 | const char *file_line) | |||
| 2264 | { | |||
| 2265 | apr_pool_clear(pool); | |||
| 2266 | } | |||
| 2267 | ||||
| 2268 | APR_DECLARE(void)void apr_pool_destroy_debug(apr_pool_t *pool, | |||
| 2269 | const char *file_line) | |||
| 2270 | { | |||
| 2271 | apr_pool_destroy(pool); | |||
| 2272 | } | |||
| 2273 | ||||
| 2274 | APR_DECLARE(apr_status_t)apr_status_t apr_pool_create_ex_debug(apr_pool_t **newpool, | |||
| 2275 | apr_pool_t *parent, | |||
| 2276 | apr_abortfunc_t abort_fn, | |||
| 2277 | apr_allocator_t *allocator, | |||
| 2278 | const char *file_line) | |||
| 2279 | { | |||
| 2280 | return apr_pool_create_ex(newpool, parent, abort_fn, allocator); | |||
| ||||
| 2281 | } | |||
| 2282 | ||||
| 2283 | #else /* APR_POOL_DEBUG */ | |||
| 2284 | ||||
| 2285 | #undef apr_palloc | |||
| 2286 | APR_DECLARE(void *)void * apr_palloc(apr_pool_t *pool, apr_size_t size); | |||
| 2287 | ||||
| 2288 | APR_DECLARE(void *)void * apr_palloc(apr_pool_t *pool, apr_size_t size) | |||
| 2289 | { | |||
| 2290 | return apr_palloc_debug(pool, size, "undefined"); | |||
| 2291 | } | |||
| 2292 | ||||
| 2293 | #undef apr_pcalloc | |||
| 2294 | APR_DECLARE(void *)void * apr_pcalloc(apr_pool_t *pool, apr_size_t size); | |||
| 2295 | ||||
| 2296 | APR_DECLARE(void *)void * apr_pcalloc(apr_pool_t *pool, apr_size_t size) | |||
| 2297 | { | |||
| 2298 | return apr_pcalloc_debug(pool, size, "undefined"); | |||
| 2299 | } | |||
| 2300 | ||||
| 2301 | #undef apr_pool_clear | |||
| 2302 | APR_DECLARE(void)void apr_pool_clear(apr_pool_t *pool); | |||
| 2303 | ||||
| 2304 | APR_DECLARE(void)void apr_pool_clear(apr_pool_t *pool) | |||
| 2305 | { | |||
| 2306 | apr_pool_clear_debug(pool, "undefined"); | |||
| 2307 | } | |||
| 2308 | ||||
| 2309 | #undef apr_pool_destroy | |||
| 2310 | APR_DECLARE(void)void apr_pool_destroy(apr_pool_t *pool); | |||
| 2311 | ||||
| 2312 | APR_DECLARE(void)void apr_pool_destroy(apr_pool_t *pool) | |||
| 2313 | { | |||
| 2314 | apr_pool_destroy_debug(pool, "undefined"); | |||
| 2315 | } | |||
| 2316 | ||||
| 2317 | #undef apr_pool_create_ex | |||
| 2318 | APR_DECLARE(apr_status_t)apr_status_t apr_pool_create_ex(apr_pool_t **newpool, | |||
| 2319 | apr_pool_t *parent, | |||
| 2320 | apr_abortfunc_t abort_fn, | |||
| 2321 | apr_allocator_t *allocator); | |||
| 2322 | ||||
| 2323 | APR_DECLARE(apr_status_t)apr_status_t apr_pool_create_ex(apr_pool_t **newpool, | |||
| 2324 | apr_pool_t *parent, | |||
| 2325 | apr_abortfunc_t abort_fn, | |||
| 2326 | apr_allocator_t *allocator) | |||
| 2327 | { | |||
| 2328 | return apr_pool_create_ex_debug(newpool, parent, | |||
| 2329 | abort_fn, allocator, | |||
| 2330 | "undefined"); | |||
| 2331 | } | |||
| 2332 | ||||
| 2333 | #endif /* APR_POOL_DEBUG */ |