Skip to content

Commit c9fee8e

Browse files
Code inside strength reduction can incorrectly prove that we know what lastIndex is
https://bugs.webkit.org/show_bug.cgi?id=230802 <rdar://problem/83543699> Reviewed by Mark Lam. JSTests: * stress/dont-fold-regexp-exec-when-we-dont-know-last-index-and-regexp-is-constant.js: Added. (assert): (let.reg.RegExp.foo.g.doExec): (noInline.doExec): Source/JavaScriptCore: The phase was searching backwards in the graph to see if it found the RegExp node. However, the RegExp node might be a JSConstant. Hence, the program didn't allocate it. So we can't assume that we know what the lastIndex is. We were incorrectly assuming it was "0" in a program like this: a: JSConstant(RegExp) b: RegExpExec(@A) And we assumed we're invoking RegExpExec with lastIndex is 0, because we found our RegExp in a backwards search. This is likely because we're also matching NewRegExp nodes, in which case, it is valid to say lastIndex is 0. This caused us to return a constant value that would've been the exec result had we invoked it with a NewRegExpNode. * dfg/DFGStrengthReductionPhase.cpp: (JSC::DFG::StrengthReductionPhase::run): (JSC::DFG::StrengthReductionPhase::handleNode): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@283232 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent fe3574a commit c9fee8e

File tree

4 files changed

+64
-2
lines changed

4 files changed

+64
-2
lines changed

JSTests/ChangeLog

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
2021-09-29 Saam Barati <[email protected]>
2+
3+
Code inside strength reduction can incorrectly prove that we know what lastIndex is
4+
https://bugs.webkit.org/show_bug.cgi?id=230802
5+
<rdar://problem/83543699>
6+
7+
Reviewed by Mark Lam.
8+
9+
* stress/dont-fold-regexp-exec-when-we-dont-know-last-index-and-regexp-is-constant.js: Added.
10+
(assert):
11+
(let.reg.RegExp.foo.g.doExec):
12+
(noInline.doExec):
13+
114
2021-09-29 Saam Barati <[email protected]>
215

316
DoesGCCheck does not use enough bits for nodeIndex
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function assert(b) {
2+
if (!b)
3+
throw new Error;
4+
}
5+
6+
let reg = RegExp(/foo/g)
7+
function doExec() {
8+
return reg.exec("-foo");
9+
}
10+
noInline(doExec)
11+
12+
for (let i = 0; i < 1000; ++i) {
13+
let r = doExec();
14+
if ((i % 2) === 0)
15+
assert(r[0] === "foo");
16+
else
17+
assert(r === null);
18+
}
19+

Source/JavaScriptCore/ChangeLog

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
2021-09-29 Saam Barati <[email protected]>
2+
3+
Code inside strength reduction can incorrectly prove that we know what lastIndex is
4+
https://bugs.webkit.org/show_bug.cgi?id=230802
5+
<rdar://problem/83543699>
6+
7+
Reviewed by Mark Lam.
8+
9+
The phase was searching backwards in the graph to see if it found the RegExp
10+
node. However, the RegExp node might be a JSConstant. Hence, the program
11+
didn't allocate it. So we can't assume that we know what the lastIndex is.
12+
We were incorrectly assuming it was "0" in a program like this:
13+
a: JSConstant(RegExp)
14+
b: RegExpExec(@a)
15+
16+
And we assumed we're invoking RegExpExec with lastIndex is 0, because we found
17+
our RegExp in a backwards search. This is likely because we're also matching
18+
NewRegExp nodes, in which case, it is valid to say lastIndex is 0.
19+
20+
This caused us to return a constant value that would've been the exec
21+
result had we invoked it with a NewRegExpNode.
22+
23+
* dfg/DFGStrengthReductionPhase.cpp:
24+
(JSC::DFG::StrengthReductionPhase::run):
25+
(JSC::DFG::StrengthReductionPhase::handleNode):
26+
127
2021-09-29 Yusuke Suzuki <[email protected]>
228

329
[JSC] Use FixedVector in JITConstantPool

Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,11 +491,13 @@ class StrengthReductionPhase : public Phase {
491491

492492
Node* regExpObjectNode = nullptr;
493493
RegExp* regExp = nullptr;
494+
bool regExpObjectNodeIsConstant = false;
494495
if (m_node->op() == RegExpExec || m_node->op() == RegExpTest || m_node->op() == RegExpMatchFast) {
495496
regExpObjectNode = m_node->child2().node();
496-
if (RegExpObject* regExpObject = regExpObjectNode->dynamicCastConstant<RegExpObject*>(vm()))
497+
if (RegExpObject* regExpObject = regExpObjectNode->dynamicCastConstant<RegExpObject*>(vm())) {
497498
regExp = regExpObject->regExp();
498-
else if (regExpObjectNode->op() == NewRegexp)
499+
regExpObjectNodeIsConstant = true;
500+
} else if (regExpObjectNode->op() == NewRegexp)
499501
regExp = regExpObjectNode->castOperand<RegExp*>();
500502
else {
501503
if (verbose)
@@ -545,6 +547,8 @@ class StrengthReductionPhase : public Phase {
545547
for (unsigned otherNodeIndex = m_nodeIndex; otherNodeIndex--;) {
546548
Node* otherNode = m_block->at(otherNodeIndex);
547549
if (otherNode == regExpObjectNode) {
550+
if (regExpObjectNodeIsConstant)
551+
break;
548552
lastIndex = 0;
549553
break;
550554
}

0 commit comments

Comments
 (0)