Closed Bug 1168257 Opened 7 years ago Closed 7 years ago

String.prototype.replace fails with frozen RegExp param

Categories

(Core :: JavaScript Engine, defect)

38 Branch
defect
Not set
normal

Tracking

()

RESOLVED INVALID

People

(Reporter: adamsmith, Unassigned)

References

Details

Attachments

(1 file)

User Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.65 Safari/537.36

Steps to reproduce:

The steps to reproduce this bug are simple:
1) Write a script that creates a RegExp, freezes it, and runs string.replace(frozenRegExp, string).
2) Open Firefox (34, 38, 41, ...) any way you desire.
3) Run the script written for step 1.
Note: The attached files will quickly reproduce the error without any difficulty. Plus it contains much greater detail of the problem than provided here.


Actual results:

TypeError: string.replace(...) is read-only


Expected results:

returned new string with replacements
It doesn't work after bug 501739. I'd say it's an issue in your code.
Blocks: 501739
Component: Untriaged → JavaScript Engine
Product: Firefox → Core
The testcase is basically this:

  var regex = /0/g;
  Object.freeze(regex);
  var str = "abc000";
  str.replace(regex, "o");

Per spec this calls http://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.replace which then gets @@replace from the regex and calls that method.

That means that we're calling http://people.mozilla.org/~jorendorff/es6-draft.html#sec-regexp.prototype-@@replace which in step 10 sees that the global flag on the regex is true and hence does step 10c, which attempts to set the lastIndex property of the regex to 0.  It does so by invoking http://people.mozilla.org/~jorendorff/es6-draft.html#sec-set-o-p-v-throw with the "Throw" argument set to true.  The call to [[Set]] in step 4 there returns false (because the property is readonly), so Set() throws an exception.  This is then propagated out.

So the observed behavior is correct: an exception should be thrown here.
Status: UNCONFIRMED → RESOLVED
Closed: 7 years ago
Resolution: --- → INVALID
I filed https://code.google.com/p/v8/issues/detail?id=4146 on Chrome here.

Also filed https://code.google.com/p/v8/issues/detail?id=4147 and bug 1168416 on a somewhat related testcase that both SpiderMonkey and V8 get wrong (in slightly different ways).
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-validateandapplypropertydescriptor

Step 4.

Since lastIndex is being set to the exactly the same value no error is thrown.
Status: RESOLVED → REOPENED
Ever confirmed: true
Resolution: INVALID → ---
Duplicate of this bug: 1168524
Flags: needinfo?(jwalden+bmo)
(In reply to Erik Arvidsson from comment #4)
> http://people.mozilla.org/~jorendorff/es6-draft.html#sec-
> validateandapplypropertydescriptor
> 
> Step 4.
> 
> Since lastIndex is being set to the exactly the same value no error is
> thrown.

21.2.5.8 RegExp.prototype [ @@replace ], step 10.c calls [[Set]] (through the Set() abstract operation). And [[Set]], step 5.a returns false which will then lead to Set() throwing the TypeError.
Yes, exactly.  This is not ending up in ValidateAndApplyPropertyDescriptor at all, nor even ending up in DefineOwnProperty.  It bails out directly from [[Set]].
Status: REOPENED → RESOLVED
Closed: 7 years ago7 years ago
Flags: needinfo?(jwalden+bmo)
Resolution: --- → INVALID
This is just something that is unfortunately **** in the standard.  The problem is understandable when the regular expression has the global flag set, but unfortunately basically all RegExp operations throw on match failure regardless of the flags due to a mistake in "21.2.5.2.2 Runtime Semantics: RegExpBuiltinExec" step 12.a.i which always sets lastIndex to 0 with a throw on failure if the regular expression doesn't successfully match before the end of the string.

The RegExpBuiltinExec step is pointless because if the RegExp is non-global/non-sticky the lastIndex can never have a non-0 value.  In fact that step is one of the only places where lastIndex is touched without gating by global or sticky.  The only other place is in "21.2.5.9 RegExp.prototype [ @@search ]" where it blindly saves and restores the lastIndex around a call to RegExpBuiltinExec (also pointless if non-global/non-sticky and so should be gated).
Please send spec feedback to es-discuss@mozilla.org....
You need to log in before you can comment on or make changes to this bug.