Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2dbfbd6

Browse files
committedAug 23, 2018
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 6953daf commit 2dbfbd6

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
@@ -881,20 +881,33 @@ other .
881881
* to forbid operator names like '?-' that could not be
882882
* sequences of SQL operators.
883883
*/
884-
while (nchars > 1 &&
885-
(yytext[nchars - 1] == '+' ||
886-
yytext[nchars - 1] == '-'))
884+
if (nchars > 1 &&
885+
(yytext[nchars - 1] == '+' ||
886+
yytext[nchars - 1] == '-'))
887887
{
888888
int ic;
889889

890890
for (ic = nchars - 2; ic >= 0; ic--)
891891
{
892-
if (strchr("~!@#^&|`?%", yytext[ic]))
892+
char c = yytext[ic];
893+
if (c == '~' || c == '!' || c == '@' ||
894+
c == '#' || c == '^' || c == '&' ||
895+
c == '|' || c == '`' || c == '?' ||
896+
c == '%')
893897
break;
894898
}
895-
if (ic >= 0)
896-
break; /* found a char that makes it OK */
897-
nchars--; /* else remove the +/-, and check again */
899+
if (ic < 0)
900+
{
901+
/*
902+
* didn't find a qualifying character, so remove
903+
* all trailing [+-]
904+
*/
905+
do {
906+
nchars--;
907+
} while (nchars > 1 &&
908+
(yytext[nchars - 1] == '+' ||
909+
yytext[nchars - 1] == '-'));
910+
}
898911
}
899912

900913
SET_YYLLOC();

‎src/fe_utils/psqlscan.l

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -800,20 +800,33 @@ other .
800800
* to forbid operator names like '?-' that could not be
801801
* sequences of SQL operators.
802802
*/
803-
while (nchars > 1 &&
804-
(yytext[nchars - 1] == '+' ||
805-
yytext[nchars - 1] == '-'))
803+
if (nchars > 1 &&
804+
(yytext[nchars - 1] == '+' ||
805+
yytext[nchars - 1] == '-'))
806806
{
807807
int ic;
808808

809809
for (ic = nchars - 2; ic >= 0; ic--)
810810
{
811-
if (strchr("~!@#^&|`?%", yytext[ic]))
811+
char c = yytext[ic];
812+
if (c == '~' || c == '!' || c == '@' ||
813+
c == '#' || c == '^' || c == '&' ||
814+
c == '|' || c == '`' || c == '?' ||
815+
c == '%')
812816
break;
813817
}
814-
if (ic >= 0)
815-
break; /* found a char that makes it OK */
816-
nchars--; /* else remove the +/-, and check again */
818+
if (ic < 0)
819+
{
820+
/*
821+
* didn't find a qualifying character, so remove
822+
* all trailing [+-]
823+
*/
824+
do {
825+
nchars--;
826+
} while (nchars > 1 &&
827+
(yytext[nchars - 1] == '+' ||
828+
yytext[nchars - 1] == '-'));
829+
}
817830
}
818831

819832
if (nchars < yyleng)

‎src/interfaces/ecpg/preproc/pgc.l

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

695-
for (ic = nchars-2; ic >= 0; ic--)
695+
for (ic = nchars - 2; ic >= 0; ic--)
696696
{
697-
if (strchr("~!@#^&|`?%", yytext[ic]))
697+
char c = yytext[ic];
698+
if (c == '~' || c == '!' || c == '@' ||
699+
c == '#' || c == '^' || c == '&' ||
700+
c == '|' || c == '`' || c == '?' ||
701+
c == '%')
698702
break;
699703
}
700-
if (ic >= 0)
701-
break; /* found a char that makes it OK */
702-
nchars--; /* else remove the +/-, and check again */
704+
if (ic < 0)
705+
{
706+
/*
707+
* didn't find a qualifying character, so remove
708+
* all trailing [+-]
709+
*/
710+
do {
711+
nchars--;
712+
} while (nchars > 1 &&
713+
(yytext[nchars - 1] == '+' ||
714+
yytext[nchars - 1] == '-'));
715+
}
703716
}
704717

705718
if (nchars < yyleng)

0 commit comments

Comments
 (0)
Failed to load comments.