Bojan Smojver
Thu, 17 Jul 2008 18:21:38 -0700
On Thu, 2008-07-17 at 13:59 +0200, Mladen Turk wrote: > So the destructor *must not* call apr_pool_destroy(subpool) > if the parent pool is inside apr_pool_destroy (tricky). You're right. In fact, this is the situation regardless of how the cleanup is registered (pre or not). The attached program crashes (double free) with or without that change. PS. I don't have any apps that actually do this, but some people may think it's OK to do this kind of thing, which makes me worried. PPS. The situation I was referring to in my previous e-mails cannot actually happen. R always outlives S. -- Bojan
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <apr.h>
#include <apr_pools.h>
#include <apr_strings.h>
#include <apr_reslist.h>
struct res{
apr_pool_t *p;
char *r;
};
struct sres{
struct res *r; /* parent resource */
char *s;
};
static apr_status_t res_clean(void *data){
struct res *r=data;
free(r->r);
r->r=NULL;
return APR_SUCCESS;
}
static apr_status_t sub_clean(void *data){
struct sres *s=data;
/* use parent resource a bit */
printf("%s\n",s->r->r);
free(s->s);
s->s=NULL;
return APR_SUCCESS;
}
static apr_status_t con(void **res,void *parm,apr_pool_t *pool){
apr_pool_t *rpool,*spool;
struct res **r=(struct res **)res;
struct sres *s;
apr_pool_create(&rpool,pool);
*r=apr_pcalloc(rpool,sizeof(**r));
(*r)->p=rpool;
(*r)->r=malloc(5);
memcpy((*r)->r,"data",5);
apr_pool_cleanup_register(rpool,*r,res_clean,apr_pool_cleanup_null);
apr_pool_create(&spool,rpool);
s=apr_pcalloc(spool,sizeof(*s));
s->r=*r;
s->s=malloc(5);
memcpy(s->s,"data",5);
apr_pool_cleanup_register(spool,s,sub_clean,apr_pool_cleanup_null);
return APR_SUCCESS;
}
static apr_status_t de(void *res,void *parm,apr_pool_t *pool){
struct res *r=res;
apr_pool_destroy(r->p);
return APR_SUCCESS;
}
int main(int argc,char **argv){
int i;
struct res *r;
apr_pool_t *pool;
apr_reslist_t *list;
apr_initialize();
apr_pool_create(&pool,NULL);
apr_reslist_create(&list,0,0,10,0,con,de,NULL,pool);
for(i=0;i<10;i++)
apr_reslist_acquire(list,(void **)&r);
for(i=0;i<10;i++)
apr_reslist_release(list,r);
apr_terminate();
return 0;
}