Skip to content

Commit e22cf06

Browse files
committed
Bug 700937: Limit recursion in regexp matcher.
Also handle negative return code as an error in the JS bindings.
1 parent ddcdca8 commit e22cf06

File tree

3 files changed

+66
-35
lines changed

3 files changed

+66
-35
lines changed

jsregexp.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ void js_newregexp(js_State *J, const char *pattern, int flags)
2929

3030
void js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text)
3131
{
32+
int result;
3233
int i;
3334
int opts;
3435
Resub m;
@@ -46,7 +47,10 @@ void js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text)
4647
}
4748
}
4849

49-
if (!js_regexec(re->prog, text, &m, opts)) {
50+
result = js_regexec(re->prog, text, &m, opts);
51+
if (result < 0)
52+
js_error(J, "regexec failed");
53+
if (result == 0) {
5054
js_newarray(J);
5155
js_pushstring(J, text);
5256
js_setproperty(J, -2, "input");
@@ -71,6 +75,7 @@ static void Rp_test(js_State *J)
7175
{
7276
js_Regexp *re;
7377
const char *text;
78+
int result;
7479
int opts;
7580
Resub m;
7681

@@ -90,7 +95,10 @@ static void Rp_test(js_State *J)
9095
}
9196
}
9297

93-
if (!js_regexec(re->prog, text, &m, opts)) {
98+
result = js_regexec(re->prog, text, &m, opts);
99+
if (result < 0)
100+
js_error(J, "regexec failed");
101+
if (result == 0) {
94102
if (re->flags & JS_REGEXP_G)
95103
re->last = re->last + (m.sub[0].ep - text);
96104
js_pushboolean(J, 1);

jsstring.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44
#include "utf.h"
55
#include "regexp.h"
66

7+
static int js_doregexec(js_State *J, Reprog *prog, const char *string, Resub *sub, int eflags)
8+
{
9+
int result = js_regexec(prog, string, sub, eflags);
10+
if (result < 0)
11+
js_error(J, "regexec failed");
12+
return result;
13+
}
14+
715
static const char *checkstring(js_State *J, int idx)
816
{
917
if (!js_iscoercible(J, idx))
@@ -343,7 +351,7 @@ static void Sp_match(js_State *J)
343351
a = text;
344352
e = text + strlen(text);
345353
while (a <= e) {
346-
if (js_regexec(re->prog, a, &m, a > text ? REG_NOTBOL : 0))
354+
if (js_doregexec(J, re->prog, a, &m, a > text ? REG_NOTBOL : 0))
347355
break;
348356

349357
b = m.sub[0].sp;
@@ -380,7 +388,7 @@ static void Sp_search(js_State *J)
380388

381389
re = js_toregexp(J, -1);
382390

383-
if (!js_regexec(re->prog, text, &m, 0))
391+
if (!js_doregexec(J, re->prog, text, &m, 0))
384392
js_pushnumber(J, js_utfptrtoidx(text, m.sub[0].sp));
385393
else
386394
js_pushnumber(J, -1);
@@ -397,7 +405,7 @@ static void Sp_replace_regexp(js_State *J)
397405
source = checkstring(J, 0);
398406
re = js_toregexp(J, 1);
399407

400-
if (js_regexec(re->prog, source, &m, 0)) {
408+
if (js_doregexec(J, re->prog, source, &m, 0)) {
401409
js_copy(J, 0);
402410
return;
403411
}
@@ -471,7 +479,7 @@ static void Sp_replace_regexp(js_State *J)
471479
else
472480
goto end;
473481
}
474-
if (!js_regexec(re->prog, source, &m, REG_NOTBOL))
482+
if (!js_doregexec(J, re->prog, source, &m, REG_NOTBOL))
475483
goto loop;
476484
}
477485

@@ -576,7 +584,7 @@ static void Sp_split_regexp(js_State *J)
576584

577585
/* splitting the empty string */
578586
if (e == text) {
579-
if (js_regexec(re->prog, text, &m, 0)) {
587+
if (js_doregexec(J, re->prog, text, &m, 0)) {
580588
if (len == limit) return;
581589
js_pushliteral(J, "");
582590
js_setindex(J, -2, 0);
@@ -586,7 +594,7 @@ static void Sp_split_regexp(js_State *J)
586594

587595
p = a = text;
588596
while (a < e) {
589-
if (js_regexec(re->prog, a, &m, a > text ? REG_NOTBOL : 0))
597+
if (js_doregexec(J, re->prog, a, &m, a > text ? REG_NOTBOL : 0))
590598
break; /* no match */
591599

592600
b = m.sub[0].sp;

regexp.c

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define REPINF 255
1717
#define MAXSUB REG_MAXSUB
1818
#define MAXPROG (32 << 10)
19+
#define MAXREC 1024
1920

2021
typedef struct Reclass Reclass;
2122
typedef struct Renode Renode;
@@ -967,98 +968,112 @@ static int strncmpcanon(const char *a, const char *b, int n)
967968
return 0;
968969
}
969970

970-
static int match(Reinst *pc, const char *sp, const char *bol, int flags, Resub *out)
971+
static int match(Reinst *pc, const char *sp, const char *bol, int flags, Resub *out, int depth)
971972
{
972973
Resub scratch;
974+
int result;
973975
int i;
974976
Rune c;
975977

978+
/* stack overflow */
979+
if (depth > MAXREC)
980+
return -1;
981+
976982
for (;;) {
977983
switch (pc->opcode) {
978984
case I_END:
979-
return 1;
985+
return 0;
980986
case I_JUMP:
981987
pc = pc->x;
982988
break;
983989
case I_SPLIT:
984990
scratch = *out;
985-
if (match(pc->x, sp, bol, flags, &scratch)) {
991+
result = match(pc->x, sp, bol, flags, &scratch, depth+1);
992+
if (result == -1)
993+
return -1;
994+
if (result == 0) {
986995
*out = scratch;
987-
return 1;
996+
return 0;
988997
}
989998
pc = pc->y;
990999
break;
9911000

9921001
case I_PLA:
993-
if (!match(pc->x, sp, bol, flags, out))
994-
return 0;
1002+
result = match(pc->x, sp, bol, flags, out, depth+1);
1003+
if (result == -1)
1004+
return -1;
1005+
if (result == 1)
1006+
return 1;
9951007
pc = pc->y;
9961008
break;
9971009
case I_NLA:
9981010
scratch = *out;
999-
if (match(pc->x, sp, bol, flags, &scratch))
1000-
return 0;
1011+
result = match(pc->x, sp, bol, flags, &scratch, depth+1);
1012+
if (result == -1)
1013+
return -1;
1014+
if (result == 0)
1015+
return 1;
10011016
pc = pc->y;
10021017
break;
10031018

10041019
case I_ANYNL:
10051020
sp += chartorune(&c, sp);
10061021
if (c == 0)
1007-
return 0;
1022+
return 1;
10081023
pc = pc + 1;
10091024
break;
10101025
case I_ANY:
10111026
sp += chartorune(&c, sp);
10121027
if (c == 0)
1013-
return 0;
1028+
return 1;
10141029
if (isnewline(c))
1015-
return 0;
1030+
return 1;
10161031
pc = pc + 1;
10171032
break;
10181033
case I_CHAR:
10191034
sp += chartorune(&c, sp);
10201035
if (c == 0)
1021-
return 0;
1036+
return 1;
10221037
if (flags & REG_ICASE)
10231038
c = canon(c);
10241039
if (c != pc->c)
1025-
return 0;
1040+
return 1;
10261041
pc = pc + 1;
10271042
break;
10281043
case I_CCLASS:
10291044
sp += chartorune(&c, sp);
10301045
if (c == 0)
1031-
return 0;
1046+
return 1;
10321047
if (flags & REG_ICASE) {
10331048
if (!incclasscanon(pc->cc, canon(c)))
1034-
return 0;
1049+
return 1;
10351050
} else {
10361051
if (!incclass(pc->cc, c))
1037-
return 0;
1052+
return 1;
10381053
}
10391054
pc = pc + 1;
10401055
break;
10411056
case I_NCCLASS:
10421057
sp += chartorune(&c, sp);
10431058
if (c == 0)
1044-
return 0;
1059+
return 1;
10451060
if (flags & REG_ICASE) {
10461061
if (incclasscanon(pc->cc, canon(c)))
1047-
return 0;
1062+
return 1;
10481063
} else {
10491064
if (incclass(pc->cc, c))
1050-
return 0;
1065+
return 1;
10511066
}
10521067
pc = pc + 1;
10531068
break;
10541069
case I_REF:
10551070
i = out->sub[pc->n].ep - out->sub[pc->n].sp;
10561071
if (flags & REG_ICASE) {
10571072
if (strncmpcanon(sp, out->sub[pc->n].sp, i))
1058-
return 0;
1073+
return 1;
10591074
} else {
10601075
if (strncmp(sp, out->sub[pc->n].sp, i))
1061-
return 0;
1076+
return 1;
10621077
}
10631078
if (i > 0)
10641079
sp += i;
@@ -1076,7 +1091,7 @@ static int match(Reinst *pc, const char *sp, const char *bol, int flags, Resub *
10761091
break;
10771092
}
10781093
}
1079-
return 0;
1094+
return 1;
10801095
case I_EOL:
10811096
if (*sp == 0) {
10821097
pc = pc + 1;
@@ -1088,19 +1103,19 @@ static int match(Reinst *pc, const char *sp, const char *bol, int flags, Resub *
10881103
break;
10891104
}
10901105
}
1091-
return 0;
1106+
return 1;
10921107
case I_WORD:
10931108
i = sp > bol && iswordchar(sp[-1]);
10941109
i ^= iswordchar(sp[0]);
10951110
if (!i)
1096-
return 0;
1111+
return 1;
10971112
pc = pc + 1;
10981113
break;
10991114
case I_NWORD:
11001115
i = sp > bol && iswordchar(sp[-1]);
11011116
i ^= iswordchar(sp[0]);
11021117
if (i)
1103-
return 0;
1118+
return 1;
11041119
pc = pc + 1;
11051120
break;
11061121

@@ -1113,7 +1128,7 @@ static int match(Reinst *pc, const char *sp, const char *bol, int flags, Resub *
11131128
pc = pc + 1;
11141129
break;
11151130
default:
1116-
return 0;
1131+
return 1;
11171132
}
11181133
}
11191134
}
@@ -1130,7 +1145,7 @@ int regexec(Reprog *prog, const char *sp, Resub *sub, int eflags)
11301145
for (i = 0; i < MAXSUB; ++i)
11311146
sub->sub[i].sp = sub->sub[i].ep = NULL;
11321147

1133-
return !match(prog->start, sp, sp, prog->flags | eflags, sub);
1148+
return match(prog->start, sp, sp, prog->flags | eflags, sub, 0);
11341149
}
11351150

11361151
#ifdef TEST

0 commit comments

Comments
 (0)