On 2/27/06, Branko Èibej <brane@xbc.nu> wrote:
>
> Here's the problem:
>
> * We have a global cache of open BDB environment descriptors. This
> cache is of course allocated from a (global) pool, and each
> descriptor gets its own subpool. The cached descriptors are
> reference-counted.
> * Each svn_fs_t owns a handle to one of these descriptors. These
> handles (actually, their allocators and pool cleanups) manage the
> descriptor reference counts.
>
> So far so good. Everything works beautifully, no memory leaks anywhere.
> Sheer paradise ...
>
> ... except for one nasty problem. The global pool for the cache can be
> created *after* the first svn_fs_t is allocated (from a different pool).
> Because we have no requirement about library initialization order in
> 1.x, we can only create the cache when it's first needed, not, say, just
> after apr_initialize.
>
> The consequence is that, when we hit apr_terminate, the cache's pool can
> be destroyed before the pool that contains the svn_fs_t that refers to
> the cache; that's because APR destroys its (global) pools in LIFO order.
> Unfortunately that means that during destruction of the svn_fs_t, we try
> to access memory that's already been freed.
>
> I've pretty much convinced myself that this can only happen during
> apr_terminate, but that's not much help, because it can still
> potentially cause a crash (or worse).
>
> I can't change the pool cleanup order short of a) hacking the pool
> structure directly (eek!), or b) requiring that svn_fs_initialize be
> called right after apr_initialize (ook ... er, that is, impossible).
>
> I've considered using malloc to allocate the descriptors, but i'd still
> need a pool per descriptor for open file handles, utf8->native
> translation of database paths, etc.
>
>
> I'm sure that, with all the brainpower on this list, someone will come
> up with a trivially elegant solution to this problem.
>
> So ... any bright ideas?
How about double-indirection pointers?
When the svn_fs_t takes an element from the cache, have the svn_fs_t leave a
pointer back to that svn_fs_t's pointer within the cache item. This allows
the cache pool cleanup to NULL the pointer back in the original svn_fs_t.
When the svn_fs_t goes to cleanup, if it sees that the pointer is NULL, it
knows that it already cleaned up and not to access any of the memory
associated with the cached item. -- justin
Received on Tue Feb 28 08:15:54 2006