dev  

Re: svn commit: r677505 - /apr/apr-util/trunk/misc/apr_reslist.c

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;
}