From 9f1e642d50b30ec5c9604b6095073012a9a73e93 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 19 Oct 2015 13:54:53 -0700 Subject: [PATCH] Fix incorrect handling of lookahead constraints in pg_regprefix(). pg_regprefix was doing nothing with lookahead constraints, which would be fine if it were the right kind of nothing, but it isn't: we have to terminate our search for a fixed prefix, not just pretend the LACON arc isn't there. Otherwise, if the current state has both a LACON outarc and a single plain-color outarc, we'd falsely conclude that the color represents an addition to the fixed prefix, and generate an extracted index condition that restricts the indexscan too much. (See added regression test case.) Terminating the search is conservative: we could traverse the LACON arc (thus assuming that the constraint can be satisfied at runtime) and then examine the outarcs of the linked-to state. But that would be a lot more work than it seems worth, because writing a LACON followed by a single plain character is a pretty silly thing to do. This makes a difference only in rather contrived cases, but it's a bug, so back-patch to all supported branches. --- src/backend/regex/regprefix.c | 10 ++++------ src/test/regress/expected/regex.out | 8 ++++++++ src/test/regress/sql/regex.sql | 1 + 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/backend/regex/regprefix.c b/src/backend/regex/regprefix.c index e78faf3996..ce41620a0b 100644 --- a/src/backend/regex/regprefix.c +++ b/src/backend/regex/regprefix.c @@ -162,14 +162,12 @@ findprefix(struct cnfa * cnfa, thiscolor = COLORLESS; for (ca = cnfa->states[st]; ca->co != COLORLESS; ca++) { - /* We ignore lookahead constraints */ - if (ca->co >= cnfa->ncolors) - continue; - /* We can also ignore BOS/BOL arcs */ + /* We can ignore BOS/BOL arcs */ if (ca->co == cnfa->bos[0] || ca->co == cnfa->bos[1]) continue; - /* ... but EOS/EOL arcs terminate the search */ - if (ca->co == cnfa->eos[0] || ca->co == cnfa->eos[1]) + /* ... but EOS/EOL arcs terminate the search, as do LACONs */ + if (ca->co == cnfa->eos[0] || ca->co == cnfa->eos[1] || + ca->co >= cnfa->ncolors) { thiscolor = COLORLESS; break; diff --git a/src/test/regress/expected/regex.out b/src/test/regress/expected/regex.out index 320f5e88c3..be151858a3 100644 --- a/src/test/regress/expected/regex.out +++ b/src/test/regress/expected/regex.out @@ -153,6 +153,14 @@ explain (costs off) select * from pg_proc where proname ~ '^(abc)?d'; Filter: (proname ~ '^(abc)?d'::text) (2 rows) +explain (costs off) select * from pg_proc where proname ~ '^abcd(x|(?=\w\w)q)'; + QUERY PLAN +------------------------------------------------------------------------ + Index Scan using pg_proc_proname_args_nsp_index on pg_proc + Index Cond: ((proname >= 'abcd'::name) AND (proname < 'abce'::name)) + Filter: (proname ~ '^abcd(x|(?=\w\w)q)'::text) +(3 rows) + -- Test for infinite loop in pullback() (CVE-2007-4772) select 'a' ~ '($|^)*'; ?column? diff --git a/src/test/regress/sql/regex.sql b/src/test/regress/sql/regex.sql index 5412f6e1c5..c59fa35f24 100644 --- a/src/test/regress/sql/regex.sql +++ b/src/test/regress/sql/regex.sql @@ -34,6 +34,7 @@ explain (costs off) select * from pg_proc where proname ~ '^abc+d'; explain (costs off) select * from pg_proc where proname ~ '^(abc)(def)'; explain (costs off) select * from pg_proc where proname ~ '^(abc)$'; explain (costs off) select * from pg_proc where proname ~ '^(abc)?d'; +explain (costs off) select * from pg_proc where proname ~ '^abcd(x|(?=\w\w)q)'; -- Test for infinite loop in pullback() (CVE-2007-4772) select 'a' ~ '($|^)*'; -- 2.40.0