aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2014-07-18 13:00:27 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2014-07-18 13:01:04 -0400
commite0a233744744d060fb07e25405bcc7dbba9c807f (patch)
treeba09ec2755f9b08eb59d904f53c33b16065959d3
parent4b767789d4b770d6eaf51467d8bbf7b516463083 (diff)
downloadpostgresql-e0a233744744d060fb07e25405bcc7dbba9c807f.tar.gz
postgresql-e0a233744744d060fb07e25405bcc7dbba9c807f.zip
Fix two low-probability memory leaks in regular expression parsing.
If pg_regcomp failed after having invoked markst/cleanst, it would leak any "struct subre" nodes it had created. (We've already detected all regex syntax errors at that point, so the only likely causes of later failure would be query cancel or out-of-memory.) To fix, make sure freesrnode knows the difference between the pre-cleanst and post-cleanst cleanup procedures. Add some documentation of this less-than-obvious point. Also, newlacon did the wrong thing with an out-of-memory failure from realloc(), so that the previously allocated array would be leaked. Both of these are pretty low-probability scenarios, but a bug is a bug, so patch all the way back. Per bug #10976 from Arthur O'Dwyer.
-rw-r--r--src/backend/regex/regcomp.c31
1 files changed, 24 insertions, 7 deletions
diff --git a/src/backend/regex/regcomp.c b/src/backend/regex/regcomp.c
index 3f0504789e6..6ae804034d4 100644
--- a/src/backend/regex/regcomp.c
+++ b/src/backend/regex/regcomp.c
@@ -1646,8 +1646,9 @@ freesrnode(struct vars * v, /* might be NULL */
freecnfa(&sr->cnfa);
sr->flags = 0;
- if (v != NULL)
+ if (v != NULL && v->treechain != NULL)
{
+ /* we're still parsing, maybe we can reuse the subre */
sr->left = v->treefree;
v->treefree = sr;
}
@@ -1693,6 +1694,20 @@ numst(struct subre * t,
/*
* markst - mark tree nodes as INUSE
+ *
+ * Note: this is a great deal more subtle than it looks. During initial
+ * parsing of a regex, all subres are linked into the treechain list;
+ * discarded ones are also linked into the treefree list for possible reuse.
+ * After we are done creating all subres required for a regex, we run markst()
+ * then cleanst(), which results in discarding all subres not reachable from
+ * v->tree. We then clear v->treechain, indicating that subres must be found
+ * by descending from v->tree. This changes the behavior of freesubre(): it
+ * will henceforth FREE() unwanted subres rather than sticking them into the
+ * treefree list. (Doing that any earlier would result in dangling links in
+ * the treechain list.) This all means that freev() will clean up correctly
+ * if invoked before or after markst()+cleanst(); but it would not work if
+ * called partway through this state conversion, so we mustn't error out
+ * in or between these two functions.
*/
static void
markst(struct subre * t)
@@ -1790,25 +1805,27 @@ newlacon(struct vars * v,
int pos)
{
int n;
+ struct subre *newlacons;
struct subre *sub;
if (v->nlacons == 0)
{
- v->lacons = (struct subre *) MALLOC(2 * sizeof(struct subre));
n = 1; /* skip 0th */
- v->nlacons = 2;
+ newlacons = (struct subre *) MALLOC(2 * sizeof(struct subre));
}
else
{
- v->lacons = (struct subre *) REALLOC(v->lacons,
- (v->nlacons + 1) * sizeof(struct subre));
- n = v->nlacons++;
+ n = v->nlacons;
+ newlacons = (struct subre *) REALLOC(v->lacons,
+ (n + 1) * sizeof(struct subre));
}
- if (v->lacons == NULL)
+ if (newlacons == NULL)
{
ERR(REG_ESPACE);
return 0;
}
+ v->lacons = newlacons;
+ v->nlacons = n + 1;
sub = &v->lacons[n];
sub->begin = begin;
sub->end = end;