leaks in TopMemoryContext?

Поиск
Список
Период
Сортировка
От Neil Conway
Тема leaks in TopMemoryContext?
Дата
Msg-id 1136965537.9143.71.camel@localhost.localdomain
обсуждение исходный текст
Ответы Re: leaks in TopMemoryContext?  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-hackers
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.)



В списке pgsql-hackers по дате отправления:

Предыдущее
От: Tom Lane
Дата:
Сообщение: Re: Is Optimizer smart enough?
Следующее
От: Tom Lane
Дата:
Сообщение: Re: leaks in TopMemoryContext?