question on how to correctly communicate with external library functions which return malloc()'ed strings

Поиск
Список
Период
Сортировка
От Vladimir Volovich
Тема question on how to correctly communicate with external library functions which return malloc()'ed strings
Дата
Msg-id 871w5d86r6.fsf@external.prs-office.com
обсуждение исходный текст
Ответы Re: question on how to correctly communicate with external library functions which return malloc()'ed strings  (Martijn van Oosterhout <kleptog@svana.org>)
Список pgsql-hackers
Hi!

i'm using a module for postgresql (8.2 and 8.3) which links with a
3rd-party library and calls a function from there which returns a
malloc()'ed string.

[it's a libunac, and unac_string() but the question is general]

there was a pg_unac-8.2.tar.gz tarball distributed on the net, which has
the following implementation:

=============================================
Datum unac(PG_FUNCTION_ARGS) {
 text *str = PG_GETARG_TEXT_P(0); text *result;  int tlen, nlen, rsize; char *tstr, *nstr, *rptr;  tlen = VARSIZE(str)
-VARHDRSZ; tstr = (char *) palloc(tlen + 1); memcpy(tstr, VARDATA(str), tlen); tstr[tlen] = '\0';
 
 nstr = NULL; nlen = 0; unac_string("UTF-8", tstr, strlen(tstr), &nstr, &nlen);
 /* It may happen that unac_string returns NULL, because iconv  * can't translate the input string. In this case we
output * the string as it is. */ if (nstr == NULL) nstr = tstr;  rsize = strlen(nstr) + VARHDRSZ; result = (text *)
palloc(rsize);rptr =  VARDATA(result); memcpy(rptr, nstr, rsize - VARHDRSZ); SET_VARSIZE(result, rsize);
PG_RETURN_TEXT_P(result);
 
}
=============================================

clearly there's a memory leak here: nstr never gets free()'d:
its value is copied to a palloc()-ated string but nstr itself is
never free()'d.

this call to palloc() appears to be necessary because one cannot just
pass malloc()-created nstr as a result of a function - there will be a
segfault, as far as i remember; therefore one needs to copy nstr to a
palloc()-created string and then to free() nstr (which is missing in the
above code).

i had to modify that function to remove the memory leak and to add some
more functionality i needed.

in a simplified form, it looks like:

============================================= /* tstr is a palloc()'ed string */ size_t nlen = 0; char *nstr = NULL;
unac_string("UTF-8",tstr, strlen(tstr), &nstr, &nlen); if (nstr == NULL) {   nstr = strdup(tstr); } pfree(tstr); result
=(text *) palloc(strlen(nstr) + VARHDRSZ); memcpy(VARDATA(result), nstr, strlen(nstr));
 
#if PG_VERSION_NUM >= 80300 SET_VARSIZE(result, strlen(nstr) + VARHDRSZ);
#else VARATT_SIZEP(result) = strlen(nstr) + VARHDRSZ;
#endif free(nstr); PG_RETURN_TEXT_P(result);
=============================================

it worked fine with postgresql 8.2; with 8.3 it started segfaulting, and
it appeared that the reason is because in postgresql 8.3, the "free" is
a macro defined in
snowball/header.h:
#define free(a) pfree(a)

i solved it by adding these lines:

#ifdef free
#warning undefining free
#undef free
#endif
#include <stdlib.h>

but i want to ask you, postgresql hackers, on how we are supposed to
work with external library functions which return malloc()'ed strings?

should we create palloc()'ed copy and free() the original string?
then, is it correct to have that "#define free(a) pfree(a)" in
snowball/header.h?

Best,
v.



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

Предыдущее
От: Magnus Hagander
Дата:
Сообщение: Re: Commit fest queue
Следующее
От: Bernd Helmle
Дата:
Сообщение: Re: Separate psql commands from arguments