📄 apr_pools.c
字号:
static int pool_is_child_of(apr_pool_t *parent, void *data){ apr_pool_t *pool = (apr_pool_t *)data; return (pool == parent);}static int apr_pool_is_child_of(apr_pool_t *pool, apr_pool_t *parent){ if (parent == NULL) return 0; return apr_pool_walk_tree(parent, pool_is_child_of, pool);}#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */static void apr_pool_check_integrity(apr_pool_t *pool){ /* Rule of thumb: use of the global pool is always * ok, since the only user is apr_pools.c. Unless * people have searched for the top level parent and * started to use that... */ if (pool == global_pool || global_pool == NULL) return; /* Lifetime * This basically checks to see if the pool being used is still * a relative to the global pool. If not it was previously * destroyed, in which case we abort(). */#if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) if (!apr_pool_is_child_of(pool, global_pool)) {#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) apr_pool_log_event(pool, "LIFE", __FILE__ ":apr_pool_integrity check", 0);#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ abort(); }#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */#if (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER)#if APR_HAS_THREADS if (!apr_os_thread_equal(pool->owner, apr_os_thread_current())) {#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) apr_pool_log_event(pool, "THREAD", __FILE__ ":apr_pool_integrity check", 0);#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ abort(); }#endif /* APR_HAS_THREADS */#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) */}/* * Initialization (debug) */APR_DECLARE(apr_status_t) apr_pool_initialize(void){ apr_status_t rv;#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) char *logpath;#endif if (apr_pools_initialized++) return APR_SUCCESS; /* Since the debug code works a bit differently then the * regular pools code, we ask for a lock here. The regular * pools code has got this lock embedded in the global * allocator, a concept unknown to debug mode. */ if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL, NULL)) != APR_SUCCESS) { return rv; } apr_pool_tag(global_pool, "APR global pool"); apr_pools_initialized = 1; /* This has to happen here because mutexes might be backed by * atomics. It used to be snug and safe in apr_initialize(). */ if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) { return rv; }#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) rv = apr_env_get(&logpath, "APR_POOL_DEBUG_LOG", global_pool); if (rv == APR_SUCCESS) { apr_file_open(&file_stderr, logpath, APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, global_pool); } else { apr_file_open_stderr(&file_stderr, global_pool); } if (file_stderr) { apr_file_printf(file_stderr, "POOL DEBUG: [PID"#if APR_HAS_THREADS "/TID"#endif /* APR_HAS_THREADS */ "] ACTION (SIZE /POOL SIZE /TOTAL SIZE) " "POOL \"TAG\" <__FILE__:__LINE__> (ALLOCS/TOTAL ALLOCS/CLEARS)\n"); apr_pool_log_event(global_pool, "GLOBAL", __FILE__ ":apr_pool_initialize", 0); }#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ return APR_SUCCESS;}APR_DECLARE(void) apr_pool_terminate(void){ if (!apr_pools_initialized) return; apr_pools_initialized = 0; apr_pool_destroy(global_pool); /* This will also destroy the mutex */ global_pool = NULL;#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) file_stderr = NULL;#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */}/* * Memory allocation (debug) */static void *pool_alloc(apr_pool_t *pool, apr_size_t size){ debug_node_t *node; void *mem; if ((mem = malloc(size)) == NULL) { if (pool->abort_fn) pool->abort_fn(APR_ENOMEM); return NULL; } node = pool->nodes; if (node == NULL || node->index == 64) { if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) { if (pool->abort_fn) pool->abort_fn(APR_ENOMEM); return NULL; } memset(node, 0, SIZEOF_DEBUG_NODE_T); node->next = pool->nodes; pool->nodes = node; node->index = 0; } node->beginp[node->index] = mem; node->endp[node->index] = (char *)mem + size; node->index++; pool->stat_alloc++; pool->stat_total_alloc++; return mem;}APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size, const char *file_line){ void *mem; apr_pool_check_integrity(pool); mem = pool_alloc(pool, size);#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) apr_pool_log_event(pool, "PALLOC", file_line, 1);#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */ return mem;}APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size, const char *file_line){ void *mem; apr_pool_check_integrity(pool); mem = pool_alloc(pool, size); memset(mem, 0, size);#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) apr_pool_log_event(pool, "PCALLOC", file_line, 1);#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */ return mem;}/* * Pool creation/destruction (debug) */#define POOL_POISON_BYTE 'A'static void pool_clear_debug(apr_pool_t *pool, const char *file_line){ debug_node_t *node; apr_uint32_t index; /* Destroy the subpools. The subpools will detach themselves from * this pool thus this loop is safe and easy. */ while (pool->child) pool_destroy_debug(pool->child, file_line); /* Run cleanups */ run_cleanups(&pool->cleanups); pool->free_cleanups = NULL; pool->cleanups = NULL; /* If new child pools showed up, this is a reason to raise a flag */ if (pool->child) abort(); /* Free subprocesses */ free_proc_chain(pool->subprocesses); pool->subprocesses = NULL; /* Clear the user data. */ pool->user_data = NULL; /* Free the blocks, scribbling over them first to help highlight * use-after-free issues. */ while ((node = pool->nodes) != NULL) { pool->nodes = node->next; for (index = 0; index < node->index; index++) { memset(node->beginp[index], POOL_POISON_BYTE, node->endp[index] - node->beginp[index]); free(node->beginp[index]); } memset(node, POOL_POISON_BYTE, SIZEOF_DEBUG_NODE_T); free(node); } pool->stat_alloc = 0; pool->stat_clear++;}APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *pool, const char *file_line){#if APR_HAS_THREADS apr_thread_mutex_t *mutex = NULL;#endif apr_pool_check_integrity(pool);#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) apr_pool_log_event(pool, "CLEAR", file_line, 1);#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */#if APR_HAS_THREADS if (pool->parent != NULL) mutex = pool->parent->mutex; /* Lock the parent mutex before clearing so that if we have our * own mutex it won't be accessed by apr_pool_walk_tree after * it has been destroyed. */ if (mutex != NULL && mutex != pool->mutex) { apr_thread_mutex_lock(mutex); }#endif pool_clear_debug(pool, file_line);#if APR_HAS_THREADS /* If we had our own mutex, it will have been destroyed by * the registered cleanups. Recreate the mutex. Unlock * the mutex we obtained above. */ if (mutex != pool->mutex) { (void)apr_thread_mutex_create(&pool->mutex, APR_THREAD_MUTEX_NESTED, pool); if (mutex != NULL) (void)apr_thread_mutex_unlock(mutex); }#endif /* APR_HAS_THREADS */}static void pool_destroy_debug(apr_pool_t *pool, const char *file_line){ apr_pool_check_integrity(pool);#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) apr_pool_log_event(pool, "DESTROY", file_line, 1);#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ pool_clear_debug(pool, file_line); /* Remove the pool from the parents child list */ if (pool->parent) {#if APR_HAS_THREADS apr_thread_mutex_t *mutex; if ((mutex = pool->parent->mutex) != NULL) apr_thread_mutex_lock(mutex);#endif /* APR_HAS_THREADS */ if ((*pool->ref = pool->sibling) != NULL) pool->sibling->ref = pool->ref;#if APR_HAS_THREADS if (mutex) apr_thread_mutex_unlock(mutex);#endif /* APR_HAS_THREADS */ } if (pool->allocator != NULL && apr_allocator_owner_get(pool->allocator) == pool) { apr_allocator_destroy(pool->allocator); } /* Free the pool itself */ free(pool);}APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *pool, const char *file_line){ if (pool->joined) { /* Joined pools must not be explicitly destroyed; the caller * has broken the guarantee. */#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) apr_pool_log_event(pool, "LIFE", __FILE__ ":apr_pool_destroy abort on joined", 0);#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ abort(); } pool_destroy_debug(pool, file_line);}APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool, apr_pool_t *parent, apr_abortfunc_t abort_fn, apr_allocator_t *allocator, const char *file_line){ apr_pool_t *pool; *newpool = NULL; if (!parent) { parent = global_pool; } else { apr_pool_check_integrity(parent); if (!allocator) allocator = parent->allocator; } if (!abort_fn && parent) abort_fn = parent->abort_fn; if ((pool = malloc(SIZEOF_POOL_T)) == NULL) { if (abort_fn) abort_fn(APR_ENOMEM); return APR_ENOMEM; } memset(pool, 0, SIZEOF_POOL_T); pool->allocator = allocator; pool->abort_fn = abort_fn; pool->tag = file_line; pool->file_line = file_line; if ((pool->parent = parent) != NULL) {#if APR_HAS_THREADS if (parent->mutex) apr_thread_mutex_lock(parent->mutex);#endif /* APR_HAS_THREADS */ if ((pool->sibling = parent->child) != NULL) pool->sibling->ref = &pool->sibling; parent->child = pool; pool->ref = &parent->child;#if APR_HAS_THREADS if (parent->mutex) apr_thread_mutex_unlock(parent->mutex);#endif /* APR_HAS_THREADS */ } else { pool->sibling = NULL; pool->ref = NULL; }#if APR_HAS_THREADS pool->owner = apr_os_thread_current();#endif /* APR_HAS_THREADS */#ifdef NETWARE pool->owner_proc = (apr_os_proc_t)getnlmhandle();#endif /* defined(NETWARE) */ if (parent == NULL || parent->allocator != allocator) {#if APR_HAS_THREADS apr_status_t rv; /* No matter what the creation flags say, always create * a lock. Without it integrity_check and apr_pool_num_bytes * blow up (because they traverse pools child lists that * possibly belong to another thread, in combination with * the pool having no lock). However, this might actually * hide problems like creating a child pool of a pool * belonging to another thread. */ if ((rv = apr_thread_mutex_create(&pool->mutex, APR_THREAD_MUTEX_NESTED, pool)) != APR_SUCCESS) { free(pool); return rv; }#endif /* APR_HAS_THREADS */ } else {#if APR_HAS_THREADS if (parent) pool->mutex = parent->mutex;#endif /* APR_HAS_THREADS */ } *newpool = pool;#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) apr_pool_log_event(pool, "CREATE", file_line, 1);#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ return APR_SUCCESS;}/* * "Print" functions (debug) */struct psprintf_data { apr_vformatter_buff_t vbuff; char *mem; apr_size_t size;};static int psprintf_flush(apr_vformatter_buff_t *vbuff){ struct psprintf_data *ps = (struct psprintf_data *)vbuff; apr_size_t size; size = ps->vbuff.curpos - ps->mem; ps->size <<= 1; if ((ps->mem = realloc(ps->mem, ps->size)) == NULL) return -1; ps->vbuff.curpos = ps->mem + size; ps->vbuff.endpos = ps->mem + ps->size - 1; return 0;}APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap){ struct psprintf_data ps; debug_node_t *node; apr_pool_check_integrity(pool); ps.size = 64; ps.mem = malloc(ps.size); ps.vbuff.curpos = ps.mem; /* Save a byte for the NUL terminator */ ps.vbuff.endpos = ps.mem + ps.size - 1; if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) { if (pool->abort_fn) pool->abort_fn(APR_ENOMEM); return NULL; } *ps.vbuff.curpos++ = '\0'; /* * Link the node in */ node = pool->nodes; if (node == NULL || node->index == 64) { if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) { if (pool->abort_fn) pool->abort_fn(APR_ENOMEM); return NULL; } node->next = pool->nodes; pool->nodes = node; node->index = 0; } node->beginp[node->index] = ps.mem; node->endp[node->index] = ps.mem + ps.size; node->index++; return ps.mem;}/* * Debug functions */APR_DECLARE(void) apr_pool_join(apr_pool_t *p, apr_pool_t *sub){#if APR_POOL_DEBUG if (sub->parent != p) { abort(); } sub->joined = p;#endif}static int pool_find(apr_pool_t *pool, void *data){ void **pmem = (void **)data; debug_node_t *node; apr_uint32_t index; node = pool->nodes; while (node) { for (index = 0; index < node->index; index++) { if (node->beginp[index] <= *pmem && node->endp[index] > *pmem) { *pmem = pool; return 1; } } node = node->next; } return 0;}APR_DECLARE(apr_pool_t *) apr_pool_find(const void *mem)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -