Re: svn commit: r1927658 - apr/apr/trunk/memory/unix

Branko Čibej <[email protected]> Wed, 20 Aug 2025 16:19:59 +0200
Newsgroups gmane.comp.apache.apr.devel
Organization The Apache Software Foundation
Message-ID <[email protected]>
On 20. 8. 25 14:56, Yann Ylavic wrote:
> On Thu, Aug 7, 2025 at 8:19 AM<[email protected]> 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;
>           }
> ?
>


I'll check. I didn't dig that deep, I only moved the code around so that 
the data dependencies lined up.

-- Brane