Hi,

I have, for debugging my own mistakes, hacked a bit in apr_pools.c (you know it 
would happen sooner or later, right?). I wanted to have easy checks for memory 
being overrun inside a pool where address sanitation will not find it. The idea 
is to add a guard at the beginning of a cleanup_t struct that is then checked 
when a pool is cleared/destroyed.

#define APR_CLEANUP_GUARD       0x55aa55aa55aa55aaL /* active guard */
#define APR_CLEANUP_CLEARED     0x11aa11aa11aa11aaL /* cleanup has run */
#define APR_CLEANUP_STOWED      0x3399339933993399L /* cleanup in free list */

struct cleanup_t {
  long guard;
  struct cleanup_t *next;
  const void *data;
  apr_status_t (*plain_cleanup_fn)(void *data);
  apr_status_t (*child_cleanup_fn)(void *data);
};

Since cleanup_t is a linked list and allocated from the pool just like any 
other memory, it can find itself sitting in various places. This can be used 
for checking boundaries of memory allocated just before. Insert a guarded dummy 
cleanup after another allocation and on pool destruction, you have the check. 
Another advantage is that this causes nearly no runtime overhead while the pool 
is in use. That helps with heisenbugs.

Now, there is consistency checking on the cleanup list during APR_POOL_DEBUG 
already, so the idea is certainly not new. However that will not help if a 
cleanup is NULLed at the start. My hack uses a magic value. And besides, I 
needed something that did not drag the whole POOL_DEBUG in at this time.

Besides apr_pool_cleanup_register(), we could in httpd also add a 
AP_DEBUG_ADD_GUARD(pool) macro that registers a dummy cleanup here and there in 
maintainer mode. In production, this would have no effect.

I am wondering what to do with my changes now. Since my hands are very full 
right now, I was wondering if someone here is interested in carrying this 
forward?

Cheers,

Stefan


Reply via email to