Skip to content

Commit d4a63f8

Browse files
committed
Reduce an unnecessary O(N^3) loop in lexer.
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.
1 parent 5ca0077 commit d4a63f8

File tree

3 files changed

+61
-22
lines changed

3 files changed

+61
-22
lines changed

src/backend/parser/scan.l

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -885,20 +885,33 @@ other .
885885
* to forbid operator names like '?-' that could not be
886886
* sequences of SQL operators.
887887
*/
888-
while (nchars > 1 &&
889-
(yytext[nchars - 1] == '+' ||
890-
yytext[nchars - 1] == '-'))
888+
if (nchars > 1 &&
889+
(yytext[nchars - 1] == '+' ||
890+
yytext[nchars - 1] == '-'))
891891
{
892892
int ic;
893893

894894
for (ic = nchars - 2; ic >= 0; ic--)
895895
{
896-
if (strchr("~!@#^&|`?%", yytext[ic]))
896+
char c = yytext[ic];
897+
if (c == '~' || c == '!' || c == '@' ||
898+
c == '#' || c == '^' || c == '&' ||
899+
c == '|' || c == '`' || c == '?' ||
900+
c == '%')
897901
break;
898902
}
899-
if (ic >= 0)
900-
break; /* found a char that makes it OK */
901-
nchars--; /* else remove the +/-, and check again */
903+
if (ic < 0)
904+
{
905+
/*
906+
* didn't find a qualifying character, so remove
907+
* all trailing [+-]
908+
*/
909+
do {
910+
nchars--;
911+
} while (nchars > 1 &&
912+
(yytext[nchars - 1] == '+' ||
913+
yytext[nchars - 1] == '-'));
914+
}
902915
}
903916

904917
SET_YYLLOC();

src/fe_utils/psqlscan.l

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -817,20 +817,33 @@ other .
817817
* to forbid operator names like '?-' that could not be
818818
* sequences of SQL operators.
819819
*/
820-
while (nchars > 1 &&
821-
(yytext[nchars - 1] == '+' ||
822-
yytext[nchars - 1] == '-'))
820+
if (nchars > 1 &&
821+
(yytext[nchars - 1] == '+' ||
822+
yytext[nchars - 1] == '-'))
823823
{
824824
int ic;
825825

826826
for (ic = nchars - 2; ic >= 0; ic--)
827827
{
828-
if (strchr("~!@#^&|`?%", yytext[ic]))
828+
char c = yytext[ic];
829+
if (c == '~' || c == '!' || c == '@' ||
830+
c == '#' || c == '^' || c == '&' ||
831+
c == '|' || c == '`' || c == '?' ||
832+
c == '%')
829833
break;
830834
}
831-
if (ic >= 0)
832-
break; /* found a char that makes it OK */
833-
nchars--; /* else remove the +/-, and check again */
835+
if (ic < 0)
836+
{
837+
/*
838+
* didn't find a qualifying character, so remove
839+
* all trailing [+-]
840+
*/
841+
do {
842+
nchars--;
843+
} while (nchars > 1 &&
844+
(yytext[nchars - 1] == '+' ||
845+
yytext[nchars - 1] == '-'));
846+
}
834847
}
835848

836849
if (nchars < yyleng)

src/interfaces/ecpg/preproc/pgc.l

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -690,20 +690,33 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
690690
* to forbid operator names like '?-' that could not be
691691
* sequences of SQL operators.
692692
*/
693-
while (nchars > 1 &&
694-
(yytext[nchars-1] == '+' ||
695-
yytext[nchars-1] == '-'))
693+
if (nchars > 1 &&
694+
(yytext[nchars - 1] == '+' ||
695+
yytext[nchars - 1] == '-'))
696696
{
697697
int ic;
698698

699-
for (ic = nchars-2; ic >= 0; ic--)
699+
for (ic = nchars - 2; ic >= 0; ic--)
700700
{
701-
if (strchr("~!@#^&|`?%", yytext[ic]))
701+
char c = yytext[ic];
702+
if (c == '~' || c == '!' || c == '@' ||
703+
c == '#' || c == '^' || c == '&' ||
704+
c == '|' || c == '`' || c == '?' ||
705+
c == '%')
702706
break;
703707
}
704-
if (ic >= 0)
705-
break; /* found a char that makes it OK */
706-
nchars--; /* else remove the +/-, and check again */
708+
if (ic < 0)
709+
{
710+
/*
711+
* didn't find a qualifying character, so remove
712+
* all trailing [+-]
713+
*/
714+
do {
715+
nchars--;
716+
} while (nchars > 1 &&
717+
(yytext[nchars - 1] == '+' ||
718+
yytext[nchars - 1] == '-'));
719+
}
707720
}
708721

709722
if (nchars < yyleng)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy