]> granicus.if.org Git - postgresql/commitdiff
Reduce an unnecessary O(N^3) loop in lexer.
authorAndrew Gierth <rhodiumtoad@postgresql.org>
Thu, 23 Aug 2018 19:00:12 +0000 (20:00 +0100)
committerAndrew Gierth <rhodiumtoad@postgresql.org>
Thu, 23 Aug 2018 20:33:55 +0000 (21:33 +0100)
The lexer's handling of operators contained an O(N^3) hazard when
dealing with long strings of + or - characters; it seems hard to
prevent this case from being O(N^2), but the additional N multiplier
was not needed.

Backpatch all the way since this has been there since 7.x, and it
presents at least a mild hazard in that trying to do Bind, PREPARE or
EXPLAIN on a hostile query could take excessive time (without
honouring cancels or timeouts) even if the query was never executed.

src/backend/parser/scan.l
src/bin/psql/psqlscan.l
src/interfaces/ecpg/preproc/pgc.l

index aa8299d69ef959d6d9d503cbf02bc80e5a9a1193..bcc6a91e044155eeb9155e43fdbdcfa217a6f4ea 100644 (file)
@@ -877,20 +877,33 @@ other                     .
                                         * to forbid operator names like '?-' that could not be
                                         * sequences of SQL operators.
                                         */
-                                       while (nchars > 1 &&
-                                                  (yytext[nchars-1] == '+' ||
-                                                       yytext[nchars-1] == '-'))
+                                       if (nchars > 1 &&
+                                               (yytext[nchars - 1] == '+' ||
+                                                yytext[nchars - 1] == '-'))
                                        {
                                                int             ic;
 
-                                               for (ic = nchars-2; ic >= 0; ic--)
+                                               for (ic = nchars - 2; ic >= 0; ic--)
                                                {
-                                                       if (strchr("~!@#^&|`?%", yytext[ic]))
+                                                       char c = yytext[ic];
+                                                       if (c == '~' || c == '!' || c == '@' ||
+                                                               c == '#' || c == '^' || c == '&' ||
+                                                               c == '|' || c == '`' || c == '?' ||
+                                                               c == '%')
                                                                break;
                                                }
-                                               if (ic >= 0)
-                                                       break; /* found a char that makes it OK */
-                                               nchars--; /* else remove the +/-, and check again */
+                                               if (ic < 0)
+                                               {
+                                                       /*
+                                                        * didn't find a qualifying character, so remove
+                                                        * all trailing [+-]
+                                                        */
+                                                       do {
+                                                               nchars--;
+                                                       } while (nchars > 1 &&
+                                                                (yytext[nchars - 1] == '+' ||
+                                                                 yytext[nchars - 1] == '-'));
+                                               }
                                        }
 
                                        SET_YYLLOC();
index dc727f7b71a7cb289efeed6e8c37f9f1506a5ef0..cde09c3e9c83f2112f1e1c71755a6b6ac314261a 100644 (file)
@@ -835,20 +835,33 @@ other                     .
                                         * to forbid operator names like '?-' that could not be
                                         * sequences of SQL operators.
                                         */
-                                       while (nchars > 1 &&
-                                                  (yytext[nchars-1] == '+' ||
-                                                       yytext[nchars-1] == '-'))
+                                       if (nchars > 1 &&
+                                               (yytext[nchars - 1] == '+' ||
+                                                yytext[nchars - 1] == '-'))
                                        {
                                                int             ic;
 
-                                               for (ic = nchars-2; ic >= 0; ic--)
+                                               for (ic = nchars - 2; ic >= 0; ic--)
                                                {
-                                                       if (strchr("~!@#^&|`?%", yytext[ic]))
+                                                       char c = yytext[ic];
+                                                       if (c == '~' || c == '!' || c == '@' ||
+                                                               c == '#' || c == '^' || c == '&' ||
+                                                               c == '|' || c == '`' || c == '?' ||
+                                                               c == '%')
                                                                break;
                                                }
-                                               if (ic >= 0)
-                                                       break; /* found a char that makes it OK */
-                                               nchars--; /* else remove the +/-, and check again */
+                                               if (ic < 0)
+                                               {
+                                                       /*
+                                                        * didn't find a qualifying character, so remove
+                                                        * all trailing [+-]
+                                                        */
+                                                       do {
+                                                               nchars--;
+                                                       } while (nchars > 1 &&
+                                                                (yytext[nchars - 1] == '+' ||
+                                                                 yytext[nchars - 1] == '-'));
+                                               }
                                        }
 
                                        if (nchars < yyleng)
index 5ac1ca8ae492b433e79e2821370a43c53c2b7024..1ce5ae5cf51217c059ce69a1177a33b84c5a450e 100644 (file)
@@ -687,20 +687,33 @@ cppline                   {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})(.*\\{space})*.
                                                 * to forbid operator names like '?-' that could not be
                                                 * sequences of SQL operators.
                                                 */
-                                               while (nchars > 1 &&
-                                                          (yytext[nchars-1] == '+' ||
-                                                               yytext[nchars-1] == '-'))
+                                               if (nchars > 1 &&
+                                                       (yytext[nchars - 1] == '+' ||
+                                                        yytext[nchars - 1] == '-'))
                                                {
                                                        int             ic;
 
-                                                       for (ic = nchars-2; ic >= 0; ic--)
+                                                       for (ic = nchars - 2; ic >= 0; ic--)
                                                        {
-                                                               if (strchr("~!@#^&|`?%", yytext[ic]))
+                                                               char c = yytext[ic];
+                                                               if (c == '~' || c == '!' || c == '@' ||
+                                                                       c == '#' || c == '^' || c == '&' ||
+                                                                       c == '|' || c == '`' || c == '?' ||
+                                                                       c == '%')
                                                                        break;
                                                        }
-                                                       if (ic >= 0)
-                                                               break; /* found a char that makes it OK */
-                                                       nchars--; /* else remove the +/-, and check again */
+                                                       if (ic < 0)
+                                                       {
+                                                               /*
+                                                                * didn't find a qualifying character, so remove
+                                                                * all trailing [+-]
+                                                                */
+                                                               do {
+                                                                       nchars--;
+                                                               } while (nchars > 1 &&
+                                                                        (yytext[nchars - 1] == '+' ||
+                                                                         yytext[nchars - 1] == '-'));
+                                                       }
                                                }
 
                                                if (nchars < yyleng)