Correctly detect string overflow when using the 'Function' constructor.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 30 Oct 2018 02:58:51 +0000 (02:58 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 30 Oct 2018 02:58:51 +0000 (02:58 +0000)
commit1198ed2032cfe1a58762d5ea4f8511d37706aec1
tree2620ef3aa7a72db255a1604e6cf248005a3a9609
parent8b06709aef46d7412f3d9d055d3dcf7a1fde5198
Correctly detect string overflow when using the 'Function' constructor.
https://bugs.webkit.org/show_bug.cgi?id=184883
<rdar://problem/36320331>

Reviewed by Saam Barati.

JSTests:

I've verified that this passes on 32-bit as well.

* slowMicrobenchmarks/function-constructor-with-huge-strings.js: Added.

Source/bmalloc:

* bmalloc/Allocator.cpp:
(bmalloc::Allocator::reallocate):
(bmalloc::Allocator::tryReallocate):
(bmalloc::Allocator::reallocateImpl):
* bmalloc/Allocator.h:
* bmalloc/Cache.h:
(bmalloc::Cache::tryReallocate):
* bmalloc/DebugHeap.cpp:
(bmalloc::DebugHeap::realloc):
* bmalloc/DebugHeap.h:
* bmalloc/bmalloc.h:
(bmalloc::api::tryRealloc):

Source/JavaScriptCore:

Added StringBuilder::hasOverflowed() checks, and throwing OutOfMemoryErrors if
we detect an overflow.

* runtime/FunctionConstructor.cpp:
(JSC::constructFunctionSkippingEvalEnabledCheck):
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::encode):
(JSC::decode):
* runtime/JSONObject.cpp:
(JSC::Stringifier::stringify):
(JSC::Stringifier::appendStringifiedValue):

Source/WTF:

1. Enhanced StringBuilder so that it supports 2 modes of behavior:
   a. StringBuilder::OverflowHandler::CrashOnOverflow.
   b. StringBuilder::OverflowHandler::RecordOverflow.

   CrashOnOverflow will crash the moment an overflow or failure to allocate
   memory is detected.

   RecordOverflow will make StringBuilder::hasOverflowed() return true when an
   overflow or failure to allocate memory is detected.  However, if the user
   invokes toString(), toStringPreserveCapacity(), toAtomicString(), length(),
   capacity(), isEmpty(), characters8(), or characters16(), then the StringBuilder
   will crash regardless because these methods can only meaningfully do their
   work and return a result if and only if the builder has not overflowed.

   By default, the StringBuilder crashes on overflow (the old behavior) unless it
   is explicitly constructed with the StringBuilder::OverflowHandler::RecordOverflow
   enum.

   Design note:

   The StringBuilder can only be put in 1 of the 2 modes at the time of
   construction.  This means that we could have implemented it as a template
   that is parameterized on an OverflowHandler class (like CheckedArithmetic)
   instead of using a runtime check in the ConditionalCrashOnOverflow handler.

   However, I was not able to get clang to export the explicitly instantiated
   instances (despite the methods having being decorated with WTF_EXPORT_PRIVATE).
   Since the StringBuilder is a transient object (not stored for a long time on
   the heap), and the runtime check of the boolean is not that costly compared
   to other work that StringBuilder routinely does (e.g. memcpy), using the
   new ConditionalCrashOnOverflow (which does a runtime check to determine to
   crash or not on overflow) is fine.

   When clang is able to export explicitly instantiated template methods, we can
   templatize StringBuilder and do away with ConditionalCrashOnOverflow.
   See https://bugs.webkit.org/show_bug.cgi?id=191050.

To support the above, we also did:

2. Enhanced all StringBuilder append and buffer allocation methods to be able to
   fail without crashing.  This also meant that ...

3. Added tryReallocate() support to StringImpl.  tryRealloc() was added to
   FastMalloc, and bmalloc (and related peers) to enable this.

4. Added ConditionalCrashOnOverflow, which can choose at runtime whether to behave
   like CrashOnOverflow or RecordOverflow.

* wtf/CheckedArithmetic.h:
(WTF::ConditionalCrashOnOverflow::overflowed):
(WTF::ConditionalCrashOnOverflow::shouldCrashOnOverflow const):
(WTF::ConditionalCrashOnOverflow::setShouldCrashOnOverflow):
(WTF::ConditionalCrashOnOverflow::hasOverflowed const):
(WTF::ConditionalCrashOnOverflow::clearOverflow):
(WTF::ConditionalCrashOnOverflow::crash):
(WTF::RecordOverflow::overflowed):
(WTF::Checked::unsafeGet const):
* wtf/FastMalloc.cpp:
(WTF::tryFastRealloc):
* wtf/FastMalloc.h:
* wtf/text/StringBuilder.cpp:
(WTF::expandedCapacity):
(WTF::StringBuilder::reifyString const):
(WTF::StringBuilder::resize):
(WTF::StringBuilder::allocateBuffer):
(WTF::StringBuilder::allocateBufferUpConvert):
(WTF::StringBuilder::reallocateBuffer<LChar>):
(WTF::StringBuilder::reallocateBuffer<UChar>):
(WTF::StringBuilder::reserveCapacity):
(WTF::StringBuilder::appendUninitialized):
(WTF::StringBuilder::appendUninitializedSlow):
(WTF::StringBuilder::append):
(WTF::StringBuilder::canShrink const):
(WTF::StringBuilder::shrinkToFit):
* wtf/text/StringBuilder.h:
(WTF::StringBuilder::StringBuilder):
(WTF::StringBuilder::didOverflow):
(WTF::StringBuilder::hasOverflowed const):
(WTF::StringBuilder::crashesOnOverflow const):
(WTF::StringBuilder::append):
(WTF::StringBuilder::toString):
(WTF::StringBuilder::toStringPreserveCapacity const):
(WTF::StringBuilder::toAtomicString const):
(WTF::StringBuilder::length const):
(WTF::StringBuilder::capacity const):
(WTF::StringBuilder::operator[] const):
(WTF::StringBuilder::swap):
(WTF::StringBuilder::getBufferCharacters<UChar>):
* wtf/text/StringBuilderJSON.cpp:
(WTF::StringBuilder::appendQuotedJSONString):
* wtf/text/StringImpl.cpp:
(WTF::StringImpl::reallocateInternal):
(WTF::StringImpl::reallocate):
(WTF::StringImpl::tryReallocate):
* wtf/text/StringImpl.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237577 268f45cc-cd09-0410-ab3c-d52691b4dbfc
22 files changed:
JSTests/ChangeLog
JSTests/slowMicrobenchmarks/function-constructor-with-huge-strings.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/FunctionConstructor.cpp
Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
Source/JavaScriptCore/runtime/JSONObject.cpp
Source/WTF/ChangeLog
Source/WTF/wtf/CheckedArithmetic.h
Source/WTF/wtf/FastMalloc.cpp
Source/WTF/wtf/FastMalloc.h
Source/WTF/wtf/text/StringBuilder.cpp
Source/WTF/wtf/text/StringBuilder.h
Source/WTF/wtf/text/StringBuilderJSON.cpp
Source/WTF/wtf/text/StringImpl.cpp
Source/WTF/wtf/text/StringImpl.h
Source/bmalloc/ChangeLog
Source/bmalloc/bmalloc/Allocator.cpp
Source/bmalloc/bmalloc/Allocator.h
Source/bmalloc/bmalloc/Cache.h
Source/bmalloc/bmalloc/DebugHeap.cpp
Source/bmalloc/bmalloc/DebugHeap.h
Source/bmalloc/bmalloc/bmalloc.h