]> granicus.if.org Git - postgresql/commitdiff
Fix regex match failures for backrefs combined with non-greedy quantifiers.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 19 Jul 2013 01:22:43 +0000 (21:22 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 19 Jul 2013 01:22:43 +0000 (21:22 -0400)
An ancient logic error in cfindloop() could cause the regex engine to fail
to find matches that begin later than the start of the string.  This
function is only used when the regex pattern contains a back reference,
and so far as we can tell the error is only reachable if the pattern is
non-greedy (i.e. its first quantifier uses the ? modifier).  Furthermore,
the actual match must begin after some potential match that satisfies the
DFA but then fails the back-reference's match test.

Reported and fixed by Jeevan Chalke, with cosmetic adjustments by me.

src/backend/regex/regexec.c
src/test/regress/expected/regex.out
src/test/regress/sql/regex.sql

index 3748a9c1714d67f97eee79c3f51baa73069c1327..78ebdee39e443dc89a211d8439e5513330ae4d92 100644 (file)
@@ -487,19 +487,21 @@ cfindloop(struct vars * v,
                                        *coldp = cold;
                                        return er;
                                }
-                               if ((shorter) ? end == estop : end == begin)
-                               {
-                                       /* no point in trying again */
-                                       *coldp = cold;
-                                       return REG_NOMATCH;
-                               }
-                               /* go around and try again */
+                               /* try next shorter/longer match with same begin point */
                                if (shorter)
+                               {
+                                       if (end == estop)
+                                               break;  /* NOTE BREAK OUT */
                                        estart = end + 1;
+                               }
                                else
+                               {
+                                       if (end == begin)
+                                               break;  /* NOTE BREAK OUT */
                                        estop = end - 1;
-                       }
-               }
+                               }
+                       }                                       /* end loop over endpoint positions */
+               }                                               /* end loop over beginning positions */
        } while (close < v->stop);
 
        *coldp = cold;
index 757f2a4028a36849d19160870a2f973a74ff1c17..df39ef937dd4040a5b2d2cb0bbcea77bc534d30b 100644 (file)
@@ -173,3 +173,18 @@ select 'a' ~ '((((((a+|)+|)+|)+|)+|)+|)';
  t
 (1 row)
 
+-- Test backref in combination with non-greedy quantifier
+-- https://core.tcl.tk/tcl/tktview/6585b21ca8fa6f3678d442b97241fdd43dba2ec0
+select 'Programmer' ~ '(\w).*?\1' as t;
+ t 
+---
+ t
+(1 row)
+
+select regexp_matches('Programmer', '(\w)(.*?\1)', 'g');
+ regexp_matches 
+----------------
+ {r,ogr}
+ {m,m}
+(2 rows)
+
index 1426562119a8e3bbd2cc8cb4d64db0016e2eafec..e5f690263b9c2002ff707ff7fd4337f2fc837fb0 100644 (file)
@@ -41,3 +41,8 @@ select 'a' ~ '($|^)*';
 -- Test for infinite loop in fixempties() (Tcl bugs 3604074, 3606683)
 select 'a' ~ '((((((a)*)*)*)*)*)*';
 select 'a' ~ '((((((a+|)+|)+|)+|)+|)+|)';
+
+-- Test backref in combination with non-greedy quantifier
+-- https://core.tcl.tk/tcl/tktview/6585b21ca8fa6f3678d442b97241fdd43dba2ec0
+select 'Programmer' ~ '(\w).*?\1' as t;
+select regexp_matches('Programmer', '(\w)(.*?\1)', 'g');