On Thu, Aug 21, 2025 at 10:13 AM Branko Čibej <br...@apache.org> wrote:
>
>> On 21. 8. 25 09:58, Joe Orton wrote:
>>
>> The pool-debug tests for httpd have started failing with SIGSEGV, I am
>> guessing related to this change since these have been very stable for a
>> long time. I think this is the relevant part of the traceback:
>
> It's probably related to what Yann pointed out yesterday. My bad. Will fix as 
> soon as I can, or indeed Yann could just commit and backport his patches; I'm 
> a bit swamped ATM.

Looks like it's not related, my patch only fixes some error cases
(which need some cleanup after the code move), but I don't think httpd
fails on creating a pool.

I think what happens is that now apr_pool_create_ex_debug() will
attach the pool to its parent before creating the mutex, but then an
apr_pool_walk_tree() on the parent (or any ancestor) running
concurrently might find the new pool with ->mutex == NULL, and
segfault in pool_lock().

ISTM that apr_pool_check_lifetime() could simply ignore any pool with
->parent == NULL (this includes the global pool and unmanaged pools),
and then we can move back the mutex creation before the pool is
attached to its parent.

Something like the attached patch?

Cheers;
Yann.
Index: memory/unix/apr_pools.c
===================================================================
--- memory/unix/apr_pools.c	(revision 1927913)
+++ memory/unix/apr_pools.c	(working copy)
@@ -600,7 +600,6 @@ struct apr_pool_t {
     apr_os_thread_t       owner;
     apr_thread_mutex_t   *mutex;
 #endif /* APR_HAS_THREADS */
-    int                   unmanaged;
 #endif /* APR_POOL_DEBUG */
 #ifdef NETWARE
     apr_os_proc_t         owner_proc;
@@ -1619,9 +1618,11 @@ static void apr_pool_check_lifetime(apr_pool_t *po
      * ok, since the only user is apr_pools.c.  Unless
      * people have searched for the top level parent and
      * started to use that...
+     * Like the global pool, unmanaged pools have their
+     * own lifetime and no ->parent, ignore both here.
+     *
      */
-    if (pool == global_pool || global_pool == NULL
-        || (pool->parent == NULL && pool->unmanaged))
+    if (pool->parent == NULL)
         return;
 
     /* Lifetime
@@ -2065,22 +2066,6 @@ APR_DECLARE(apr_status_t) apr_pool_create_ex_debug
     pool->owner_proc = (apr_os_proc_t)getnlmhandle();
 #endif /* defined(NETWARE) */
 
-    if ((pool->parent = parent) != NULL) {
-        pool_lock(parent);
-
-        if ((pool->sibling = parent->child) != NULL)
-            pool->sibling->ref = &pool->sibling;
-
-        parent->child = pool;
-        pool->ref = &parent->child;
-
-        pool_unlock(parent);
-    }
-    else {
-        pool->sibling = NULL;
-        pool->ref = NULL;
-    }
-
 #if APR_HAS_THREADS
     if (parent == NULL || parent->allocator != allocator) {
         apr_status_t rv;
@@ -2104,6 +2089,22 @@ APR_DECLARE(apr_status_t) apr_pool_create_ex_debug
     }
 #endif /* APR_HAS_THREADS */
 
+    if ((pool->parent = parent) != NULL) {
+        pool_lock(parent);
+
+        if ((pool->sibling = parent->child) != NULL)
+            pool->sibling->ref = &pool->sibling;
+
+        parent->child = pool;
+        pool->ref = &parent->child;
+
+        pool_unlock(parent);
+    }
+    else {
+        pool->sibling = NULL;
+        pool->ref = NULL;
+    }
+
 #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) */
@@ -2132,7 +2133,6 @@ APR_DECLARE(apr_status_t) apr_pool_create_unmanage
 
     memset(pool, 0, SIZEOF_POOL_T);
 
-    pool->unmanaged = 1;
     pool->abort_fn = abort_fn;
     pool->tag = file_line;
     pool->file_line = file_line;
@@ -2169,6 +2169,9 @@ APR_DECLARE(apr_status_t) apr_pool_create_unmanage
          */
         if ((rv = apr_thread_mutex_create(&pool->mutex,
                 APR_THREAD_MUTEX_NESTED, pool)) != APR_SUCCESS) {
+            /* Don't leak the (own) allocator created above eventually */
+            if (pool_allocator->owner == pool)
+                apr_allocator_destroy(pool_allocator);
             free(pool);
             return rv;
         }

Reply via email to