Changeset 263771 in webkit


Ignore:
Timestamp:
Jun 30, 2020, 2:17:01 PM (5 years ago)
Author:
mark.lam@apple.com
Message:

Add handling for a case of OOME in CSSTokenizer and CSSParser.
https://bugs.webkit.org/show_bug.cgi?id=213702
<rdar://problem/64808889>

Reviewed by Darin Adler.

Source/WebCore:

We add a bool* constructionSuccess feedback argument to the private CSSTokenizer
constructor. If construction fails and constructionSuccess is provided, the
constructor will set *constructionSuccess to false. If construction fails and
constructionSuccess is not provided, the constructor will crash with a failed
RELEASE_ASSERT. In other words, the client may opt in to handle the failure to
construct if it doesn't want the default behavior of crashing on failure.

We also provide 2 convenience factory methods for CSSTokenizer which will return
a null std::unique_ptr<CSSTokenizer> if construction fails. This is currently
only used by CSSParserImpl, and ensures that its m_tokenizer is null if we fail to
construct. This ensures that there isn't a pointer to a partially constructed
tokenizer that some code may unknowingly use.

The reason we don't force all clients of CSSTokenizer to use the factory methods
instead is because there are clients that currently use on-stack instantiations
of CSSTokenizer to do their work. We don't want to force them to switch to using
a malloc instance. Currently, the constructors used by those clients do not
provide a constructionSuccess argument to the underlying private constructor.
Hence, for them, the CSSTokenizer constructor will crash if construction fails,
which is how things work in pre-existing code. The only difference is that
the crash is deferred till the client attempts to use the tokenizer instead of at
construction time.

As of this patch, only CSSParser::parseSupportsCondition() makes use of the new
feedback mechanism, and handles OOME during CSSTokenizer construction by
interpreting it as CSS not supporting the passed in condition string.

Test: css3/out-of-memory-in-css-tokenizer.html

  • css/parser/CSSParser.cpp:

(WebCore::CSSParser::parseSupportsCondition):

  • css/parser/CSSParserImpl.cpp:

(WebCore::CSSParserImpl::CSSParserImpl):
(WebCore::CSSParserImpl::failed const):

  • css/parser/CSSParserImpl.h:
  • css/parser/CSSTokenizer.cpp:

(WebCore::CSSTokenizer::CSSTokenizer):

  • css/parser/CSSTokenizer.h:

(WebCore::CSSTokenizer::failed const):

Source/WTF:

  1. Added FailureAction so that we can parameterize how we want to handle failures. In this patch, we're only using this for allocation failures, but we could technically apply this to other types of failures as well.
  1. Apply FailureAction to many methods in Vector (and its super classes) so that we can start de-duplicating code. Previously, we were always duplicating code just to have a "try" version of the same method that reports the failure to allocate instead of crashing. We can now parameterize all these methods on a FailureAction template parameter instead, and avoid the code duplication. This patch also reverses some of the existing code duplication.
  • WTF.xcodeproj/project.pbxproj:
  • wtf/CMakeLists.txt:
  • wtf/FailureAction.h: Added.
  • wtf/Vector.h:

(WTF::VectorBufferBase::allocateBuffer):
(WTF::VectorBufferBase::tryAllocateBuffer):
(WTF::VectorBuffer::allocateBuffer):
(WTF::VectorBuffer::tryAllocateBuffer):
(WTF::Vector::reserveCapacity):
(WTF::Vector::tryReserveCapacity):
(WTF::Vector::reserveInitialCapacity):
(WTF::Vector::tryReserveInitialCapacity):
(WTF::Vector::append):
(WTF::Vector::tryAppend):
(WTF::Vector::constructAndAppend):
(WTF::Vector::tryConstructAndAppend):
(WTF::Vector::expandCapacity):
(WTF::Vector::resize):
(WTF::Vector::grow):
(WTF::Vector::reserveCapacity):
(WTF::Vector::reserveInitialCapacity):
(WTF::Vector::append):
(WTF::Vector::constructAndAppend):
(WTF::Vector::appendSlowCase):
(WTF::Vector::constructAndAppendSlowCase):
(WTF::Vector::appendVector):
(WTF::Vector::insert):
(WTF::Vector::tryExpandCapacity): Deleted.
(WTF::Vector::tryReserveCapacity): Deleted.
(WTF::Vector::tryAppend): Deleted.
(WTF::Vector::tryConstructAndAppend): Deleted.
(WTF::Vector::tryConstructAndAppendSlowCase): Deleted.

LayoutTests:

  • css3/out-of-memory-in-css-tokenizer-expected.txt: Added.
  • css3/out-of-memory-in-css-tokenizer.html: Added.
Location:
trunk
Files:
3 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r263770 r263771  
     12020-06-30  Mark Lam  <mark.lam@apple.com>
     2
     3        Add handling for a case of OOME in CSSTokenizer and CSSParser.
     4        https://bugs.webkit.org/show_bug.cgi?id=213702
     5        <rdar://problem/64808889>
     6
     7        Reviewed by Darin Adler.
     8
     9        * css3/out-of-memory-in-css-tokenizer-expected.txt: Added.
     10        * css3/out-of-memory-in-css-tokenizer.html: Added.
     11
    1122020-06-30  Karl Rackler  <rackler@apple.com>
    213
  • trunk/Source/WTF/ChangeLog

    r263764 r263771  
     12020-06-30  Mark Lam  <mark.lam@apple.com>
     2
     3        Add handling for a case of OOME in CSSTokenizer and CSSParser.
     4        https://bugs.webkit.org/show_bug.cgi?id=213702
     5        <rdar://problem/64808889>
     6
     7        Reviewed by Darin Adler.
     8
     9        1. Added FailureAction so that we can parameterize how we want to handle failures.
     10           In this patch, we're only using this for allocation failures, but we could
     11           technically apply this to other types of failures as well.
     12
     13        2. Apply FailureAction to many methods in Vector (and its super classes) so that
     14           we can start de-duplicating code.  Previously, we were always duplicating code
     15           just to have a "try" version of the same method that reports the failure to
     16           allocate instead of crashing.  We can now parameterize all these methods on a
     17           FailureAction template parameter instead, and avoid the code duplication.
     18           This patch also reverses some of the existing code duplication.
     19
     20        * WTF.xcodeproj/project.pbxproj:
     21        * wtf/CMakeLists.txt:
     22        * wtf/FailureAction.h: Added.
     23        * wtf/Vector.h:
     24        (WTF::VectorBufferBase::allocateBuffer):
     25        (WTF::VectorBufferBase::tryAllocateBuffer):
     26        (WTF::VectorBuffer::allocateBuffer):
     27        (WTF::VectorBuffer::tryAllocateBuffer):
     28        (WTF::Vector::reserveCapacity):
     29        (WTF::Vector::tryReserveCapacity):
     30        (WTF::Vector::reserveInitialCapacity):
     31        (WTF::Vector::tryReserveInitialCapacity):
     32        (WTF::Vector::append):
     33        (WTF::Vector::tryAppend):
     34        (WTF::Vector::constructAndAppend):
     35        (WTF::Vector::tryConstructAndAppend):
     36        (WTF::Vector::expandCapacity):
     37        (WTF::Vector::resize):
     38        (WTF::Vector::grow):
     39        (WTF::Vector::reserveCapacity):
     40        (WTF::Vector::reserveInitialCapacity):
     41        (WTF::Vector::append):
     42        (WTF::Vector::constructAndAppend):
     43        (WTF::Vector::appendSlowCase):
     44        (WTF::Vector::constructAndAppendSlowCase):
     45        (WTF::Vector::appendVector):
     46        (WTF::Vector::insert):
     47        (WTF::Vector::tryExpandCapacity): Deleted.
     48        (WTF::Vector::tryReserveCapacity): Deleted.
     49        (WTF::Vector::tryAppend): Deleted.
     50        (WTF::Vector::tryConstructAndAppend): Deleted.
     51        (WTF::Vector::tryConstructAndAppendSlowCase): Deleted.
     52
    1532020-06-30  Peng Liu  <peng.liu6@apple.com>
    254
  • trunk/Source/WTF/WTF.xcodeproj/project.pbxproj

    r263759 r263771  
    758758                FE8925AF1D00DAEC0046907E /* Indenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Indenter.h; sourceTree = "<group>"; };
    759759                FE97F6A8245CE5DD00C63FC6 /* StdIntExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StdIntExtras.h; sourceTree = "<group>"; };
     760                FE996B5224A845AF001D2E63 /* FailureAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FailureAction.h; sourceTree = "<group>"; };
    760761                FEB6B035201BE0B600B958C1 /* PointerPreparations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PointerPreparations.h; sourceTree = "<group>"; };
    761762                FEDACD3B1630F83F00C69634 /* StackStats.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StackStats.cpp; sourceTree = "<group>"; };
     
    10171018                                AD7C434A1DD2A4A70026888B /* Expected.h */,
    10181019                                A8A4729F151A825A004123FF /* ExportMacros.h */,
     1020                                FE996B5224A845AF001D2E63 /* FailureAction.h */,
    10191021                                0F7C5FB51D885CF20044F5E2 /* FastBitVector.cpp */,
    10201022                                0FD81AC4154FB22E00983E72 /* FastBitVector.h */,
  • trunk/Source/WTF/wtf/CMakeLists.txt

    r263759 r263771  
    6363    Expected.h
    6464    ExportMacros.h
     65    FailureAction.h
    6566    FastBitVector.h
    6667    FastMalloc.h
  • trunk/Source/WTF/wtf/Vector.h

    r261393 r263771  
    11/*
    2  *  Copyright (C) 2005-2019 Apple Inc. All rights reserved.
     2 *  Copyright (C) 2005-2020 Apple Inc. All rights reserved.
    33 *
    44 *  This library is free software; you can redistribute it and/or
     
    2727#include <utility>
    2828#include <wtf/CheckedArithmetic.h>
     29#include <wtf/FailureAction.h>
    2930#include <wtf/FastMalloc.h>
    3031#include <wtf/Forward.h>
     
    283284    WTF_MAKE_NONCOPYABLE(VectorBufferBase);
    284285public:
    285     void allocateBuffer(size_t newCapacity)
    286     {
     286    template<FailureAction action>
     287    bool allocateBuffer(size_t newCapacity)
     288    {
     289        static_assert(action == FailureAction::Crash || action == FailureAction::Report);
    287290        ASSERT(newCapacity);
    288         if (newCapacity > std::numeric_limits<unsigned>::max() / sizeof(T))
    289             CRASH();
     291        if (newCapacity > std::numeric_limits<unsigned>::max() / sizeof(T)) {
     292            if constexpr (action == FailureAction::Crash)
     293                CRASH();
     294            else
     295                return false;
     296        }
     297
    290298        size_t sizeToAllocate = newCapacity * sizeof(T);
    291         m_capacity = sizeToAllocate / sizeof(T);
    292         m_buffer = static_cast<T*>(Malloc::malloc(sizeToAllocate));
    293     }
    294 
    295     bool tryAllocateBuffer(size_t newCapacity)
    296     {
    297         ASSERT(newCapacity);
    298         if (newCapacity > std::numeric_limits<unsigned>::max() / sizeof(T))
    299             return false;
    300 
    301         size_t sizeToAllocate = newCapacity * sizeof(T);
    302         T* newBuffer = static_cast<T*>(Malloc::tryMalloc(sizeToAllocate));
    303         if (!newBuffer)
    304             return false;
     299        T* newBuffer = nullptr;
     300        if constexpr (action == FailureAction::Crash)
     301            newBuffer = static_cast<T*>(Malloc::malloc(sizeToAllocate));
     302        else {
     303            newBuffer = static_cast<T*>(Malloc::tryMalloc(sizeToAllocate));
     304            if (UNLIKELY(!newBuffer))
     305                return false;
     306        }
    305307        m_capacity = sizeToAllocate / sizeof(T);
    306308        m_buffer = newBuffer;
    307309        return true;
    308310    }
     311
     312    ALWAYS_INLINE void allocateBuffer(size_t newCapacity) { allocateBuffer<FailureAction::Crash>(newCapacity); }
     313    ALWAYS_INLINE bool tryAllocateBuffer(size_t newCapacity) { return allocateBuffer<FailureAction::Report>(newCapacity); }
    309314
    310315    bool shouldReallocateBuffer(size_t newCapacity) const
     
    458463    }
    459464
    460     void allocateBuffer(size_t newCapacity)
     465    template<FailureAction action>
     466    bool allocateBuffer(size_t newCapacity)
    461467    {
    462468        // FIXME: This should ASSERT(!m_buffer) to catch misuse/leaks.
    463469        if (newCapacity > inlineCapacity)
    464             Base::allocateBuffer(newCapacity);
    465         else {
    466             m_buffer = inlineBuffer();
    467             m_capacity = inlineCapacity;
    468         }
    469     }
    470 
    471     bool tryAllocateBuffer(size_t newCapacity)
    472     {
    473         if (newCapacity > inlineCapacity)
    474             return Base::tryAllocateBuffer(newCapacity);
     470            return Base::template allocateBuffer<action>(newCapacity);
    475471        m_buffer = inlineBuffer();
    476472        m_capacity = inlineCapacity;
    477473        return true;
    478474    }
     475
     476    ALWAYS_INLINE void allocateBuffer(size_t newCapacity) { allocateBuffer<FailureAction::Crash>(newCapacity); }
     477    ALWAYS_INLINE bool tryAllocateBuffer(size_t newCapacity) { return allocateBuffer<FailureAction::Report>(newCapacity); }
    479478
    480479    void deallocateBuffer(T* bufferToDeallocate)
     
    762761    void resize(size_t size);
    763762    void resizeToFit(size_t size);
    764     void reserveCapacity(size_t newCapacity);
    765     bool tryReserveCapacity(size_t newCapacity);
    766     void reserveInitialCapacity(size_t initialCapacity);
     763    ALWAYS_INLINE void reserveCapacity(size_t newCapacity) { reserveCapacity<FailureAction::Crash>(newCapacity); }
     764    ALWAYS_INLINE bool tryReserveCapacity(size_t newCapacity) { return reserveCapacity<FailureAction::Report>(newCapacity); }
     765    ALWAYS_INLINE void reserveInitialCapacity(size_t initialCapacity) { reserveInitialCapacity<FailureAction::Crash>(initialCapacity); }
     766    ALWAYS_INLINE bool tryReserveInitialCapacity(size_t initialCapacity) { return reserveInitialCapacity<FailureAction::Report>(initialCapacity); }
    767767    void shrinkCapacity(size_t newCapacity);
    768768    void shrinkToFit() { shrinkCapacity(size()); }
     
    773773
    774774    ALWAYS_INLINE void append(ValueType&& value) { append<ValueType>(std::forward<ValueType>(value)); }
    775     template<typename U> void append(U&&);
    776     template<typename... Args> void constructAndAppend(Args&&...);
    777     template<typename... Args> bool tryConstructAndAppend(Args&&...);
     775    template<typename U> ALWAYS_INLINE void append(U&& u) { append<FailureAction::Crash, U>(std::forward<U>(u)); }
     776    template<typename U> ALWAYS_INLINE bool tryAppend(U&& u) { return append<FailureAction::Report, U>(std::forward<U>(u)); }
     777    template<typename... Args> ALWAYS_INLINE void constructAndAppend(Args&&... args) { constructAndAppend<FailureAction::Crash>(std::forward<Args>(args)...); }
     778    template<typename... Args> ALWAYS_INLINE bool tryConstructAndAppend(Args&&... args) { return constructAndAppend<FailureAction::Report>(std::forward<Args>(args)...); }
    778779
    779780    void uncheckedAppend(ValueType&& value) { uncheckedAppend<ValueType>(std::forward<ValueType>(value)); }
     
    781782    template<typename... Args> void uncheckedConstructAndAppend(Args&&...);
    782783
    783     template<typename U> void append(const U*, size_t);
     784    template<typename U> ALWAYS_INLINE void append(const U* u, size_t size) { append<FailureAction::Crash>(u, size); }
     785    template<typename U> ALWAYS_INLINE bool tryAppend(const U* u, size_t size) { return append<FailureAction::Report>(u, size); }
    784786    template<typename U, size_t otherCapacity> void appendVector(const Vector<U, otherCapacity>&);
    785787    template<typename U, size_t otherCapacity> void appendVector(Vector<U, otherCapacity>&&);
    786     template<typename U> bool tryAppend(const U*, size_t);
    787788
    788789    template<typename U> void insert(size_t position, const U*, size_t);
     
    838839
    839840private:
    840     void expandCapacity(size_t newMinCapacity);
    841     T* expandCapacity(size_t newMinCapacity, T*);
    842     bool tryExpandCapacity(size_t newMinCapacity);
    843     const T* tryExpandCapacity(size_t newMinCapacity, const T*);
    844     template<typename U> U* expandCapacity(size_t newMinCapacity, U*);
    845     template<typename U> void appendSlowCase(U&&);
    846     template<typename... Args> void constructAndAppendSlowCase(Args&&...);
    847     template<typename... Args> bool tryConstructAndAppendSlowCase(Args&&...);
     841    template<FailureAction> bool reserveCapacity(size_t newCapacity);
     842    template<FailureAction> bool reserveInitialCapacity(size_t initialCapacity);
     843
     844    template<FailureAction> bool expandCapacity(size_t newMinCapacity);
     845    template<FailureAction> T* expandCapacity(size_t newMinCapacity, T*);
     846    template<FailureAction, typename U> U* expandCapacity(size_t newMinCapacity, U*);
     847    template<FailureAction, typename U> bool appendSlowCase(U&&);
     848    template<FailureAction, typename... Args> bool constructAndAppend(Args&&...);
     849    template<FailureAction, typename... Args> bool constructAndAppendSlowCase(Args&&...);
     850
     851    template<FailureAction, typename U> bool append(U&&);
     852    template<FailureAction, typename U> bool append(const U*, size_t);
    848853
    849854    template<size_t position, typename U, typename... Items>
     
    10441049
    10451050template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1046 void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::expandCapacity(size_t newMinCapacity)
    1047 {
    1048     reserveCapacity(std::max(newMinCapacity, std::max(static_cast<size_t>(minCapacity), capacity() + capacity() / 4 + 1)));
    1049 }
    1050 
    1051 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
     1051template<FailureAction action>
     1052bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::expandCapacity(size_t newMinCapacity)
     1053{
     1054    return reserveCapacity<action>(std::max(newMinCapacity, std::max(static_cast<size_t>(minCapacity), capacity() + capacity() / 4 + 1)));
     1055}
     1056
     1057template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
     1058template<FailureAction action>
    10521059NEVER_INLINE T* Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::expandCapacity(size_t newMinCapacity, T* ptr)
    10531060{
     1061    static_assert(action == FailureAction::Crash || action == FailureAction::Report);
    10541062    if (ptr < begin() || ptr >= end()) {
    1055         expandCapacity(newMinCapacity);
     1063        bool success = expandCapacity<action>(newMinCapacity);
     1064        if constexpr (action == FailureAction::Report) {
     1065            if (UNLIKELY(!success))
     1066                return nullptr;
     1067        }
    10561068        return ptr;
    10571069    }
    10581070    size_t index = ptr - begin();
    1059     expandCapacity(newMinCapacity);
     1071    bool success = expandCapacity<action>(newMinCapacity);
     1072    if constexpr (action == FailureAction::Report) {
     1073        if (UNLIKELY(!success))
     1074            return nullptr;
     1075    }
    10601076    return begin() + index;
    10611077}
    10621078
    10631079template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1064 bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::tryExpandCapacity(size_t newMinCapacity)
    1065 {
    1066     return tryReserveCapacity(std::max(newMinCapacity, std::max(static_cast<size_t>(minCapacity), capacity() + capacity() / 4 + 1)));
    1067 }
    1068 
    1069 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1070 const T* Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::tryExpandCapacity(size_t newMinCapacity, const T* ptr)
    1071 {
    1072     if (ptr < begin() || ptr >= end()) {
    1073         if (!tryExpandCapacity(newMinCapacity))
    1074             return 0;
    1075         return ptr;
    1076     }
    1077     size_t index = ptr - begin();
    1078     if (!tryExpandCapacity(newMinCapacity))
    1079         return 0;
    1080     return begin() + index;
    1081 }
    1082 
    1083 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1084 template<typename U>
     1080template<FailureAction action, typename U>
    10851081inline U* Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::expandCapacity(size_t newMinCapacity, U* ptr)
    10861082{
    1087     expandCapacity(newMinCapacity);
     1083    static_assert(action == FailureAction::Crash || action == FailureAction::Report);
     1084    bool success = expandCapacity<action>(newMinCapacity);
     1085    if constexpr (action == FailureAction::Report) {
     1086        if (UNLIKELY(!success))
     1087            return nullptr;
     1088    }
    10881089    return ptr;
    10891090}
     
    10971098    } else {
    10981099        if (size > capacity())
    1099             expandCapacity(size);
     1100            expandCapacity<FailureAction::Crash>(size);
    11001101        asanBufferSizeWillChangeTo(size);
    11011102        if (begin())
     
    11271128    ASSERT(size >= m_size);
    11281129    if (size > capacity())
    1129         expandCapacity(size);
     1130        expandCapacity<FailureAction::Crash>(size);
    11301131    asanBufferSizeWillChangeTo(size);
    11311132    if (begin())
     
    11791180
    11801181template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1181 void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::reserveCapacity(size_t newCapacity)
    1182 {
    1183     if (newCapacity <= capacity())
    1184         return;
    1185     T* oldBuffer = begin();
    1186     T* oldEnd = end();
    1187 
    1188     asanSetBufferSizeToFullCapacity();
    1189 
    1190     Base::allocateBuffer(newCapacity);
    1191     ASSERT(begin());
    1192 
    1193     asanSetInitialBufferSizeTo(size());
    1194 
    1195     TypeOperations::move(oldBuffer, oldEnd, begin());
    1196     Base::deallocateBuffer(oldBuffer);
    1197 }
    1198 
    1199 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1200 bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::tryReserveCapacity(size_t newCapacity)
    1201 {
     1182template<FailureAction action>
     1183bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::reserveCapacity(size_t newCapacity)
     1184{
     1185    static_assert(action == FailureAction::Crash || action == FailureAction::Report);
    12021186    if (newCapacity <= capacity())
    12031187        return true;
     
    12071191    asanSetBufferSizeToFullCapacity();
    12081192
    1209     if (!Base::tryAllocateBuffer(newCapacity)) {
    1210         asanSetInitialBufferSizeTo(size());
    1211         return false;
     1193    bool success = Base::template allocateBuffer<action>(newCapacity);
     1194    if constexpr (action == FailureAction::Report) {
     1195        if (UNLIKELY(!success)) {
     1196            asanSetInitialBufferSizeTo(size());
     1197            return false;
     1198        }
    12121199    }
    12131200    ASSERT(begin());
     
    12211208
    12221209template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1223 inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::reserveInitialCapacity(size_t initialCapacity)
    1224 {
     1210template<FailureAction action>
     1211inline bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::reserveInitialCapacity(size_t initialCapacity)
     1212{
     1213    static_assert(action == FailureAction::Crash || action == FailureAction::Report);
    12251214    ASSERT(!m_size);
    12261215    ASSERT(capacity() == inlineCapacity);
    1227     if (initialCapacity > inlineCapacity)
    1228         Base::allocateBuffer(initialCapacity);
     1216    if (initialCapacity <= inlineCapacity)
     1217        return true;
     1218    return Base::template allocateBuffer<action>(initialCapacity);
    12291219}
    12301220
     
    12611251
    12621252template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1263 template<typename U>
    1264 ALWAYS_INLINE void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::append(const U* data, size_t dataSize)
    1265 {
     1253template<FailureAction action, typename U>
     1254ALWAYS_INLINE bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::append(const U* data, size_t dataSize)
     1255{
     1256    static_assert(action == FailureAction::Crash || action == FailureAction::Report);
    12661257    size_t newSize = m_size + dataSize;
    12671258    if (newSize > capacity()) {
    1268         data = expandCapacity(newSize, data);
     1259        data = expandCapacity<action>(newSize, data);
     1260        if constexpr (action == FailureAction::Report) {
     1261            if (UNLIKELY(!data))
     1262                return false;
     1263        }
    12691264        ASSERT(begin());
    12701265    }
    1271     if (newSize < m_size)
    1272         CRASH();
    1273     asanBufferSizeWillChangeTo(newSize);
    1274     T* dest = end();
    1275     VectorCopier<std::is_trivial<T>::value, U>::uninitializedCopy(data, std::addressof(data[dataSize]), dest);
    1276     m_size = newSize;
    1277 }
    1278 
    1279 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1280 template<typename U>
    1281 ALWAYS_INLINE bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::tryAppend(const U* data, size_t dataSize)
    1282 {
    1283     size_t newSize = m_size + dataSize;
    1284     if (newSize > capacity()) {
    1285         data = tryExpandCapacity(newSize, data);
    1286         if (!data)
     1266    if (newSize < m_size) {
     1267        if constexpr (action == FailureAction::Crash)
     1268            CRASH();
     1269        else
    12871270            return false;
    1288         ASSERT(begin());
    1289     }
    1290     if (newSize < m_size)
    1291         return false;
     1271    }
    12921272    asanBufferSizeWillChangeTo(newSize);
    12931273    T* dest = end();
     
    12981278
    12991279template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1300 template<typename U>
    1301 ALWAYS_INLINE void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::append(U&& value)
     1280template<FailureAction action, typename U>
     1281ALWAYS_INLINE bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::append(U&& value)
    13021282{
    13031283    if (size() != capacity()) {
     
    13051285        new (NotNull, end()) T(std::forward<U>(value));
    13061286        ++m_size;
    1307         return;
    1308     }
    1309 
    1310     appendSlowCase(std::forward<U>(value));
    1311 }
    1312 
    1313 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1314 template<typename... Args>
    1315 ALWAYS_INLINE void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::constructAndAppend(Args&&... args)
    1316 {
    1317     if (size() != capacity()) {
    1318         asanBufferSizeWillChangeTo(m_size + 1);
    1319         new (NotNull, end()) T(std::forward<Args>(args)...);
    1320         ++m_size;
    1321         return;
    1322     }
    1323 
    1324     constructAndAppendSlowCase(std::forward<Args>(args)...);
    1325 }
    1326 
    1327 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1328 template<typename... Args>
    1329 ALWAYS_INLINE bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::tryConstructAndAppend(Args&&... args)
     1287        return true;
     1288    }
     1289
     1290    return appendSlowCase<action, U>(std::forward<U>(value));
     1291}
     1292
     1293template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
     1294template<FailureAction action, typename... Args>
     1295ALWAYS_INLINE bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::constructAndAppend(Args&&... args)
    13301296{
    13311297    if (size() != capacity()) {
     
    13351301        return true;
    13361302    }
    1337    
    1338     return tryConstructAndAppendSlowCase(std::forward<Args>(args)...);
    1339 }
    1340 
    1341 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1342 template<typename U>
    1343 void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::appendSlowCase(U&& value)
    1344 {
     1303
     1304    return constructAndAppendSlowCase<action>(std::forward<Args>(args)...);
     1305}
     1306
     1307template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
     1308template<FailureAction action, typename U>
     1309bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::appendSlowCase(U&& value)
     1310{
     1311    static_assert(action == FailureAction::Crash || action == FailureAction::Report);
    13451312    ASSERT(size() == capacity());
    13461313
    13471314    auto ptr = const_cast<typename std::remove_const<typename std::remove_reference<U>::type>::type*>(std::addressof(value));
    1348     ptr = expandCapacity(size() + 1, ptr);
     1315    ptr = expandCapacity<action>(size() + 1, ptr);
     1316    if constexpr (action == FailureAction::Report) {
     1317        if (UNLIKELY(!ptr))
     1318            return false;
     1319    }
    13491320    ASSERT(begin());
    13501321
     
    13521323    new (NotNull, end()) T(std::forward<U>(*ptr));
    13531324    ++m_size;
    1354 }
    1355 
    1356 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1357 template<typename... Args>
    1358 void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::constructAndAppendSlowCase(Args&&... args)
    1359 {
     1325    return true;
     1326}
     1327
     1328template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
     1329template<FailureAction action, typename... Args>
     1330bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::constructAndAppendSlowCase(Args&&... args)
     1331{
     1332    static_assert(action == FailureAction::Crash || action == FailureAction::Report);
    13601333    ASSERT(size() == capacity());
    13611334
    1362     expandCapacity(size() + 1);
     1335    bool success = expandCapacity<action>(size() + 1);
     1336    if constexpr (action == FailureAction::Report) {
     1337        if (UNLIKELY(!success))
     1338            return false;
     1339    }
    13631340    ASSERT(begin());
    13641341
    1365     asanBufferSizeWillChangeTo(m_size + 1);
    1366     new (NotNull, end()) T(std::forward<Args>(args)...);
    1367     ++m_size;
    1368 }
    1369 
    1370 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
    1371 template<typename... Args>
    1372 bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::tryConstructAndAppendSlowCase(Args&&... args)
    1373 {
    1374     ASSERT(size() == capacity());
    1375    
    1376     if (UNLIKELY(!tryExpandCapacity(size() + 1)))
    1377         return false;
    1378     ASSERT(begin());
    1379    
    13801342    asanBufferSizeWillChangeTo(m_size + 1);
    13811343    new (NotNull, end()) T(std::forward<Args>(args)...);
     
    14241386    size_t newSize = m_size + val.size();
    14251387    if (newSize > capacity())
    1426         expandCapacity(newSize);
     1388        expandCapacity<FailureAction::Crash>(newSize);
    14271389    for (auto& item : val)
    14281390        uncheckedAppend(WTFMove(item));
     
    14361398    size_t newSize = m_size + dataSize;
    14371399    if (newSize > capacity()) {
    1438         data = expandCapacity(newSize, data);
     1400        data = expandCapacity<FailureAction::Crash>(newSize, data);
    14391401        ASSERT(begin());
    14401402    }
     
    14561418    auto ptr = const_cast<typename std::remove_const<typename std::remove_reference<U>::type>::type*>(std::addressof(value));
    14571419    if (size() == capacity()) {
    1458         ptr = expandCapacity(size() + 1, ptr);
     1420        ptr = expandCapacity<FailureAction::Crash>(size() + 1, ptr);
    14591421        ASSERT(begin());
    14601422    }
  • trunk/Source/WebCore/ChangeLog

    r263764 r263771  
     12020-06-30  Mark Lam  <mark.lam@apple.com>
     2
     3        Add handling for a case of OOME in CSSTokenizer and CSSParser.
     4        https://bugs.webkit.org/show_bug.cgi?id=213702
     5        <rdar://problem/64808889>
     6
     7        Reviewed by Darin Adler.
     8
     9        We add a bool* constructionSuccess feedback argument to the private CSSTokenizer
     10        constructor.  If construction fails and constructionSuccess is provided, the
     11        constructor will set *constructionSuccess to false.  If construction fails and
     12        constructionSuccess is not provided, the constructor will crash with a failed
     13        RELEASE_ASSERT.  In other words, the client may opt in to handle the failure to
     14        construct if it doesn't want the default behavior of crashing on failure.
     15
     16        We also provide 2 convenience factory methods for CSSTokenizer which will return
     17        a null std::unique_ptr<CSSTokenizer> if construction fails.  This is currently
     18        only used by CSSParserImpl, and ensures that its m_tokenizer is null if we fail to
     19        construct.  This ensures that there isn't a pointer to a partially constructed
     20        tokenizer that some code may unknowingly use.
     21
     22        The reason we don't force all clients of CSSTokenizer to use the factory methods
     23        instead is because there are clients that currently use on-stack instantiations
     24        of CSSTokenizer to do their work.  We don't want to force them to switch to using
     25        a malloc instance.  Currently, the constructors used by those clients do not
     26        provide a constructionSuccess argument to the underlying private constructor.
     27        Hence, for them, the CSSTokenizer constructor will crash if construction fails,
     28        which is how things work in pre-existing code.  The only difference is that
     29        the crash is deferred till the client attempts to use the tokenizer instead of at
     30        construction time.
     31
     32        As of this patch, only CSSParser::parseSupportsCondition() makes use of the new
     33        feedback mechanism, and handles OOME during CSSTokenizer construction by
     34        interpreting it as CSS not supporting the passed in condition string.
     35
     36        Test: css3/out-of-memory-in-css-tokenizer.html
     37
     38        * css/parser/CSSParser.cpp:
     39        (WebCore::CSSParser::parseSupportsCondition):
     40        * css/parser/CSSParserImpl.cpp:
     41        (WebCore::CSSParserImpl::CSSParserImpl):
     42        (WebCore::CSSParserImpl::failed const):
     43        * css/parser/CSSParserImpl.h:
     44        * css/parser/CSSTokenizer.cpp:
     45        (WebCore::CSSTokenizer::CSSTokenizer):
     46        * css/parser/CSSTokenizer.h:
     47        (WebCore::CSSTokenizer::failed const):
     48
    1492020-06-30  Peng Liu  <peng.liu6@apple.com>
    250
  • trunk/Source/WebCore/css/parser/CSSParser.cpp

    r262155 r263771  
    22 * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
    33 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
    4  * Copyright (C) 2004-2016 Apple Inc. All rights reserved.
     4 * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
    55 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
    66 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
     
    9090{
    9191    CSSParserImpl parser(m_context, condition);
     92    if (!parser.tokenizer())
     93        return false;
    9294    return CSSSupportsParser::supportsCondition(parser.tokenizer()->tokenRange(), parser, CSSSupportsParser::ForWindowCSS) == CSSSupportsParser::Supported;
    9395}
  • trunk/Source/WebCore/css/parser/CSSParserImpl.cpp

    r259006 r263771  
    11// Copyright 2014 The Chromium Authors. All rights reserved.
    2 // Copyright (C) 2016 Apple Inc. All rights reserved.
     2// Copyright (C) 2016-2020 Apple Inc. All rights reserved.
    33//
    44// Redistribution and use in source and binary forms, with or without
     
    7878    , m_observerWrapper(wrapper)
    7979{
    80     m_tokenizer = wrapper ? makeUnique<CSSTokenizer>(string, *wrapper) : makeUnique<CSSTokenizer>(string);
     80    m_tokenizer = wrapper ? CSSTokenizer::tryCreate(string, *wrapper) : CSSTokenizer::tryCreate(string);
     81    if (!m_tokenizer)
     82        return;
    8183    if (context.deferredCSSParserEnabled && !wrapper && styleSheet && ruleParsing == CSSParser::RuleParsing::Deferred)
    8284        m_deferredParser = CSSDeferredParser::create(context, string, *styleSheet);
  • trunk/Source/WebCore/css/parser/CSSParserImpl.h

    r257696 r263771  
    11// Copyright 2014 The Chromium Authors. All rights reserved.
    2 // Copyright (C) 2016 Apple Inc. All rights reserved.
     2// Copyright (C) 2016-2020 Apple Inc. All rights reserved.
    33//
    44// Redistribution and use in source and binary forms, with or without
  • trunk/Source/WebCore/css/parser/CSSTokenizer.cpp

    r259773 r263771  
    11// Copyright 2015 The Chromium Authors. All rights reserved.
    2 // Copyright (C) 2016 Apple Inc. All rights reserved.
     2// Copyright (C) 2016-2020 Apple Inc. All rights reserved.
    33//
    44// Redistribution and use in source and binary forms, with or without
     
    4949}
    5050
     51std::unique_ptr<CSSTokenizer> CSSTokenizer::tryCreate(const String& string)
     52{
     53    bool success = true;
     54    // We can't use makeUnique here because it does not have access to this private constructor.
     55    auto tokenizer = std::unique_ptr<CSSTokenizer>(new CSSTokenizer(preprocessString(string), nullptr, &success));
     56    if (UNLIKELY(!success))
     57        return nullptr;
     58    return tokenizer;
     59}
     60
     61std::unique_ptr<CSSTokenizer> CSSTokenizer::tryCreate(const String& string, CSSParserObserverWrapper& wrapper)
     62{
     63    bool success = true;
     64    // We can't use makeUnique here because it does not have access to this private constructor.
     65    auto tokenizer = std::unique_ptr<CSSTokenizer>(new CSSTokenizer(preprocessString(string), &wrapper, &success));
     66    if (UNLIKELY(!success))
     67        return nullptr;
     68    return tokenizer;
     69}
     70
    5171CSSTokenizer::CSSTokenizer(const String& string)
    52     : CSSTokenizer(preprocessString(string), nullptr)
     72    : CSSTokenizer(preprocessString(string), nullptr, nullptr)
    5373{
    5474}
    5575
    5676CSSTokenizer::CSSTokenizer(const String& string, CSSParserObserverWrapper& wrapper)
    57     : CSSTokenizer(preprocessString(string), &wrapper)
    58 {
    59 }
    60 
    61 inline CSSTokenizer::CSSTokenizer(String&& string, CSSParserObserverWrapper* wrapper)
     77    : CSSTokenizer(preprocessString(string), &wrapper, nullptr)
     78{
     79}
     80
     81CSSTokenizer::CSSTokenizer(String&& string, CSSParserObserverWrapper* wrapper, bool* constructionSuccessPtr)
    6282    : m_input(string)
    6383{
     84    if (constructionSuccessPtr)
     85        *constructionSuccessPtr = true;
     86
    6487    if (string.isEmpty())
    6588        return;
     
    6790    // To avoid resizing we err on the side of reserving too much space.
    6891    // Most strings we tokenize have about 3.5 to 5 characters per token.
    69     m_tokens.reserveInitialCapacity(string.length() / 3);
     92    if (UNLIKELY(!m_tokens.tryReserveInitialCapacity(string.length() / 3))) {
     93        // When constructionSuccessPtr is null, our policy is to crash on failure.
     94        RELEASE_ASSERT(constructionSuccessPtr);
     95        *constructionSuccessPtr = false;
     96        return;
     97    }
    7098
    7199    unsigned offset = 0;
     
    78106                wrapper->addComment(offset, m_input.offset(), m_tokens.size());
    79107        } else {
    80             m_tokens.append(token);
     108            if (UNLIKELY(!m_tokens.tryAppend(token))) {
     109                // When constructionSuccessPtr is null, our policy is to crash on failure.
     110                RELEASE_ASSERT(constructionSuccessPtr);
     111                *constructionSuccessPtr = false;
     112                return;
     113            }
    81114            if (wrapper)
    82115                wrapper->addToken(offset);
  • trunk/Source/WebCore/css/parser/CSSTokenizer.h

    r259773 r263771  
    11// Copyright 2014 The Chromium Authors. All rights reserved.
    2 // Copyright (C) 2016 Apple Inc. All rights reserved.
     2// Copyright (C) 2016-2020 Apple Inc. All rights reserved.
    33//
    44// Redistribution and use in source and binary forms, with or without
     
    4646    WTF_MAKE_FAST_ALLOCATED;
    4747public:
     48    static std::unique_ptr<CSSTokenizer> tryCreate(const String&);
     49    static std::unique_ptr<CSSTokenizer> tryCreate(const String&, CSSParserObserverWrapper&); // For the inspector
     50
    4851    explicit CSSTokenizer(const String&);
    4952    CSSTokenizer(const String&, CSSParserObserverWrapper&); // For the inspector
     
    5558
    5659private:
    57     CSSTokenizer(String&&, CSSParserObserverWrapper*);
     60    CSSTokenizer(String&&, CSSParserObserverWrapper*, bool* constructionSuccess);
    5861
    5962    CSSParserToken nextToken();
Note: See TracChangeset for help on using the changeset viewer.