Changeset 232089 in webkit


Ignore:
Timestamp:
May 22, 2018 4:54:16 PM (6 years ago)
Author:
mark.lam@apple.com
Message:

StringImpl utf8 conversion should not fail silently.
https://bugs.webkit.org/show_bug.cgi?id=185888
<rdar://problem/40464506>

Reviewed by Filip Pizlo.

JSTests:

  • stress/regress-185888.js: Added.

Source/JavaScriptCore:

  • dfg/DFGLazyJSValue.cpp:

(JSC::DFG::LazyJSValue::dumpInContext const):

  • runtime/DateConstructor.cpp:

(JSC::constructDate):
(JSC::dateParse):

  • runtime/JSDateMath.cpp:

(JSC::parseDate):

  • runtime/JSDateMath.h:

Source/WTF:

  • WTF.xcodeproj/project.pbxproj:
  • wtf/CMakeLists.txt:
  • wtf/PrintStream.cpp:

(WTF::printExpectedCStringHelper):
(WTF::printInternal):

  • wtf/text/StringImpl.cpp:

(WTF::StringImpl::utf8Impl):
(WTF::StringImpl::utf8ForCharacters):
(WTF::StringImpl::tryUtf8ForRange const):
(WTF::StringImpl::tryUtf8 const):
(WTF::StringImpl::utf8 const):
(WTF::StringImpl::utf8ForRange const): Deleted.

  • wtf/text/StringImpl.h:
  • wtf/text/StringView.cpp:

(WTF::StringView::tryUtf8 const):
(WTF::StringView::utf8 const):

  • wtf/text/StringView.h:
  • wtf/text/UTF8ConversionError.h: Added.
  • wtf/text/WTFString.cpp:

(WTF::String::tryUtf8 const):
(WTF::String::utf8 const):

  • wtf/text/WTFString.h:
Location:
trunk
Files:
2 added
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r232070 r232089  
     12018-05-22  Mark Lam  <mark.lam@apple.com>
     2
     3        StringImpl utf8 conversion should not fail silently.
     4        https://bugs.webkit.org/show_bug.cgi?id=185888
     5        <rdar://problem/40464506>
     6
     7        Reviewed by Filip Pizlo.
     8
     9        * stress/regress-185888.js: Added.
     10
    1112018-05-22  Keith Miller  <keith_miller@apple.com>
    212
  • trunk/Source/JavaScriptCore/ChangeLog

    r232080 r232089  
     12018-05-22  Mark Lam  <mark.lam@apple.com>
     2
     3        StringImpl utf8 conversion should not fail silently.
     4        https://bugs.webkit.org/show_bug.cgi?id=185888
     5        <rdar://problem/40464506>
     6
     7        Reviewed by Filip Pizlo.
     8
     9        * dfg/DFGLazyJSValue.cpp:
     10        (JSC::DFG::LazyJSValue::dumpInContext const):
     11        * runtime/DateConstructor.cpp:
     12        (JSC::constructDate):
     13        (JSC::dateParse):
     14        * runtime/JSDateMath.cpp:
     15        (JSC::parseDate):
     16        * runtime/JSDateMath.h:
     17
    1182018-05-22  Keith Miller  <keith_miller@apple.com>
    219
  • trunk/Source/JavaScriptCore/dfg/DFGLazyJSValue.cpp

    r214571 r232089  
    251251        out.print("Lazy:SingleCharacterString(");
    252252        out.printf("%04X", static_cast<unsigned>(character()));
    253         out.print(" / ", StringImpl::utf8ForCharacters(&u.character, 1), ")");
     253        out.print(" / ", StringImpl::utf8ForCharacters(&u.character, 1).value(), ")");
    254254        return;
    255255    case KnownStringImpl:
  • trunk/Source/JavaScriptCore/runtime/DateConstructor.cpp

    r230369 r232089  
    11/*
    22 *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
    3  *  Copyright (C) 2004-2008, 2011, 2016 Apple Inc. All rights reserved.
     3 *  Copyright (C) 2004-2018 Apple Inc. All rights reserved.
    44 *
    55 *  This library is free software; you can redistribute it and/or
     
    137137            JSValue primitive = arg0.toPrimitive(exec);
    138138            RETURN_IF_EXCEPTION(scope, nullptr);
    139             if (primitive.isString())
    140                 value = parseDate(vm, asString(primitive)->value(exec));
    141             else
     139            if (primitive.isString()) {
     140                value = parseDate(exec, vm, asString(primitive)->value(exec));
     141                RETURN_IF_EXCEPTION(scope, nullptr);
     142            } else
    142143                value = primitive.toNumber(exec);
    143144        }
     
    173174    String dateStr = exec->argument(0).toWTFString(exec);
    174175    RETURN_IF_EXCEPTION(scope, encodedJSValue());
    175     return JSValue::encode(jsNumber(parseDate(vm, dateStr)));
     176    scope.release();
     177    return JSValue::encode(jsNumber(parseDate(exec, vm, dateStr)));
    176178}
    177179
  • trunk/Source/JavaScriptCore/runtime/JSDateMath.cpp

    r229209 r232089  
    11/*
    22 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
    3  * Copyright (C) 2006, 2007, 2012 Apple Inc. All rights reserved.
     3 * Copyright (C) 2006-2018 Apple Inc. All rights reserved.
    44 * Copyright (C) 2009 Google Inc. All rights reserved.
    55 * Copyright (C) 2007-2009 Torch Mobile, Inc.
     
    236236}
    237237
    238 double parseDate(VM& vm, const String& date)
    239 {
     238double parseDate(ExecState* exec, VM& vm, const String& date)
     239{
     240    auto scope = DECLARE_THROW_SCOPE(vm);
     241
    240242    if (date == vm.cachedDateString)
    241243        return vm.cachedDateStringValue;
    242     double value = parseES5DateFromNullTerminatedCharacters(date.utf8().data());
     244    auto expectedString = date.tryGetUtf8();
     245    if (!expectedString) {
     246        if (expectedString.error() == UTF8ConversionError::OutOfMemory)
     247            throwOutOfMemoryError(exec, scope);
     248        // https://tc39.github.io/ecma262/#sec-date-objects section 20.3.3.2 states that:
     249        // "Unrecognizable Strings or dates containing illegal element values in the
     250        // format String shall cause Date.parse to return NaN."
     251        return std::numeric_limits<double>::quiet_NaN();
     252    }
     253
     254    auto dateUtf8 = expectedString.value();
     255    double value = parseES5DateFromNullTerminatedCharacters(dateUtf8.data());
    243256    if (std::isnan(value))
    244         value = parseDateFromNullTerminatedCharacters(vm, date.utf8().data());
     257        value = parseDateFromNullTerminatedCharacters(vm, dateUtf8.data());
    245258    vm.cachedDateString = date;
    246259    vm.cachedDateStringValue = value;
  • trunk/Source/JavaScriptCore/runtime/JSDateMath.h

    r206525 r232089  
    11/*
    22 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
    3  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
     3 * Copyright (C) 2006-2018 Apple Inc. All rights reserved.
    44 * Copyright (C) 2009 Google Inc. All rights reserved.
    55 * Copyright (C) 2010 Research In Motion Limited. All rights reserved.
     
    4848namespace JSC {
    4949
     50class ExecState;
    5051class VM;
    5152
     
    5455JS_EXPORT_PRIVATE double getUTCOffset(VM&);
    5556JS_EXPORT_PRIVATE double parseDateFromNullTerminatedCharacters(VM&, const char* dateString);
    56 JS_EXPORT_PRIVATE double parseDate(VM&, const WTF::String&);
     57JS_EXPORT_PRIVATE double parseDate(ExecState*, VM&, const WTF::String&);
    5758
    5859} // namespace JSC
  • trunk/Source/WTF/ChangeLog

    r232082 r232089  
     12018-05-22  Mark Lam  <mark.lam@apple.com>
     2
     3        StringImpl utf8 conversion should not fail silently.
     4        https://bugs.webkit.org/show_bug.cgi?id=185888
     5        <rdar://problem/40464506>
     6
     7        Reviewed by Filip Pizlo.
     8
     9        * WTF.xcodeproj/project.pbxproj:
     10        * wtf/CMakeLists.txt:
     11        * wtf/PrintStream.cpp:
     12        (WTF::printExpectedCStringHelper):
     13        (WTF::printInternal):
     14        * wtf/text/StringImpl.cpp:
     15        (WTF::StringImpl::utf8Impl):
     16        (WTF::StringImpl::utf8ForCharacters):
     17        (WTF::StringImpl::tryUtf8ForRange const):
     18        (WTF::StringImpl::tryUtf8 const):
     19        (WTF::StringImpl::utf8 const):
     20        (WTF::StringImpl::utf8ForRange const): Deleted.
     21        * wtf/text/StringImpl.h:
     22        * wtf/text/StringView.cpp:
     23        (WTF::StringView::tryUtf8 const):
     24        (WTF::StringView::utf8 const):
     25        * wtf/text/StringView.h:
     26        * wtf/text/UTF8ConversionError.h: Added.
     27        * wtf/text/WTFString.cpp:
     28        (WTF::String::tryUtf8 const):
     29        (WTF::String::utf8 const):
     30        * wtf/text/WTFString.h:
     31
    1322018-05-22  Chris Dumez  <cdumez@apple.com>
    233
  • trunk/Source/WTF/WTF.xcodeproj/project.pbxproj

    r232082 r232089  
    642642                FEDACD3B1630F83F00C69634 /* StackStats.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StackStats.cpp; sourceTree = "<group>"; };
    643643                FEDACD3C1630F83F00C69634 /* StackStats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackStats.h; sourceTree = "<group>"; };
     644                FEF295BF20B49DCB00CF283A /* UTF8ConversionError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UTF8ConversionError.h; sourceTree = "<group>"; };
    644645                FF0A436588954F3CB07DBECA /* StdList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StdList.h; sourceTree = "<group>"; };
    645646/* End PBXFileReference section */
     
    12191220                                A3E4DD911F3A803400DED0B4 /* TextStream.cpp */,
    12201221                                A3E4DD921F3A803400DED0B4 /* TextStream.h */,
     1222                                FEF295BF20B49DCB00CF283A /* UTF8ConversionError.h */,
    12211223                                70ECA60C1B02426800449739 /* UniquedStringImpl.h */,
    12221224                                A3AB6E6A1F3E1AD6009C14B1 /* ValueToString.h */,
  • trunk/Source/WTF/wtf/CMakeLists.txt

    r232000 r232089  
    306306    text/TextPosition.h
    307307    text/TextStream.h
     308    text/UTF8ConversionError.h
    308309    text/UniquedStringImpl.h
    309310    text/ValueToString.h
  • trunk/Source/WTF/wtf/PrintStream.cpp

    r220058 r232089  
    8383}
    8484
     85static void printExpectedCStringHelper(PrintStream& out, const char* type, Expected<CString, UTF8ConversionError> expectedCString)
     86{
     87    if (UNLIKELY(!expectedCString)) {
     88        if (expectedCString.error() == UTF8ConversionError::OutOfMemory)
     89            out.print("(Out of memory while converting ", type, " to utf8)");
     90        else
     91            out.print("(failed to convert ", type, " to utf8)");
     92        return;
     93    }
     94    out.print(expectedCString.value());
     95}
     96
    8597void printInternal(PrintStream& out, const StringView& string)
    8698{
    87     out.print(string.utf8());
     99    printExpectedCStringHelper(out, "StringView", string.tryGetUtf8());
    88100}
    89101
     
    95107void printInternal(PrintStream& out, const String& string)
    96108{
    97     out.print(string.utf8());
     109    printExpectedCStringHelper(out, "String", string.tryGetUtf8());
    98110}
    99111
     
    104116        return;
    105117    }
    106     out.print(string->utf8());
     118    printExpectedCStringHelper(out, "StringImpl*", string->tryGetUtf8());
    107119}
    108120
  • trunk/Source/WTF/wtf/text/StringImpl.cpp

    r231337 r232089  
    17271727}
    17281728
    1729 bool StringImpl::utf8Impl(const UChar* characters, unsigned length, char*& buffer, size_t bufferSize, ConversionMode mode)
     1729UTF8ConversionError StringImpl::utf8Impl(const UChar* characters, unsigned length, char*& buffer, size_t bufferSize, ConversionMode mode)
    17301730{
    17311731    if (mode == StrictConversionReplacingUnpairedSurrogatesWithFFFD) {
     
    17551755        if (result == sourceIllegal) {
    17561756            ASSERT(strict);
    1757             return false;
     1757            return UTF8ConversionError::IllegalSource;
    17581758        }
    17591759
     
    17611761        if (result == sourceExhausted) {
    17621762            if (strict)
    1763                 return false;
     1763                return UTF8ConversionError::SourceExhausted;
    17641764            // This should be one unpaired high surrogate. Treat it the same
    17651765            // was as an unpaired high surrogate would have been handled in
     
    17751775    }
    17761776   
    1777     return true;
    1778 }
    1779 
    1780 CString StringImpl::utf8ForCharacters(const LChar* characters, unsigned length)
     1777    return UTF8ConversionError::None;
     1778}
     1779
     1780Expected<CString, UTF8ConversionError> StringImpl::utf8ForCharacters(const LChar* characters, unsigned length)
    17811781{
    17821782    if (!length)
    17831783        return CString("", 0);
    17841784    if (length > std::numeric_limits<unsigned>::max() / 3)
    1785         return CString();
     1785        return makeUnexpected(UTF8ConversionError::OutOfMemory);
    17861786    Vector<char, 1024> bufferVector(length * 3);
    17871787    char* buffer = bufferVector.data();
     
    17921792}
    17931793
    1794 CString StringImpl::utf8ForCharacters(const UChar* characters, unsigned length, ConversionMode mode)
     1794Expected<CString, UTF8ConversionError> StringImpl::utf8ForCharacters(const UChar* characters, unsigned length, ConversionMode mode)
    17951795{
    17961796    if (!length)
    17971797        return CString("", 0);
    17981798    if (length > std::numeric_limits<unsigned>::max() / 3)
    1799         return CString();
     1799        return makeUnexpected(UTF8ConversionError::OutOfMemory);
    18001800    Vector<char, 1024> bufferVector(length * 3);
    18011801    char* buffer = bufferVector.data();
    1802     if (!utf8Impl(characters, length, buffer, bufferVector.size(), mode))
    1803         return CString();
     1802    UTF8ConversionError error = utf8Impl(characters, length, buffer, bufferVector.size(), mode);
     1803    if (error != UTF8ConversionError::None)
     1804        return makeUnexpected(error);
    18041805    return CString(bufferVector.data(), buffer - bufferVector.data());
    18051806}
    18061807
    1807 CString StringImpl::utf8ForRange(unsigned offset, unsigned length, ConversionMode mode) const
     1808Expected<CString, UTF8ConversionError> StringImpl::tryGetUtf8ForRange(unsigned offset, unsigned length, ConversionMode mode) const
    18081809{
    18091810    ASSERT(offset <= this->length());
     
    18241825    //    buffer without reallocing (say, 1.5 x length).
    18251826    if (length > std::numeric_limits<unsigned>::max() / 3)
    1826         return CString();
     1827        return makeUnexpected(UTF8ConversionError::OutOfMemory);
    18271828    Vector<char, 1024> bufferVector(length * 3);
    18281829
     
    18351836        ASSERT_UNUSED(result, result != targetExhausted); // (length * 3) should be sufficient for any conversion
    18361837    } else {
    1837         if (!utf8Impl(this->characters16() + offset, length, buffer, bufferVector.size(), mode))
    1838             return CString();
     1838        UTF8ConversionError error = utf8Impl(this->characters16() + offset, length, buffer, bufferVector.size(), mode);
     1839        if (error != UTF8ConversionError::None)
     1840            return makeUnexpected(error);
    18391841    }
    18401842
     
    18421844}
    18431845
     1846Expected<CString, UTF8ConversionError> StringImpl::tryGetUtf8(ConversionMode mode) const
     1847{
     1848    return tryGetUtf8ForRange(0, length(), mode);
     1849}
     1850
    18441851CString StringImpl::utf8(ConversionMode mode) const
    18451852{
    1846     return utf8ForRange(0, length(), mode);
     1853    auto expectedString = tryGetUtf8ForRange(0, length(), mode);
     1854    RELEASE_ASSERT(expectedString);
     1855    return expectedString.value();
    18471856}
    18481857
  • trunk/Source/WTF/wtf/text/StringImpl.h

    r231337 r232089  
    2828#include <wtf/ASCIICType.h>
    2929#include <wtf/CheckedArithmetic.h>
     30#include <wtf/Expected.h>
    3031#include <wtf/MathExtras.h>
    3132#include <wtf/StdLibExtras.h>
     
    3536#include <wtf/text/StringCommon.h>
    3637#include <wtf/text/StringHasher.h>
     38#include <wtf/text/UTF8ConversionError.h>
    3739
    3840#if USE(CF)
     
    285287#endif
    286288
    287     static WTF_EXPORT_PRIVATE CString utf8ForCharacters(const LChar* characters, unsigned length);
    288     static WTF_EXPORT_PRIVATE CString utf8ForCharacters(const UChar* characters, unsigned length, ConversionMode = LenientConversion);
    289     WTF_EXPORT_PRIVATE CString utf8ForRange(unsigned offset, unsigned length, ConversionMode = LenientConversion) const;
     289    static WTF_EXPORT_PRIVATE Expected<CString, UTF8ConversionError> utf8ForCharacters(const LChar* characters, unsigned length);
     290    static WTF_EXPORT_PRIVATE Expected<CString, UTF8ConversionError> utf8ForCharacters(const UChar* characters, unsigned length, ConversionMode = LenientConversion);
     291
     292    WTF_EXPORT_PRIVATE Expected<CString, UTF8ConversionError> tryGetUtf8ForRange(unsigned offset, unsigned length, ConversionMode = LenientConversion) const;
     293    WTF_EXPORT_PRIVATE Expected<CString, UTF8ConversionError> tryGetUtf8(ConversionMode = LenientConversion) const;
    290294    WTF_EXPORT_PRIVATE CString utf8(ConversionMode = LenientConversion) const;
    291295
    292296private:
    293     static WTF_EXPORT_PRIVATE bool utf8Impl(const UChar* characters, unsigned length, char*& buffer, size_t bufferSize, ConversionMode);
     297    static WTF_EXPORT_PRIVATE UTF8ConversionError utf8Impl(const UChar* characters, unsigned length, char*& buffer, size_t bufferSize, ConversionMode);
    294298   
    295299    // The high bits of 'hash' are always empty, but we prefer to store our flags
     
    12031207} // namespace WTF
    12041208
     1209using WTF::StaticStringImpl;
    12051210using WTF::StringImpl;
    1206 using WTF::StaticStringImpl;
    12071211using WTF::equal;
    12081212
  • trunk/Source/WTF/wtf/text/StringView.cpp

    r230303 r232089  
    8181}
    8282
    83 CString StringView::utf8(ConversionMode mode) const
     83Expected<CString, UTF8ConversionError> StringView::tryGetUtf8(ConversionMode mode) const
    8484{
    8585    if (isNull())
     
    8888        return StringImpl::utf8ForCharacters(characters8(), length());
    8989    return StringImpl::utf8ForCharacters(characters16(), length(), mode);
     90}
     91
     92CString StringView::utf8(ConversionMode mode) const
     93{
     94    auto expectedString = tryGetUtf8(mode);
     95    RELEASE_ASSERT(expectedString);
     96    return expectedString.value();
    9097}
    9198
  • trunk/Source/WTF/wtf/text/StringView.h

    r230130 r232089  
    3737#include <wtf/text/LChar.h>
    3838#include <wtf/text/StringCommon.h>
     39#include <wtf/text/UTF8ConversionError.h>
    3940
    4041// FIXME: Enabling the StringView lifetime checking causes the MSVC build to fail. Figure out why.
     
    107108#endif
    108109
     110    WTF_EXPORT_PRIVATE Expected<CString, UTF8ConversionError> tryGetUtf8(ConversionMode = LenientConversion) const;
    109111    WTF_EXPORT_PRIVATE CString utf8(ConversionMode = LenientConversion) const;
    110112
  • trunk/Source/WTF/wtf/text/WTFString.cpp

    r230113 r232089  
    805805}
    806806
     807Expected<CString, UTF8ConversionError> String::tryGetUtf8(ConversionMode mode) const
     808{
     809    return m_impl ? m_impl->tryGetUtf8(mode) : CString { "", 0 };
     810}
     811
     812Expected<CString, UTF8ConversionError> String::tryGetUtf8() const
     813{
     814    return tryGetUtf8(LenientConversion);
     815}
     816
    807817CString String::utf8(ConversionMode mode) const
    808818{
    809     return m_impl ? m_impl->utf8(mode) : CString { "", 0 };
     819    Expected<CString, UTF8ConversionError> expectedString = tryGetUtf8(mode);
     820    RELEASE_ASSERT(expectedString);
     821    return expectedString.value();
    810822}
    811823
  • trunk/Source/WTF/wtf/text/WTFString.h

    r231337 r232089  
    165165    WTF_EXPORT_PRIVATE CString utf8(ConversionMode) const;
    166166    WTF_EXPORT_PRIVATE CString utf8() const;
     167
     168    WTF_EXPORT_PRIVATE Expected<CString, UTF8ConversionError> tryGetUtf8(ConversionMode) const;
     169    WTF_EXPORT_PRIVATE Expected<CString, UTF8ConversionError> tryGetUtf8() const;
    167170
    168171    UChar characterAt(unsigned index) const;
Note: See TracChangeset for help on using the changeset viewer.