Thread: leaks in TopMemoryContext?

leaks in TopMemoryContext?

From
Neil Conway
Date:
While thinking about how to do memory management for the TupleDesc
refcounting changes, it occurred to me that this coding pattern is
dangerous:

local_var = MemoryContextAlloc(TopMemoryContext, ...);
func_call();
/* ... */
/* update global state */
if (global != NULL)   pfree(global);
global = local_var;

the idea being that we're allocating some memory that should live longer
than the current transaction. For example, see circa line 141 in
mb/mbutils.c:SetClientEncoding().

This works fine if no error occurs: presumably, the code takes care of
releasing the allocation in TopMemoryContext when appropriate (as
mbutils.c does). The problem arises if there is an error: suppose that
func_call() in the example above elogs. The elog handler will abort the
current transaction and reset per-transaction memory contexts, but
TopMemoryContext will not be reset. Therefore the memory allocated for
"local_var" will be leaked.

To see the leak in practice, insert an elog(ERROR) in mbutils.c here:

line 141:oldcontext = MemoryContextSwitchTo(TopMemoryContext);to_server = palloc(sizeof(FmgrInfo));to_client =
palloc(sizeof(FmgrInfo));fmgr_info(to_server_proc,to_server);fmgr_info(to_client_proc, to_client);
 
>>>>>   elog(ERROR, "...");MemoryContextSwitchTo(oldcontext);

Running a stream of "SET client_encoding = 'koi8';" on my machine yields
a steady growth in the size of the TopMemoryContext.[1]

The elog(ERROR) above is inserted by hand to make the problem easier to
reproduce, but it is certainly possible for the calls to palloc() or
fmgr_info() to fail for legitimate reasons during normal usage (e.g. OOM
in the case of palloc(), or a multitude of reasons for fmgr_info()).

I'm not sure if there's a clean way to fix the problem. One solution
would be to enclose code that does allocations in TopMemoryContext in a
PG_TRY block. We could then pfree() the local variable in a PG_CATCH
block (provided that the "global = local_var" assignment hasn't occurred
yet). Unfortunately, that's pretty ugly, and requires adding hackery to
every site where this coding pattern occurs.

Thoughts?

-Neil

P.S. It occurs to me that the mbutils code is actually busted anyway, as
it assumes that a pfree'ing the FmgrInfo is sufficient to release all
the resources allocated by fmgr_info(). However, this is not the case:
the CurrentMemoryContext when fmgr_info() is called is used to allocate
additional things. mbutils ought to invoke fmgr_info() in its own
long-lived memory context -- but that is unrelated to the problem
described above...

[1] This codepath is only followed if the server_encoding is not
compatiable with the chosen client_encoding -- in my case
server_encoding = 'en_CA.utf8' reproduces the problem.)



Re: leaks in TopMemoryContext?

From
Tom Lane
Date:
Neil Conway <neilc@samurai.com> writes:
> Thoughts?

One comment is that there are worse things than small memory leaks in
seldom-followed code paths, especially if those paths are only taken in
error cases.  I'm interested in fixing this if it can be done without
unreasonable code complication, but there are limits to how far we
should go to do it.
        regards, tom lane


Re: leaks in TopMemoryContext?

From
Neil Conway
Date:
On Wed, 2006-01-11 at 02:58 -0500, Tom Lane wrote:
> One comment is that there are worse things than small memory leaks in
> seldom-followed code paths, especially if those paths are only taken in
> error cases.

While I agree the problem isn't a showstopper, I think it is still
worthy of concern: the mbutils example was chosen for being clearly
broken, not as being the most serious instance of the problem. The issue
might occur in *any* situation in which we're allocating memory in a
memory context whose lifetime exceeds the current transaction -- I
haven't looked to see what other places might need fixing.

-Neil




Re: leaks in TopMemoryContext?

From
Tom Lane
Date:
Neil Conway <neilc@samurai.com> writes:
> While I agree the problem isn't a showstopper, I think it is still
> worthy of concern: the mbutils example was chosen for being clearly
> broken, not as being the most serious instance of the problem. The issue
> might occur in *any* situation in which we're allocating memory in a
> memory context whose lifetime exceeds the current transaction -- I
> haven't looked to see what other places might need fixing.

There's very little code that runs in TopMemoryContext (by design), so
I don't think you'll find much.
        regards, tom lane