Like the situation with function cache loading, text search
dictionary loading functions tend to leak some cruft into the
dictionary's long-lived cache context. To judge by the examples in
the core regression tests, not very many bytes are at stake.
Moreover, I don't see a way to prevent such leaks without changing the
API for TS template initialization functions: right now they do not
have to worry about making sure that their results are long-lived.
Hence, I think we should install a suppression rule rather than trying
to fix this completely. However, I did grab some low-hanging fruit:
several places were leaking the result of get_tsearch_config_filename.
This seems worth doing mostly because they are inconsistent with other
dictionaries that were freeing it already.
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/285483.
1746756246@sss.pgh.pa.us
if (strcmp(defel->defname, "dictfile") == 0)
{
+ char *filename;
+
if (dictloaded)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("multiple DictFile parameters")));
- NIImportDictionary(&(d->obj),
- get_tsearch_config_filename(defGetString(defel),
- "dict"));
+ filename = get_tsearch_config_filename(defGetString(defel),
+ "dict");
+ NIImportDictionary(&(d->obj), filename);
+ pfree(filename);
dictloaded = true;
}
else if (strcmp(defel->defname, "afffile") == 0)
{
+ char *filename;
+
if (affloaded)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("multiple AffFile parameters")));
- NIImportAffixes(&(d->obj),
- get_tsearch_config_filename(defGetString(defel),
- "affix"));
+ filename = get_tsearch_config_filename(defGetString(defel),
+ "affix");
+ NIImportAffixes(&(d->obj), filename);
+ pfree(filename);
affloaded = true;
}
else if (strcmp(defel->defname, "stopwords") == 0)
}
tsearch_readline_end(&trst);
+ pfree(filename);
d->len = cur;
qsort(d->syn, d->len, sizeof(Syn), compareSyn);
static void
thesaurusRead(const char *filename, DictThesaurus *d)
{
+ char *real_filename = get_tsearch_config_filename(filename, "ths");
tsearch_readline_state trst;
uint32 idsubst = 0;
bool useasis = false;
char *line;
- filename = get_tsearch_config_filename(filename, "ths");
- if (!tsearch_readline_begin(&trst, filename))
+ if (!tsearch_readline_begin(&trst, real_filename))
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not open thesaurus file \"%s\": %m",
- filename)));
+ real_filename)));
while ((line = tsearch_readline(&trst)) != NULL)
{
d->nsubst = idsubst;
tsearch_readline_end(&trst);
+ pfree(real_filename);
}
static TheLexeme *
/*
* Init method runs in dictionary's private memory context, and we
- * make sure the options are stored there too
+ * make sure the options are stored there too. This typically
+ * results in a small amount of memory leakage, but it's not worth
+ * complicating the API for tmplinit functions to avoid it.
*/
oldcontext = MemoryContextSwitchTo(entry->dictCtx);
...
fun:cached_function_compile
}
+
+# Suppress complaints about stuff leaked during TS dictionary loading.
+# Not very much is typically lost there, and preventing it would
+# require a risky API change for TS tmplinit functions.
+{
+ hide_ts_dictionary_leaks
+ Memcheck:Leak
+ match-leak-kinds: definite,possible,indirect
+
+ ...
+ fun:lookup_ts_dictionary_cache
+}