Inconsistent gating of `Set(_, "lastIndex", _, true)` in Regular Expressions breaks frozen instances.

Duane Leslie parakleta at
Mon Feb 29 00:16:23 UTC 2016

In most cases [[Set]] operations on the `lastIndex` property of regular
expressions is gated by the 'global' and/or 'sticky' flags*.  This should
mean that a non-global/non-stick regular expression can be safely frozen.
Unfortunately two cases have not been gated, and in both of these cases the
operation is a no-op except that it results in a thrown TypeError.

Specifically, ' Runtime Semantics: RegExpBuiltinExec', step
12.a.i sets the `lastIndex` to 0 if the match fails to occur regardless of
the flags or the original state of `lastIndex`.  If the regular expression
is non-global/non-sticky the `lastIndex` property can never be non-zero so
this is a no-op that throws.

Additionally, in ' RegExp.prototype [ @@search ]' steps 5 & 7
blindly reset and restore the `lastIndex` value without checking the global
or sticky flags.  Assuming the `RegExpBuiltinExec` is used then Step 5 is a
no-op that throws since the `lastIndex` cannot be non-zero, and step 7 is a
no-op that throws since the `lastIndex` can only be set to 0 (or not
modified) by `RegExpBuiltinExec`.  The attached NOTE states "The
`lastIndex` property is left unchanged" which is not entirely true.

The problem with the throw in `RegExpBuiltinExec` that particularly
troubles me is that it only occurs if the match fails.  So long as the
match succeeds a frozen non-global/non-sticky regular expression will work
correctly through this method.  If however the match fails instead of
returning `null` a TypeError will be thrown.

For completeness, the only other non-gate [[Set]] of `lastIndex` is in
' Runtime Semantics: RegExpInitialize' step 12 which is only
called with an existing object through 'B.2.5.1 RegExp.prototype.compile'.
I have no position either way on whether this instance should be gated
somehow.  All of the other initialized values are internal properties and
so unaffected by being frozen, so maybe it is best that the `lastIndex`
always throws so that a frozen `RegExp` cannot be changed by a call to

[*] Gated [[Set]]: step 12.c.i.1 (sticky) step 15 (global || sticky) step 6.b (global) step 6.e.iii.4.c (global) step 8.b (global) step 11.c.iii.2.c (global) step 19.a (sticky, supplied `rx` is copied first)


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list