Changeset 263771 in webkit
- Timestamp:
- Jun 30, 2020, 2:17:01 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r263770 r263771 1 2020-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 1 12 2020-06-30 Karl Rackler <rackler@apple.com> 2 13 -
trunk/Source/WTF/ChangeLog
r263764 r263771 1 2020-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 1 53 2020-06-30 Peng Liu <peng.liu6@apple.com> 2 54 -
trunk/Source/WTF/WTF.xcodeproj/project.pbxproj
r263759 r263771 758 758 FE8925AF1D00DAEC0046907E /* Indenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Indenter.h; sourceTree = "<group>"; }; 759 759 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>"; }; 760 761 FEB6B035201BE0B600B958C1 /* PointerPreparations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PointerPreparations.h; sourceTree = "<group>"; }; 761 762 FEDACD3B1630F83F00C69634 /* StackStats.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StackStats.cpp; sourceTree = "<group>"; }; … … 1017 1018 AD7C434A1DD2A4A70026888B /* Expected.h */, 1018 1019 A8A4729F151A825A004123FF /* ExportMacros.h */, 1020 FE996B5224A845AF001D2E63 /* FailureAction.h */, 1019 1021 0F7C5FB51D885CF20044F5E2 /* FastBitVector.cpp */, 1020 1022 0FD81AC4154FB22E00983E72 /* FastBitVector.h */, -
trunk/Source/WTF/wtf/CMakeLists.txt
r263759 r263771 63 63 Expected.h 64 64 ExportMacros.h 65 FailureAction.h 65 66 FastBitVector.h 66 67 FastMalloc.h -
trunk/Source/WTF/wtf/Vector.h
r261393 r263771 1 1 /* 2 * Copyright (C) 2005-20 19Apple Inc. All rights reserved.2 * Copyright (C) 2005-2020 Apple Inc. All rights reserved. 3 3 * 4 4 * This library is free software; you can redistribute it and/or … … 27 27 #include <utility> 28 28 #include <wtf/CheckedArithmetic.h> 29 #include <wtf/FailureAction.h> 29 30 #include <wtf/FastMalloc.h> 30 31 #include <wtf/Forward.h> … … 283 284 WTF_MAKE_NONCOPYABLE(VectorBufferBase); 284 285 public: 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); 287 290 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 290 298 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 } 305 307 m_capacity = sizeToAllocate / sizeof(T); 306 308 m_buffer = newBuffer; 307 309 return true; 308 310 } 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); } 309 314 310 315 bool shouldReallocateBuffer(size_t newCapacity) const … … 458 463 } 459 464 460 void allocateBuffer(size_t newCapacity) 465 template<FailureAction action> 466 bool allocateBuffer(size_t newCapacity) 461 467 { 462 468 // FIXME: This should ASSERT(!m_buffer) to catch misuse/leaks. 463 469 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); 475 471 m_buffer = inlineBuffer(); 476 472 m_capacity = inlineCapacity; 477 473 return true; 478 474 } 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); } 479 478 480 479 void deallocateBuffer(T* bufferToDeallocate) … … 762 761 void resize(size_t size); 763 762 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); } 767 767 void shrinkCapacity(size_t newCapacity); 768 768 void shrinkToFit() { shrinkCapacity(size()); } … … 773 773 774 774 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)...); } 778 779 779 780 void uncheckedAppend(ValueType&& value) { uncheckedAppend<ValueType>(std::forward<ValueType>(value)); } … … 781 782 template<typename... Args> void uncheckedConstructAndAppend(Args&&...); 782 783 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); } 784 786 template<typename U, size_t otherCapacity> void appendVector(const Vector<U, otherCapacity>&); 785 787 template<typename U, size_t otherCapacity> void appendVector(Vector<U, otherCapacity>&&); 786 template<typename U> bool tryAppend(const U*, size_t);787 788 788 789 template<typename U> void insert(size_t position, const U*, size_t); … … 838 839 839 840 private: 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); 848 853 849 854 template<size_t position, typename U, typename... Items> … … 1044 1049 1045 1050 template<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> 1051 template<FailureAction action> 1052 bool 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 1057 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc> 1058 template<FailureAction action> 1052 1059 NEVER_INLINE T* Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::expandCapacity(size_t newMinCapacity, T* ptr) 1053 1060 { 1061 static_assert(action == FailureAction::Crash || action == FailureAction::Report); 1054 1062 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 } 1056 1068 return ptr; 1057 1069 } 1058 1070 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 } 1060 1076 return begin() + index; 1061 1077 } 1062 1078 1063 1079 template<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> 1080 template<FailureAction action, typename U> 1085 1081 inline U* Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::expandCapacity(size_t newMinCapacity, U* ptr) 1086 1082 { 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 } 1088 1089 return ptr; 1089 1090 } … … 1097 1098 } else { 1098 1099 if (size > capacity()) 1099 expandCapacity (size);1100 expandCapacity<FailureAction::Crash>(size); 1100 1101 asanBufferSizeWillChangeTo(size); 1101 1102 if (begin()) … … 1127 1128 ASSERT(size >= m_size); 1128 1129 if (size > capacity()) 1129 expandCapacity (size);1130 expandCapacity<FailureAction::Crash>(size); 1130 1131 asanBufferSizeWillChangeTo(size); 1131 1132 if (begin()) … … 1179 1180 1180 1181 template<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 { 1182 template<FailureAction action> 1183 bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::reserveCapacity(size_t newCapacity) 1184 { 1185 static_assert(action == FailureAction::Crash || action == FailureAction::Report); 1202 1186 if (newCapacity <= capacity()) 1203 1187 return true; … … 1207 1191 asanSetBufferSizeToFullCapacity(); 1208 1192 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 } 1212 1199 } 1213 1200 ASSERT(begin()); … … 1221 1208 1222 1209 template<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 { 1210 template<FailureAction action> 1211 inline bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::reserveInitialCapacity(size_t initialCapacity) 1212 { 1213 static_assert(action == FailureAction::Crash || action == FailureAction::Report); 1225 1214 ASSERT(!m_size); 1226 1215 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); 1229 1219 } 1230 1220 … … 1261 1251 1262 1252 template<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 { 1253 template<FailureAction action, typename U> 1254 ALWAYS_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); 1266 1257 size_t newSize = m_size + dataSize; 1267 1258 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 } 1269 1264 ASSERT(begin()); 1270 1265 } 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 1287 1270 return false; 1288 ASSERT(begin()); 1289 } 1290 if (newSize < m_size) 1291 return false; 1271 } 1292 1272 asanBufferSizeWillChangeTo(newSize); 1293 1273 T* dest = end(); … … 1298 1278 1299 1279 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc> 1300 template< typename U>1301 ALWAYS_INLINE voidVector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::append(U&& value)1280 template<FailureAction action, typename U> 1281 ALWAYS_INLINE bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::append(U&& value) 1302 1282 { 1303 1283 if (size() != capacity()) { … … 1305 1285 new (NotNull, end()) T(std::forward<U>(value)); 1306 1286 ++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 1293 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc> 1294 template<FailureAction action, typename... Args> 1295 ALWAYS_INLINE bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::constructAndAppend(Args&&... args) 1330 1296 { 1331 1297 if (size() != capacity()) { … … 1335 1301 return true; 1336 1302 } 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 1307 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc> 1308 template<FailureAction action, typename U> 1309 bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::appendSlowCase(U&& value) 1310 { 1311 static_assert(action == FailureAction::Crash || action == FailureAction::Report); 1345 1312 ASSERT(size() == capacity()); 1346 1313 1347 1314 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 } 1349 1320 ASSERT(begin()); 1350 1321 … … 1352 1323 new (NotNull, end()) T(std::forward<U>(*ptr)); 1353 1324 ++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 1328 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc> 1329 template<FailureAction action, typename... Args> 1330 bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::constructAndAppendSlowCase(Args&&... args) 1331 { 1332 static_assert(action == FailureAction::Crash || action == FailureAction::Report); 1360 1333 ASSERT(size() == capacity()); 1361 1334 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 } 1363 1340 ASSERT(begin()); 1364 1341 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 1380 1342 asanBufferSizeWillChangeTo(m_size + 1); 1381 1343 new (NotNull, end()) T(std::forward<Args>(args)...); … … 1424 1386 size_t newSize = m_size + val.size(); 1425 1387 if (newSize > capacity()) 1426 expandCapacity (newSize);1388 expandCapacity<FailureAction::Crash>(newSize); 1427 1389 for (auto& item : val) 1428 1390 uncheckedAppend(WTFMove(item)); … … 1436 1398 size_t newSize = m_size + dataSize; 1437 1399 if (newSize > capacity()) { 1438 data = expandCapacity (newSize, data);1400 data = expandCapacity<FailureAction::Crash>(newSize, data); 1439 1401 ASSERT(begin()); 1440 1402 } … … 1456 1418 auto ptr = const_cast<typename std::remove_const<typename std::remove_reference<U>::type>::type*>(std::addressof(value)); 1457 1419 if (size() == capacity()) { 1458 ptr = expandCapacity (size() + 1, ptr);1420 ptr = expandCapacity<FailureAction::Crash>(size() + 1, ptr); 1459 1421 ASSERT(begin()); 1460 1422 } -
trunk/Source/WebCore/ChangeLog
r263764 r263771 1 2020-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 1 49 2020-06-30 Peng Liu <peng.liu6@apple.com> 2 50 -
trunk/Source/WebCore/css/parser/CSSParser.cpp
r262155 r263771 2 2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org) 3 3 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) 4 * Copyright (C) 2004-20 16Apple Inc. All rights reserved.4 * Copyright (C) 2004-2020 Apple Inc. All rights reserved. 5 5 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com> 6 6 * Copyright (C) 2008 Eric Seidel <eric@webkit.org> … … 90 90 { 91 91 CSSParserImpl parser(m_context, condition); 92 if (!parser.tokenizer()) 93 return false; 92 94 return CSSSupportsParser::supportsCondition(parser.tokenizer()->tokenRange(), parser, CSSSupportsParser::ForWindowCSS) == CSSSupportsParser::Supported; 93 95 } -
trunk/Source/WebCore/css/parser/CSSParserImpl.cpp
r259006 r263771 1 1 // 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. 3 3 // 4 4 // Redistribution and use in source and binary forms, with or without … … 78 78 , m_observerWrapper(wrapper) 79 79 { 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; 81 83 if (context.deferredCSSParserEnabled && !wrapper && styleSheet && ruleParsing == CSSParser::RuleParsing::Deferred) 82 84 m_deferredParser = CSSDeferredParser::create(context, string, *styleSheet); -
trunk/Source/WebCore/css/parser/CSSParserImpl.h
r257696 r263771 1 1 // 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. 3 3 // 4 4 // Redistribution and use in source and binary forms, with or without -
trunk/Source/WebCore/css/parser/CSSTokenizer.cpp
r259773 r263771 1 1 // 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. 3 3 // 4 4 // Redistribution and use in source and binary forms, with or without … … 49 49 } 50 50 51 std::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 61 std::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 51 71 CSSTokenizer::CSSTokenizer(const String& string) 52 : CSSTokenizer(preprocessString(string), nullptr )72 : CSSTokenizer(preprocessString(string), nullptr, nullptr) 53 73 { 54 74 } 55 75 56 76 CSSTokenizer::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 81 CSSTokenizer::CSSTokenizer(String&& string, CSSParserObserverWrapper* wrapper, bool* constructionSuccessPtr) 62 82 : m_input(string) 63 83 { 84 if (constructionSuccessPtr) 85 *constructionSuccessPtr = true; 86 64 87 if (string.isEmpty()) 65 88 return; … … 67 90 // To avoid resizing we err on the side of reserving too much space. 68 91 // 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 } 70 98 71 99 unsigned offset = 0; … … 78 106 wrapper->addComment(offset, m_input.offset(), m_tokens.size()); 79 107 } 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 } 81 114 if (wrapper) 82 115 wrapper->addToken(offset); -
trunk/Source/WebCore/css/parser/CSSTokenizer.h
r259773 r263771 1 1 // 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. 3 3 // 4 4 // Redistribution and use in source and binary forms, with or without … … 46 46 WTF_MAKE_FAST_ALLOCATED; 47 47 public: 48 static std::unique_ptr<CSSTokenizer> tryCreate(const String&); 49 static std::unique_ptr<CSSTokenizer> tryCreate(const String&, CSSParserObserverWrapper&); // For the inspector 50 48 51 explicit CSSTokenizer(const String&); 49 52 CSSTokenizer(const String&, CSSParserObserverWrapper&); // For the inspector … … 55 58 56 59 private: 57 CSSTokenizer(String&&, CSSParserObserverWrapper* );60 CSSTokenizer(String&&, CSSParserObserverWrapper*, bool* constructionSuccess); 58 61 59 62 CSSParserToken nextToken();
Note:
See TracChangeset
for help on using the changeset viewer.