From 2a4c46e0baf2d51117cd4468b28705d01ffcbff9 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 24 May 2012 13:56:16 -0400 Subject: [PATCH] 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 4dd78bf37aa29d04b3f358b08c4a2fa43cf828e7, 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. --- src/backend/regex/regexec.c | 13 +++++++++---- src/test/regress/expected/regex.out | 19 +++++++++++++++++++ src/test/regress/sql/regex.sql | 5 +++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/backend/regex/regexec.c b/src/backend/regex/regexec.c index c9c73e978b6..5d7415b3c1a 100644 --- a/src/backend/regex/regexec.c +++ b/src/backend/regex/regexec.c @@ -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, diff --git a/src/test/regress/expected/regex.out b/src/test/regress/expected/regex.out index 4acc4a47a03..dc0c713b408 100644 --- a/src/test/regress/expected/regex.out +++ b/src/test/regress/expected/regex.out @@ -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) + diff --git a/src/test/regress/sql/regex.sql b/src/test/regress/sql/regex.sql index b5315a3df6d..9fdcb2f5bd5 100644 --- a/src/test/regress/sql/regex.sql +++ b/src/test/regress/sql/regex.sql @@ -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)+)');