Changeset 232092 in webkit


Ignore:
Timestamp:
May 22, 2018 5:16:57 PM (6 years ago)
Author:
Yusuke Suzuki
Message:

[JSC] Fix CachedCall's argument count if RegExp has named captures
https://bugs.webkit.org/show_bug.cgi?id=185587

Reviewed by Mark Lam.

JSTests:

  • test262/expectations.yaml:

Source/JavaScriptCore:

If the given RegExp has named captures, the argument count of CachedCall in String#replace
should be increased by one. This causes crash with assertion in test262. This patch corrects
the argument count.

This patch also unifies source.is8Bit()/!source.is8Bit() code since they are now completely
the same.

  • runtime/StringPrototype.cpp:

(JSC::replaceUsingRegExpSearch):

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r232089 r232092  
     12018-05-22  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Fix CachedCall's argument count if RegExp has named captures
     4        https://bugs.webkit.org/show_bug.cgi?id=185587
     5
     6        Reviewed by Mark Lam.
     7
     8        * test262/expectations.yaml:
     9
    1102018-05-22  Mark Lam  <mark.lam@apple.com>
    211
  • trunk/JSTests/test262/expectations.yaml

    r231768 r232092  
    13041304  default: 'SyntaxError: Invalid regular expression: invalid group specifier name'
    13051305  strict mode: 'SyntaxError: Invalid regular expression: invalid group specifier name'
    1306 test/built-ins/RegExp/named-groups/functional-replace-global.js:
    1307   default: "TypeError: undefined is not an object (evaluating 'groups.fst')"
    1308   strict mode: "TypeError: undefined is not an object (evaluating 'groups.fst')"
    13091306test/built-ins/RegExp/named-groups/groups-object-subclass-sans.js:
    13101307  default: 'Test262Error: Expected SameValue(«b», «$<a>») to be true'
  • trunk/Source/JavaScriptCore/ChangeLog

    r232089 r232092  
     12018-05-22  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Fix CachedCall's argument count if RegExp has named captures
     4        https://bugs.webkit.org/show_bug.cgi?id=185587
     5
     6        Reviewed by Mark Lam.
     7
     8        If the given RegExp has named captures, the argument count of CachedCall in String#replace
     9        should be increased by one. This causes crash with assertion in test262. This patch corrects
     10        the argument count.
     11
     12        This patch also unifies source.is8Bit()/!source.is8Bit() code since they are now completely
     13        the same.
     14
     15        * runtime/StringPrototype.cpp:
     16        (JSC::replaceUsingRegExpSearch):
     17
    1182018-05-22  Mark Lam  <mark.lam@apple.com>
    219
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp

    r231741 r232092  
    566566        // regExp->numSubpatterns() + 1 for pattern args, + 2 for match start and string
    567567        int argCount = regExp->numSubpatterns() + 1 + 2;
     568        if (hasNamedCaptures)
     569            ++argCount;
    568570        JSFunction* func = jsCast<JSFunction*>(replaceValue);
    569571        CachedCall cachedCall(exec, func, argCount);
    570572        RETURN_IF_EXCEPTION(scope, nullptr);
    571         if (source.is8Bit()) {
    572             while (true) {
    573                 int* ovector;
    574                 MatchResult result = regExpConstructor->performMatch(vm, regExp, string, source, startPosition, &ovector);
    575                 if (!result)
    576                     break;
    577 
    578                 if (UNLIKELY(!sourceRanges.tryConstructAndAppend(lastIndex, result.start - lastIndex)))
    579                     OUT_OF_MEMORY(exec, scope);
    580 
    581                 unsigned i = 0;
    582                 cachedCall.clearArguments();
    583 
    584                 JSObject* groups = nullptr;
    585 
    586                 if (hasNamedCaptures) {
    587                     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
    588                     groups = JSFinalObject::create(vm, JSFinalObject::createStructure(vm, globalObject, globalObject->objectPrototype(), 0));
    589                 }
    590 
    591                 for (; i < regExp->numSubpatterns() + 1; ++i) {
    592                     int matchStart = ovector[i * 2];
    593                     int matchLen = ovector[i * 2 + 1] - matchStart;
    594 
    595                     JSValue patternValue;
    596 
    597                     if (matchStart < 0)
    598                         patternValue = jsUndefined();
    599                     else
    600                         patternValue = jsSubstring(&vm, source, matchStart, matchLen);
    601 
    602                     cachedCall.appendArgument(patternValue);
    603 
    604                     if (i && hasNamedCaptures) {
    605                         String groupName = regExp->getCaptureGroupName(i);
    606                         if (!groupName.isEmpty())
    607                             groups->putDirect(vm, Identifier::fromString(&vm, groupName), patternValue);
    608                     }
    609                 }
    610 
    611                 cachedCall.appendArgument(jsNumber(result.start));
    612                 cachedCall.appendArgument(string);
    613                 if (hasNamedCaptures)
    614                     cachedCall.appendArgument(groups);
    615 
    616                 cachedCall.setThis(jsUndefined());
    617                 if (UNLIKELY(cachedCall.hasOverflowedArguments())) {
    618                     throwOutOfMemoryError(exec, scope);
    619                     return nullptr;
    620                 }
    621 
    622                 JSValue jsResult = cachedCall.call();
    623                 RETURN_IF_EXCEPTION(scope, nullptr);
    624                 replacements.append(jsResult.toWTFString(exec));
    625                 RETURN_IF_EXCEPTION(scope, nullptr);
    626 
    627                 lastIndex = result.end;
    628                 startPosition = lastIndex;
    629 
    630                 // special case of empty match
    631                 if (result.empty()) {
    632                     startPosition++;
    633                     if (startPosition > sourceLen)
    634                         break;
     573        while (true) {
     574            int* ovector;
     575            MatchResult result = regExpConstructor->performMatch(vm, regExp, string, source, startPosition, &ovector);
     576            if (!result)
     577                break;
     578
     579            if (UNLIKELY(!sourceRanges.tryConstructAndAppend(lastIndex, result.start - lastIndex)))
     580                OUT_OF_MEMORY(exec, scope);
     581
     582            cachedCall.clearArguments();
     583
     584            JSObject* groups = nullptr;
     585
     586            if (hasNamedCaptures) {
     587                JSGlobalObject* globalObject = exec->lexicalGlobalObject();
     588                groups = JSFinalObject::create(vm, JSFinalObject::createStructure(vm, globalObject, globalObject->objectPrototype(), 0));
     589            }
     590
     591            for (unsigned i = 0; i < regExp->numSubpatterns() + 1; ++i) {
     592                int matchStart = ovector[i * 2];
     593                int matchLen = ovector[i * 2 + 1] - matchStart;
     594
     595                JSValue patternValue;
     596
     597                if (matchStart < 0)
     598                    patternValue = jsUndefined();
     599                else
     600                    patternValue = jsSubstring(&vm, source, matchStart, matchLen);
     601
     602                cachedCall.appendArgument(patternValue);
     603
     604                if (i && hasNamedCaptures) {
     605                    String groupName = regExp->getCaptureGroupName(i);
     606                    if (!groupName.isEmpty())
     607                        groups->putDirect(vm, Identifier::fromString(&vm, groupName), patternValue);
    635608                }
    636609            }
    637         } else {
    638             while (true) {
    639                 int* ovector;
    640                 MatchResult result = regExpConstructor->performMatch(vm, regExp, string, source, startPosition, &ovector);
    641                 if (!result)
     610
     611            cachedCall.appendArgument(jsNumber(result.start));
     612            cachedCall.appendArgument(string);
     613            if (hasNamedCaptures)
     614                cachedCall.appendArgument(groups);
     615
     616            cachedCall.setThis(jsUndefined());
     617            if (UNLIKELY(cachedCall.hasOverflowedArguments())) {
     618                throwOutOfMemoryError(exec, scope);
     619                return nullptr;
     620            }
     621
     622            JSValue jsResult = cachedCall.call();
     623            RETURN_IF_EXCEPTION(scope, nullptr);
     624            replacements.append(jsResult.toWTFString(exec));
     625            RETURN_IF_EXCEPTION(scope, nullptr);
     626
     627            lastIndex = result.end;
     628            startPosition = lastIndex;
     629
     630            // special case of empty match
     631            if (result.empty()) {
     632                startPosition++;
     633                if (startPosition > sourceLen)
    642634                    break;
    643 
    644                 if (UNLIKELY(!sourceRanges.tryConstructAndAppend(lastIndex, result.start - lastIndex)))
    645                     OUT_OF_MEMORY(exec, scope);
    646 
    647                 unsigned i = 0;
    648                 cachedCall.clearArguments();
    649 
    650                 JSObject* groups = nullptr;
    651 
    652                 if (hasNamedCaptures) {
    653                     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
    654                     groups = JSFinalObject::create(vm, JSFinalObject::createStructure(vm, globalObject, globalObject->objectPrototype(), 0));
    655                 }
    656 
    657                 for (; i < regExp->numSubpatterns() + 1; ++i) {
    658                     int matchStart = ovector[i * 2];
    659                     int matchLen = ovector[i * 2 + 1] - matchStart;
    660 
    661                     JSValue patternValue;
    662 
    663                     if (matchStart < 0)
    664                         patternValue = jsUndefined();
    665                     else
    666                         patternValue = jsSubstring(&vm, source, matchStart, matchLen);
    667 
    668                     cachedCall.appendArgument(patternValue);
    669 
    670                     if (i && hasNamedCaptures) {
    671                         String groupName = regExp->getCaptureGroupName(i);
    672                         if (!groupName.isEmpty())
    673                             groups->putDirect(vm, Identifier::fromString(&vm, groupName), patternValue);
    674                     }
    675                 }
    676 
    677                 cachedCall.appendArgument(jsNumber(result.start));
    678                 cachedCall.appendArgument(string);
    679                 if (hasNamedCaptures)
    680                     cachedCall.appendArgument(groups);
    681 
    682                 cachedCall.setThis(jsUndefined());
    683                 if (UNLIKELY(cachedCall.hasOverflowedArguments())) {
    684                     throwOutOfMemoryError(exec, scope);
    685                     return nullptr;
    686                 }
    687 
    688                 JSValue jsResult = cachedCall.call();
    689                 RETURN_IF_EXCEPTION(scope, nullptr);
    690                 replacements.append(jsResult.toWTFString(exec));
    691                 RETURN_IF_EXCEPTION(scope, nullptr);
    692 
    693                 lastIndex = result.end;
    694                 startPosition = lastIndex;
    695 
    696                 // special case of empty match
    697                 if (result.empty()) {
    698                     startPosition++;
    699                     if (startPosition > sourceLen)
    700                         break;
    701                 }
    702635            }
    703636        }
Note: See TracChangeset for help on using the changeset viewer.