Skip to content

Commit f8ce76a

Browse files
authored
RegExp: Fix bug with quantified capture groups (mozilla#1845)
Fixes an issue where capture groups in quantified expressions (min ≥ 2) were not cleared between iterations. For example, in /(?:(\2)(\d)){2}/, during the second iteration, \2 incorrectly retained the first iteration's value instead of being reset. Before: js> /(?:(\2)(\d)){2}/.exec("112") 112,1,2 After: js> /(?:(\2)(\d)){2}/.exec("112") 11,,1
1 parent daa64a8 commit f8ce76a

File tree

2 files changed

+37
-5
lines changed

2 files changed

+37
-5
lines changed

Diff for: rhino/src/main/java/org/mozilla/javascript/regexp/NativeRegExp.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -2683,11 +2683,11 @@ && simpleMatch(gData, input, op, program, pc, end, false, false)
26832683
startcp,
26842684
state.continuationOp,
26852685
state.continuationPc);
2686-
int parenCount = getIndex(program, pc);
2687-
int parenIndex = getIndex(program, pc + INDEX_LEN);
2688-
for (int k = 0; k < parenCount; k++) {
2689-
gData.setParens(parenIndex + k, -1, 0);
2690-
}
2686+
}
2687+
int parenCount = getIndex(program, pc);
2688+
int parenIndex = getIndex(program, pc + INDEX_LEN);
2689+
for (int k = 0; k < parenCount; k++) {
2690+
gData.setParens(parenIndex + k, -1, 0);
26912691
}
26922692
} while (program[nextpc] == REOP_ENDCHILD);
26932693

Diff for: rhino/src/test/java/org/mozilla/javascript/tests/NativeRegExpTest.java

+32
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static org.junit.Assert.assertTrue;
99
import static org.junit.Assert.fail;
1010

11+
import java.util.function.BiFunction;
1112
import org.junit.Test;
1213
import org.mozilla.javascript.Context;
1314
import org.mozilla.javascript.ScriptableObject;
@@ -700,4 +701,35 @@ public void backwardFlatCaseInsensitiveNoMatch() throws Exception {
700701
final String script = "var regex = /abc(?<=XYZ)/i;\n" + "'abc'.match(regex);";
701702
Utils.assertWithAllModes_ES6(null, script);
702703
}
704+
705+
@Test
706+
public void quantifiedCaptureClearsPreviousCaptures() {
707+
// With the pattern /(?:(\2)(\d))*/, the first capture group should be always empty
708+
// when used with a quantifier
709+
BiFunction<String, String, String> test =
710+
(quantifier, input) -> {
711+
return "var regexStr = '(?:(\\\\2)(\\\\d))'\n"
712+
+ "function test(quantifier, input) {\n"
713+
+ " var regexp = new RegExp(regexStr + quantifier + '$');\n"
714+
+ " var res = regexp.exec(input);\n"
715+
+ " return res != null && res.length == 3 && res[1] == '' && res[2] != '';\n"
716+
+ "}\n"
717+
+ "test('"
718+
+ quantifier
719+
+ "','"
720+
+ input
721+
+ "');";
722+
};
723+
724+
Utils.assertWithAllModes_ES6("greedy-*", true, test.apply("*", "123"));
725+
Utils.assertWithAllModes_ES6("greedy-+", true, test.apply("+", "123"));
726+
Utils.assertWithAllModes_ES6("greedy-?", true, test.apply("?", "123"));
727+
Utils.assertWithAllModes_ES6("greedy-{2}", true, test.apply("{2}", "123"));
728+
Utils.assertWithAllModes_ES6("greedy-{2,3}", true, test.apply("{2,}", "123"));
729+
Utils.assertWithAllModes_ES6("non-greedy-*", true, test.apply("*?", "123"));
730+
Utils.assertWithAllModes_ES6("non-greedy-+", true, test.apply("+?", "123"));
731+
Utils.assertWithAllModes_ES6("non-greedy-?", true, test.apply("??", "123"));
732+
Utils.assertWithAllModes_ES6("non-greedy-{2}", true, test.apply("{2}?", "123"));
733+
Utils.assertWithAllModes_ES6("non-greedy-{2,3}", true, test.apply("{2,}?", "123"));
734+
}
703735
}

0 commit comments

Comments
 (0)