Commit 2a4c46e0 authored by Tom Lane's avatar Tom Lane

Fix array overrun in regex code.

zaptreesubs() was coded to unconditionally reset a capture subre's
corresponding pmatch[] entry.  However, in regexes without backrefs, that
array is caller-supplied and might not have as many entries as the regex
has capturing parens.  So check the array length and do nothing if there
is no corresponding entry, much as subset() does.  Failure to check this
resulted in a stack clobber in the case reported by Marko Kreen.

This bug appears to have been latent in the regex library from the
beginning.  It was not exposed because find() called dissect() not
cdissect(), and the dissect() code path didn't ever call zaptreesubs()
(formerly zapmem()).  When I unified dissect() and cdissect() in commit
4dd78bf3, the problem was exposed.

Now that I've seen this, I'm rather suspicious that we might need to
back-patch it; but will refrain for now, for lack of evidence that
the case can be hit in the previous coding.
parent ace397e9
......@@ -531,9 +531,14 @@ zaptreesubs(struct vars * v,
{
if (t->op == '(')
{
assert(t->subno > 0);
v->pmatch[t->subno].rm_so = -1;
v->pmatch[t->subno].rm_eo = -1;
int n = t->subno;
assert(n > 0);
if ((size_t) n < v->nmatch)
{
v->pmatch[n].rm_so = -1;
v->pmatch[n].rm_eo = -1;
}
}
if (t->left != NULL)
......@@ -543,7 +548,7 @@ zaptreesubs(struct vars * v,
}
/*
* subset - set any subexpression relevant to a successful subre
* subset - set subexpression match data for a successful subre
*/
static void
subset(struct vars * v,
......
......@@ -71,3 +71,22 @@ select 'abc abc abd' ~ '^(.+)( \1)+$' as f;
f
(1 row)
-- Test some cases that crashed in 9.2beta1 due to pmatch[] array overrun
select substring('asd TO foo' from ' TO (([a-z0-9._]+|"([^"]+|"")+")+)');
substring
-----------
foo
(1 row)
select substring('a' from '((a))+');
substring
-----------
a
(1 row)
select substring('a' from '((a)+)');
substring
-----------
a
(1 row)
......@@ -19,3 +19,8 @@ select 'abc abc abd' ~ '^(\w+)( \1)+$' as f;
select 'abc abc abc' ~ '^(.+)( \1)+$' as t;
select 'abc abd abc' ~ '^(.+)( \1)+$' as f;
select 'abc abc abd' ~ '^(.+)( \1)+$' as f;
-- Test some cases that crashed in 9.2beta1 due to pmatch[] array overrun
select substring('asd TO foo' from ' TO (([a-z0-9._]+|"([^"]+|"")+")+)');
select substring('a' from '((a))+');
select substring('a' from '((a)+)');
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment