On Wednesday 17 February 2010, Jeff Trawick wrote:
> > What about adding some code to apr-util's bucket debugging that
> > logs when destroyed brigades (i.e. where the pool cleanup has
> > been removed) are reused? I think this may be a common cause for
> > memory leaks.
> 
> as in something like this?
> 
>   apr_brigade_destroy(foo->bb)
>   ...
>   if (!foo->bb) {
>     foo->bb = apr_brigade_create();
>   }
>   ...
>   APR_BRIGADE_INSERT_TAIL(foo->bb, b);
>   /* no automatic cleanup of b */

Exactly. I have fixed a few of these in httpd trunk but I guess these 
can appear in third party modules, too. And 2.2.x has these problems, 
too.

One particular problem is that 2.2's core_output_filter may call 
apr_brigade_destroy() on brigades which have been passed down the 
filter chain and which may be later reused by the filter that has 
created them. I have attached an (untested) patch for this issue. A 
simpler variant would just change all three apr_brigade_destroy() 
calls to apr_brigade_cleanup().
Index: server/core_filters.c
===================================================================
--- server/core_filters.c	(Revision 910332)
+++ server/core_filters.c	(Arbeitskopie)
@@ -655,6 +655,8 @@
                             /* Create a temporary brigade as a means
                              * of concatenating a bunch of buckets together
                              */
+                            temp_brig = apr_brigade_create(f->c->pool,
+                                                       f->c->bucket_alloc);
                             if (last_merged_bucket) {
                                 /* If we've concatenated together small
                                  * buckets already in a previous pass,
@@ -667,16 +669,9 @@
                                  * these buckets, so that the content
                                  * in them doesn't have to be copied again.
                                  */
-                                apr_bucket_brigade *bb;
-                                bb = apr_brigade_split(b,
-                                         APR_BUCKET_NEXT(last_merged_bucket));
-                                temp_brig = b;
-                                b = bb;
+				APR_BRIGADE_PREPEND(b, temp_brig);
+				brigade_move(temp_brig, b, APR_BUCKET_NEXT(last_merged_bucket));
                             }
-                            else {
-                                temp_brig = apr_brigade_create(f->c->pool,
-                                                           f->c->bucket_alloc);
-                            }
 
                             temp = APR_BRIGADE_FIRST(b);
                             while (temp != e) {
@@ -879,7 +874,7 @@
                 logio_add_bytes_out(c, bytes_sent);
         }
 
-        apr_brigade_destroy(b);
+        apr_brigade_cleanup(b);
 
         /* drive cleanups for resources which were set aside
          * this may occur before or after termination of the request which
@@ -910,7 +905,7 @@
                           "core_output_filter: writing data to the network");
 
             if (more)
-                apr_brigade_destroy(more);
+                apr_brigade_cleanup(more);
 
             /* No need to check for SUCCESS, we did that above. */
             if (!APR_STATUS_IS_EAGAIN(rv)) {

Reply via email to