8000 Fix two low-probability memory leaks in regular expression parsing. · patchsoft/postgres@e0a2337 · GitHub
[go: up one dir, main page]

Skip to content

Commit e0a2337

Browse files
committed
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.
1 parent 4b76778 commit e0a2337

File tree

1 file changed

+24
-7
lines changed

1 file changed

+24
-7
lines changed

src/backend/regex/regcomp.c

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1646,8 +1646,9 @@ freesrnode(struct vars * v, /* might be NULL */
16461646
freecnfa(&sr->cnfa);
16471647
sr->flags = 0;
16481648

1649-
if (v != NULL)
1649+
if (v != NULL && v->treechain != NULL)
16501650
{
1651+
/* we're still parsing, maybe we can reuse the subre */
16511652
sr->left = v->treefree;
16521653
v->treefree = sr;
16531654
}
@@ -1693,6 +1694,20 @@ numst(struct subre * t,
16931694

16941695
/*
16951696
* markst - mark tree nodes as INUSE
1697+
*
1698+
* Note: this is a great deal more subtle than it looks. During initial
1699+
* parsing of a regex, all subres are linked into the treechain list;
1700+
* discarded ones are also linked into the treefree list for possible reuse.
1701+
* After we are done creating all subres required for a regex, we run markst()
1702+
* then cleanst(), which results in discarding all subres not reachable from
1703+
* v->tree. We then clear v->treechain, indicating that subres must be found
1704+
* by descending from v->tree. This changes the behavior of freesubre(): it
1705+
* will henceforth FREE() unwanted subres rather than sticking them into the
1706+
* treefree list. (Doing that any earlier would result in dangling links in
1707+
* the treechain list.) This all means that freev() will clean up correctly
1708+
* if invoked before or after markst()+cleanst(); but it would not work if
1709+
* called partway through this state conversion, so we mustn't error out
1710+
* in or between these two functions.
16961711
*/
16971712
static void
16981713
markst(struct subre * t)
@@ -1790,25 +1805,27 @@ newlacon(struct vars * v,
17901805
int pos)
17911806
{
17921807
int n;
1808+
struct subre *newlacons;
17931809
struct subre *sub;
17941810

17951811
if (v->nlacons == 0)
17961812
{
1797-
v->lacons = (struct subre *) MALLOC(2 * sizeof(struct subre));
17981813
n = 1; /* skip 0th */
1799-
v->nlacons = 2;
1814+
newlacons = (struct subre *) MALLOC(2 * sizeof(struct subre));
18001815
}
18011816
else
18021817
{
1803-
v->lacons = (struct subre *) REALLOC(v->lacons,
1804-
(v->nlacons + 1) * sizeof(struct subre));
1805-
n = v->nlacons++;
1818+
n = v->nlacons;
1819+
newlacons = (struct subre *) REALLOC(v->lacons,
1820+
(n + 1) * sizeof(struct subre));
18061821
}
1807-
if (v->lacons == NULL)
1822+
if (newlacons == NULL)
18081823
{
18091824
ERR(REG_ESPACE);
18101825
return 0;
18111826
}
1827+
v->lacons = newlacons;
1828+
v->nlacons = n + 1;
18121829
sub = &v->lacons[n];
18131830
sub->begin = begin;
18141831
sub->end = end;

0 commit comments

Comments
 (0)
0