[regexp] Fix invalid lastIndex handling in RegExp.p[@@replace]

The RegExp replace implementation is a bit of a mess. Here, we first
try to handle parts of RegExp.p.exec, and then call directly into the
raw irregexp code (skipping RegExp.p.exec).

We got parts of this wrong: when lastIndex > string.length and the
regexp instance is sticky, two things should happen. 1. The match
should fail, and 2. lastIndex should be reset to 0. On the fast path,
we did the latter but not the former, instead running exec with a
lastIndex of 0.

This CL omits the irregexp call in this case, and defaults to a failed
match instead.

Bug: chromium:875493
Change-Id: I8c959610d267575e37686076a3fd5dfde322f0ca
Reviewed-on: https://chromium-review.googlesource.com/1180889
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Mathias Bynens <mathias@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55207}
This commit is contained in:
jgruber 2018-08-20 11:44:10 +02:00 committed by Commit Bot
parent 3b336a2ee5
commit d74a9fd595
2 changed files with 31 additions and 7 deletions

View File

@ -1323,15 +1323,19 @@ V8_WARN_UNUSED_RESULT MaybeHandle<String> RegExpReplace(
Object::ToLength(isolate, last_index_obj),
String);
last_index = PositiveNumberToUint32(*last_index_obj);
if (last_index > static_cast<uint32_t>(string->length())) last_index = 0;
}
Handle<Object> match_indices_obj;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, match_indices_obj,
RegExpImpl::Exec(isolate, regexp, string, last_index, last_match_info),
String);
Handle<Object> match_indices_obj(ReadOnlyRoots(isolate).null_value(),
isolate);
// A lastIndex exceeding the string length always always returns null
// (signalling failure) in RegExpBuiltinExec, thus we can skip the call.
if (last_index <= static_cast<uint32_t>(string->length())) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, match_indices_obj,
RegExpImpl::Exec(isolate, regexp, string,
last_index, last_match_info),
String);
}
if (match_indices_obj->IsNull(isolate)) {
if (sticky) regexp->set_last_index(Smi::kZero, SKIP_WRITE_BARRIER);

View File

@ -0,0 +1,20 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function test() {
const re = /./y;
re.lastIndex = 3;
const str = 'fg';
return re[Symbol.replace](str, '$');
}
%SetForceSlowPath(false);
const fast = test();
%SetForceSlowPath(true);
const slow = test();
%SetForceSlowPath(false);
assertEquals(slow, fast);