Changeset 207861 in webkit
- Timestamp:
- Oct 25, 2016 6:15:49 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r207849 r207861 1 2016-10-25 Mark Lam <mark.lam@apple.com> 2 3 String.prototype.replace() should throw an OutOfMemoryError when using too much memory. 4 https://bugs.webkit.org/show_bug.cgi?id=163996 5 <rdar://problem/28263117> 6 7 Reviewed by Geoffrey Garen. 8 9 * stress/string-prototype-replace-should-throw-out-of-memory-error-when-using-too-much-memory.js: Added. 10 1 11 2016-10-25 Mark Lam <mark.lam@apple.com> 2 12 -
trunk/Source/JavaScriptCore/ChangeLog
r207859 r207861 1 2016-10-25 Mark Lam <mark.lam@apple.com> 2 3 String.prototype.replace() should throw an OutOfMemoryError when using too much memory. 4 https://bugs.webkit.org/show_bug.cgi?id=163996 5 <rdar://problem/28263117> 6 7 Reviewed by Geoffrey Garen. 8 9 String.prototype.replace() uses a Vector internally for bookkeeping work. 10 Currently, if this vector gets too big, we just crash on allocation failure. 11 While this is correct behavior, it is not too friendly. 12 13 We now detect the imminent failure, and throw a OutOfMemoryError instead. 14 15 * runtime/StringPrototype.cpp: 16 (JSC::removeUsingRegExpSearch): 17 (JSC::replaceUsingRegExpSearch): 18 (JSC::operationStringProtoFuncReplaceRegExpEmptyStr): 19 (JSC::stringProtoFuncReplaceUsingRegExp): 20 1 21 2016-10-25 Mark Lam <mark.lam@apple.com> 2 22 -
trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp
r207851 r207861 434 434 } 435 435 436 #define OUT_OF_MEMORY(exec__, scope__) \ 437 do { \ 438 throwOutOfMemoryError(exec__, scope__); \ 439 return encodedJSValue(); \ 440 } while (false) 441 436 442 static ALWAYS_INLINE EncodedJSValue removeUsingRegExpSearch(VM& vm, ExecState* exec, JSString* string, const String& source, RegExp* regExp) 437 443 { 444 auto scope = DECLARE_THROW_SCOPE(vm); 438 445 SuperSamplerScope superSamplerScope(false); 439 446 … … 450 457 break; 451 458 452 if (lastIndex < result.start) 453 sourceRanges.constructAndAppend(lastIndex, result.start - lastIndex); 454 459 if (lastIndex < result.start) { 460 if (UNLIKELY(!sourceRanges.tryConstructAndAppend(lastIndex, result.start - lastIndex))) 461 OUT_OF_MEMORY(exec, scope); 462 } 455 463 lastIndex = result.end; 456 464 startPosition = lastIndex; … … 467 475 return JSValue::encode(string); 468 476 469 if (static_cast<unsigned>(lastIndex) < sourceLen) 470 sourceRanges.constructAndAppend(lastIndex, sourceLen - lastIndex); 471 477 if (static_cast<unsigned>(lastIndex) < sourceLen) { 478 if (UNLIKELY(!sourceRanges.tryConstructAndAppend(lastIndex, sourceLen - lastIndex))) 479 OUT_OF_MEMORY(exec, scope); 480 } 481 scope.release(); 472 482 return JSValue::encode(jsSpliceSubstrings(exec, string, source, sourceRanges.data(), sourceRanges.size())); 473 483 } … … 491 501 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 492 502 493 if (callType == CallType::None && !replacementString.length()) 503 if (callType == CallType::None && !replacementString.length()) { 504 scope.release(); 494 505 return removeUsingRegExpSearch(vm, exec, string, source, regExp); 506 } 495 507 } 496 508 … … 519 531 break; 520 532 521 sourceRanges.constructAndAppend(lastIndex, result.start - lastIndex); 533 if (UNLIKELY(!sourceRanges.tryConstructAndAppend(lastIndex, result.start - lastIndex))) 534 OUT_OF_MEMORY(exec, scope); 522 535 523 536 unsigned i = 0; … … 557 570 break; 558 571 559 sourceRanges.constructAndAppend(lastIndex, result.start - lastIndex); 572 if (UNLIKELY(!sourceRanges.tryConstructAndAppend(lastIndex, result.start - lastIndex))) 573 OUT_OF_MEMORY(exec, scope); 560 574 561 575 unsigned i = 0; … … 597 611 598 612 if (callType != CallType::None) { 599 sourceRanges.constructAndAppend(lastIndex, result.start - lastIndex); 613 if (UNLIKELY(!sourceRanges.tryConstructAndAppend(lastIndex, result.start - lastIndex))) 614 OUT_OF_MEMORY(exec, scope); 600 615 601 616 MarkedArgumentBuffer args; … … 621 636 int replLen = replacementString.length(); 622 637 if (lastIndex < result.start || replLen) { 623 sourceRanges.constructAndAppend(lastIndex, result.start - lastIndex); 638 if (UNLIKELY(!sourceRanges.tryConstructAndAppend(lastIndex, result.start - lastIndex))) 639 OUT_OF_MEMORY(exec, scope); 624 640 625 641 if (replLen) … … 645 661 return JSValue::encode(string); 646 662 647 if (static_cast<unsigned>(lastIndex) < sourceLen) 648 sourceRanges.constructAndAppend(lastIndex, sourceLen - lastIndex); 649 663 if (static_cast<unsigned>(lastIndex) < sourceLen) { 664 if (UNLIKELY(!sourceRanges.tryConstructAndAppend(lastIndex, sourceLen - lastIndex))) 665 OUT_OF_MEMORY(exec, scope); 666 } 650 667 return JSValue::encode(jsSpliceSubstringsWithSeparators(exec, string, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size())); 651 668 } … … 663 680 searchValue->setLastIndex(exec, 0); 664 681 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 682 scope.release(); 665 683 return removeUsingRegExpSearch(vm, exec, thisValue, thisValue->value(exec), regExp); 666 684 } … … 668 686 CallData callData; 669 687 String replacementString = emptyString(); 688 scope.release(); 670 689 return replaceUsingRegExpSearch( 671 690 vm, exec, thisValue, searchValue, callData, CallType::None, replacementString, JSValue()); … … 696 715 } 697 716 717 scope.release(); 698 718 return replaceUsingRegExpSearch( 699 719 vm, exec, string, searchValue, callData, callType, replacementString, replaceValue); … … 833 853 return JSValue::encode(jsUndefined()); 834 854 855 scope.release(); 835 856 return replaceUsingRegExpSearch(exec->vm(), exec, string, searchValue, exec->argument(1)); 836 857 } -
trunk/Source/WTF/ChangeLog
r207819 r207861 1 2016-10-25 Mark Lam <mark.lam@apple.com> 2 3 String.prototype.replace() should throw an OutOfMemoryError when using too much memory. 4 https://bugs.webkit.org/show_bug.cgi?id=163996 5 <rdar://problem/28263117> 6 7 Reviewed by Geoffrey Garen. 8 9 * wtf/Vector.h: 10 (WTF::minCapacity>::tryConstructAndAppend): 11 (WTF::minCapacity>::tryConstructAndAppendSlowCase): 12 - Added try versions of constructAndAppend() so that we can handle the failure 13 to allocate more gracefully. 14 1 15 2016-10-25 Konstantin Tokarev <annulen@yandex.ru> 2 16 -
trunk/Source/WTF/wtf/Vector.h
r201314 r207861 723 723 template<typename U> void append(U&&); 724 724 template<typename... Args> void constructAndAppend(Args&&...); 725 template<typename... Args> bool tryConstructAndAppend(Args&&...); 725 726 726 727 void uncheckedAppend(ValueType&& value) { uncheckedAppend<ValueType>(std::forward<ValueType>(value)); } … … 786 787 template<typename U> void appendSlowCase(U&&); 787 788 template<typename... Args> void constructAndAppendSlowCase(Args&&...); 789 template<typename... Args> bool tryConstructAndAppendSlowCase(Args&&...); 788 790 789 791 void asanSetInitialBufferSizeTo(size_t); … … 1226 1228 } 1227 1229 1230 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename... Args> 1231 ALWAYS_INLINE bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryConstructAndAppend(Args&&... args) 1232 { 1233 if (size() != capacity()) { 1234 asanBufferSizeWillChangeTo(m_size + 1); 1235 new (NotNull, end()) T(std::forward<Args>(args)...); 1236 ++m_size; 1237 return true; 1238 } 1239 1240 return tryConstructAndAppendSlowCase(std::forward<Args>(args)...); 1241 } 1242 1228 1243 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename U> 1229 1244 void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::appendSlowCase(U&& value) … … 1251 1266 new (NotNull, end()) T(std::forward<Args>(args)...); 1252 1267 ++m_size; 1268 } 1269 1270 template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename... Args> 1271 bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryConstructAndAppendSlowCase(Args&&... args) 1272 { 1273 ASSERT(size() == capacity()); 1274 1275 if (UNLIKELY(!tryExpandCapacity(size() + 1))) 1276 return false; 1277 ASSERT(begin()); 1278 1279 asanBufferSizeWillChangeTo(m_size + 1); 1280 new (NotNull, end()) T(std::forward<Args>(args)...); 1281 ++m_size; 1282 return true; 1253 1283 } 1254 1284
Note: See TracChangeset
for help on using the changeset viewer.