On Thu, Aug 7, 2025 at 8:19 AM <br...@apache.org> wrote:
>
> Author: brane
> Date: Thu Aug  7 06:19:52 2025
> New Revision: 1927658
>
> Log:
> Fix pool debugging. With lifetime or owner checks enabled, pools couldn't
> even be created, except for the global pool which is a special case.
>
> * memory/unix/apr_pools.c
>   (struct apr_pool_t): Add an 'unmanaged' member for pool-debug mode.
>    The lifetime checks must be skipped for unmanaged pools, since they
>    inevitably fail: apr_pool_is_child_of() expects all pools to have a
>    parent, which obviously is not the case for unmanaged pools.
>
>   (apr_pool_create_ex_debug): Create the pool's mutex after the parent
>    has been assigned, because that involves an allocation which triggers
>    a lifetime check which ... well, see above.
>
>   (apr_pool_create_unmanaged): Set the pool->unmanaged flag and create the
>    pool's mutex after the owner and allocator have been assigned. A pool
>    without the owner set fails the ownershhip check, and without an
>    allocator it's sort of hard to allocate space for the mutex.
>
> Modified:
>    apr/apr/trunk/memory/unix/apr_pools.c
[]
> --- apr/apr/trunk/memory/unix/apr_pools.c       Thu Aug  7 05:08:51 2025      
>   (r1927657)
> +++ apr/apr/trunk/memory/unix/apr_pools.c       Thu Aug  7 06:19:52 2025      
>   (r1927658)
[]
> @@ -2063,6 +2065,22 @@ APR_DECLARE(apr_status_t) apr_pool_creat
>      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;

Here we might fail and need to rewind the above if parent != NULL,
maybe something like this:

Index: memory/unix/apr_pools.c
===================================================================
--- memory/unix/apr_pools.c    (revision 1927913)
+++ memory/unix/apr_pools.c    (working copy)
@@ -2095,7 +2095,15 @@ APR_DECLARE(apr_status_t) apr_pool_create_ex_debug
          */
         if ((rv = apr_thread_mutex_create(&pool->mutex,
                 APR_THREAD_MUTEX_NESTED, pool)) != APR_SUCCESS) {
-            free(pool);
+            /* Unwind parent binding from above eventually */
+            if (parent) {
+                pool_lock(parent);
+                pool_destroy_debug(pool, file_line);
+                pool_unlock(parent);
+            }
+            else {
+                free(pool);
+            }
             return rv;
         }
     }
?

[]
> @@ -2130,11 +2132,30 @@ APR_DECLARE(apr_status_t) apr_pool_creat
>
>      memset(pool, 0, SIZEOF_POOL_T);
>
> +    pool->unmanaged = 1;
>      pool->abort_fn = abort_fn;
>      pool->tag = file_line;
>      pool->file_line = file_line;
>
>  #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 ((pool_allocator = allocator) == NULL) {
> +        apr_status_t rv;
> +        if ((rv = apr_allocator_create(&pool_allocator)) != APR_SUCCESS) {
> +            if (abort_fn)
> +                abort_fn(rv);
> +            return rv;
> +        }
> +        pool_allocator->owner = pool;
> +    }
> +    pool->allocator = pool_allocator;
> +
> +#if APR_HAS_THREADS
>      {
>          apr_status_t rv;

Likewise here we need to destroy pool_allocator eventually on failure,
something like this:

Index: memory/unix/apr_pools.c
===================================================================
--- memory/unix/apr_pools.c    (revision 1927913)
+++ memory/unix/apr_pools.c    (working copy)
@@ -2169,6 +2177,10 @@ 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 own allocator created above eventually */
+            if (pool_allocator->owner == pool) {
+                apr_allocator_destroy(pool_allocator);
+            }
             free(pool);
             return rv;
         }
?


Regards;
Yann.

Reply via email to