<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[237577] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/237577">237577</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2018-10-29 19:58:51 -0700 (Mon, 29 Oct 2018)</dd>
</dl>

<h3>Log Message</h3>
<pre>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:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeFunctionConstructorcpp">trunk/Source/JavaScriptCore/runtime/FunctionConstructor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSGlobalObjectFunctionscpp">trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSONObjectcpp">trunk/Source/JavaScriptCore/runtime/JSONObject.cpp</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfCheckedArithmetich">trunk/Source/WTF/wtf/CheckedArithmetic.h</a></li>
<li><a href="#trunkSourceWTFwtfFastMalloccpp">trunk/Source/WTF/wtf/FastMalloc.cpp</a></li>
<li><a href="#trunkSourceWTFwtfFastMalloch">trunk/Source/WTF/wtf/FastMalloc.h</a></li>
<li><a href="#trunkSourceWTFwtftextStringBuildercpp">trunk/Source/WTF/wtf/text/StringBuilder.cpp</a></li>
<li><a href="#trunkSourceWTFwtftextStringBuilderh">trunk/Source/WTF/wtf/text/StringBuilder.h</a></li>
<li><a href="#trunkSourceWTFwtftextStringBuilderJSONcpp">trunk/Source/WTF/wtf/text/StringBuilderJSON.cpp</a></li>
<li><a href="#trunkSourceWTFwtftextStringImplcpp">trunk/Source/WTF/wtf/text/StringImpl.cpp</a></li>
<li><a href="#trunkSourceWTFwtftextStringImplh">trunk/Source/WTF/wtf/text/StringImpl.h</a></li>
<li><a href="#trunkSourcebmallocChangeLog">trunk/Source/bmalloc/ChangeLog</a></li>
<li><a href="#trunkSourcebmallocbmallocAllocatorcpp">trunk/Source/bmalloc/bmalloc/Allocator.cpp</a></li>
<li><a href="#trunkSourcebmallocbmallocAllocatorh">trunk/Source/bmalloc/bmalloc/Allocator.h</a></li>
<li><a href="#trunkSourcebmallocbmallocCacheh">trunk/Source/bmalloc/bmalloc/Cache.h</a></li>
<li><a href="#trunkSourcebmallocbmallocDebugHeapcpp">trunk/Source/bmalloc/bmalloc/DebugHeap.cpp</a></li>
<li><a href="#trunkSourcebmallocbmallocDebugHeaph">trunk/Source/bmalloc/bmalloc/DebugHeap.h</a></li>
<li><a href="#trunkSourcebmallocbmallocbmalloch">trunk/Source/bmalloc/bmalloc/bmalloc.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsslowMicrobenchmarksfunctionconstructorwithhugestringsjs">trunk/JSTests/slowMicrobenchmarks/function-constructor-with-huge-strings.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog  2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/JSTests/ChangeLog     2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2018-10-29  Mark Lam  <mark.lam@apple.com>
+
+        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.
+
+        I've verified that this passes on 32-bit as well.
+
+        * slowMicrobenchmarks/function-constructor-with-huge-strings.js: Added.
+
</ins><span class="cx"> 2018-10-29  Tadeu Zagallo  <tzagallo@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Add support for GetStack FlushedDouble
</span></span></pre></div>
<a id="trunkJSTestsslowMicrobenchmarksfunctionconstructorwithhugestringsjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/slowMicrobenchmarks/function-constructor-with-huge-strings.js (0 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/slowMicrobenchmarks/function-constructor-with-huge-strings.js                              (rev 0)
+++ trunk/JSTests/slowMicrobenchmarks/function-constructor-with-huge-strings.js 2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+var hugeString = "x";
+for (i = 0; i < 25; ++i) {
+    hugeString += hugeString;
+}
+
+var exception;
+var weird = '';
+try {
+    var f = new Function(hugeString, hugeString, hugeString, hugeString, hugeString, hugeString, hugeString,
+      hugeString, hugeString, hugeString, hugeString, hugeString, hugeString, hugeString,
+      hugeString, hugeString, hugeString, hugeString, hugeString, hugeString, hugeString,
+      () => 42,
+      "return 42;");
+} catch (e) {
+    exception = e;
+}
+
+if (exception != "Error: Out of memory")
+    throw "FAIL";
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/JavaScriptCore/ChangeLog       2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2018-10-29  Mark Lam  <mark.lam@apple.com>
+
+        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.
+
+        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):
+
</ins><span class="cx"> 2018-10-29  Tadeu Zagallo  <tzagallo@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, fix JSC on arm64e after r237547
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeFunctionConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/FunctionConstructor.cpp (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/FunctionConstructor.cpp      2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/JavaScriptCore/runtime/FunctionConstructor.cpp 2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -123,21 +123,25 @@
</span><span class="cx">         RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">         program = makeString("{", prefix, functionName.string(), "() {\n", body, "\n}}");
</span><span class="cx">     } else {
</span><del>-        StringBuilder builder;
</del><ins>+        StringBuilder builder(StringBuilder::OverflowHandler::RecordOverflow);
</ins><span class="cx">         builder.append('{');
</span><span class="cx">         builder.append(prefix);
</span><span class="cx">         builder.append(functionName.string());
</span><span class="cx">         builder.append('(');
</span><del>-        StringBuilder parameterBuilder;
</del><ins>+        StringBuilder parameterBuilder(StringBuilder::OverflowHandler::RecordOverflow);
</ins><span class="cx">         auto viewWithString = args.at(0).toString(exec)->viewWithUnderlyingString(exec);
</span><span class="cx">         RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">         parameterBuilder.append(viewWithString.view);
</span><del>-        for (size_t i = 1; i < args.size() - 1; i++) {
</del><ins>+        for (size_t i = 1; !parameterBuilder.hasOverflowed() && i < args.size() - 1; i++) {
</ins><span class="cx">             parameterBuilder.appendLiteral(", ");
</span><span class="cx">             auto viewWithString = args.at(i).toString(exec)->viewWithUnderlyingString(exec);
</span><span class="cx">             RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">             parameterBuilder.append(viewWithString.view);
</span><span class="cx">         }
</span><ins>+        if (parameterBuilder.hasOverflowed()) {
+            throwOutOfMemoryError(exec, scope);
+            return nullptr;
+        }
</ins><span class="cx">         auto body = args.at(args.size() - 1).toWTFString(exec);
</span><span class="cx">         RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx"> 
</span><span class="lines">@@ -164,6 +168,10 @@
</span><span class="cx">         RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">         builder.append(body);
</span><span class="cx">         builder.appendLiteral("\n}}");
</span><ins>+        if (builder.hasOverflowed()) {
+            throwOutOfMemoryError(exec, scope);
+            return nullptr;
+        }
</ins><span class="cx">         program = builder.toString();
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSGlobalObjectFunctionscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp  2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp     2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> /*
</span><span class="cx">  *  Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
</span><span class="cx">  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
</span><del>- *  Copyright (C) 2003-2017 Apple Inc. All rights reserved.
</del><ins>+ *  Copyright (C) 2003-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
</span><span class="cx">  *  Copyright (C) 2007 Maks Orlovich
</span><span class="cx">  *
</span><span class="lines">@@ -87,7 +87,7 @@
</span><span class="cx">         return JSC::throwException(exec, scope, createURIError(exec, "String contained an illegal UTF-16 sequence."_s));
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    StringBuilder builder;
</del><ins>+    StringBuilder builder(StringBuilder::OverflowHandler::RecordOverflow);
</ins><span class="cx">     builder.reserveCapacity(length);
</span><span class="cx"> 
</span><span class="cx">     // 4. Repeat
</span><span class="lines">@@ -151,6 +151,8 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (UNLIKELY(builder.hasOverflowed()))
+        return throwOutOfMemoryError(exec, scope);
</ins><span class="cx">     return jsString(exec, builder.toString());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -170,7 +172,7 @@
</span><span class="cx">     VM& vm = exec->vm();
</span><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><span class="cx"> 
</span><del>-    StringBuilder builder;
</del><ins>+    StringBuilder builder(StringBuilder::OverflowHandler::RecordOverflow);
</ins><span class="cx">     int k = 0;
</span><span class="cx">     UChar u = 0;
</span><span class="cx">     while (k < length) {
</span><span class="lines">@@ -229,6 +231,8 @@
</span><span class="cx">         k++;
</span><span class="cx">         builder.append(c);
</span><span class="cx">     }
</span><ins>+    if (UNLIKELY(builder.hasOverflowed()))
+        return throwOutOfMemoryError(exec, scope);
</ins><span class="cx">     RELEASE_AND_RETURN(scope, jsString(&vm, builder.toString()));
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSONObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSONObject.cpp (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSONObject.cpp       2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/JavaScriptCore/runtime/JSONObject.cpp  2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2009-2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2009-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -273,7 +273,7 @@
</span><span class="cx">         object->putDirect(vm, vm.propertyNames->emptyIdentifier, value);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    StringBuilder result;
</del><ins>+    StringBuilder result(StringBuilder::OverflowHandler::RecordOverflow);
</ins><span class="cx">     Holder root(Holder::RootHolder, object);
</span><span class="cx">     auto stringifyResult = appendStringifiedValue(result, value, root, emptyPropertyName);
</span><span class="cx">     EXCEPTION_ASSERT(!scope.exception() || (stringifyResult != StringifySucceeded));
</span><span class="lines">@@ -358,10 +358,12 @@
</span><span class="cx">     if (value.isString()) {
</span><span class="cx">         const String& string = asString(value)->value(m_exec);
</span><span class="cx">         RETURN_IF_EXCEPTION(scope, StringifyFailed);
</span><del>-        if (builder.appendQuotedJSONString(string))
-            return StringifySucceeded;
-        throwOutOfMemoryError(m_exec, scope);
-        return StringifyFailed;
</del><ins>+        builder.appendQuotedJSONString(string);
+        if (UNLIKELY(builder.hasOverflowed())) {
+            throwOutOfMemoryError(m_exec, scope);
+            return StringifyFailed;
+        }
+        return StringifySucceeded;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (value.isNumber()) {
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog       2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/WTF/ChangeLog  2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,3 +1,107 @@
</span><ins>+2018-10-29  Mark Lam  <mark.lam@apple.com>
+
+        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.
+
+        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:
+
</ins><span class="cx"> 2018-10-29  Tim Horton  <timothy_horton@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Modernize WebKit nibs and lprojs for localization's sake
</span></span></pre></div>
<a id="trunkSourceWTFwtfCheckedArithmetich"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/CheckedArithmetic.h (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/CheckedArithmetic.h 2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/WTF/wtf/CheckedArithmetic.h    2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -70,6 +70,31 @@
</span><span class="cx">     DidNotOverflow
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+class ConditionalCrashOnOverflow {
+public:
+    void overflowed()
+    {
+        m_overflowed = true;
+        if (m_shouldCrashOnOverflow)
+            crash();
+    }
+
+    bool shouldCrashOnOverflow() const { return m_shouldCrashOnOverflow; }
+    void setShouldCrashOnOverflow(bool value) { m_shouldCrashOnOverflow = value; }
+
+    bool hasOverflowed() const { return m_overflowed; }
+    void clearOverflow() { m_overflowed = false; }
+
+    static NO_RETURN_DUE_TO_CRASH void crash()
+    {
+        CRASH();
+    }
+
+private:
+    bool m_overflowed { false };
+    bool m_shouldCrashOnOverflow { true };
+};
+
</ins><span class="cx"> class CrashOnOverflow {
</span><span class="cx"> public:
</span><span class="cx">     static NO_RETURN_DUE_TO_CRASH void overflowed()
</span><span class="lines">@@ -95,11 +120,6 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void overflowed()
-    {
-        m_overflowed = true;
-    }
-
</del><span class="cx">     void clearOverflow()
</span><span class="cx">     {
</span><span class="cx">         m_overflowed = false;
</span><span class="lines">@@ -112,6 +132,7 @@
</span><span class="cx"> 
</span><span class="cx"> public:
</span><span class="cx">     bool hasOverflowed() const { return m_overflowed; }
</span><ins>+    void overflowed() { m_overflowed = true; }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     unsigned char m_overflowed;
</span><span class="lines">@@ -206,6 +227,11 @@
</span><span class="cx">     static const CleanType DefaultValue = 0;    
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+template <typename T> struct RemoveChecked<Checked<T, ConditionalCrashOnOverflow>> {
+    using CleanType = typename RemoveChecked<T>::CleanType;
+    static const CleanType DefaultValue = 0;
+};
+
</ins><span class="cx"> template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow>> {
</span><span class="cx">     typedef typename RemoveChecked<T>::CleanType CleanType;
</span><span class="cx">     static const CleanType DefaultValue = 0;
</span><span class="lines">@@ -631,11 +657,12 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Value accessors. unsafeGet() will crash if there's been an overflow.
</span><del>-    T unsafeGet() const
</del><ins>+    template<typename U = T>
+    U unsafeGet() const
</ins><span class="cx">     {
</span><span class="cx">         if (this->hasOverflowed())
</span><span class="cx">             this->crash();
</span><del>-        return m_value;
</del><ins>+        return static_cast<U>(m_value);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     inline CheckedState safeGet(T& value) const WARN_UNUSED_RETURN
</span><span class="lines">@@ -914,6 +941,7 @@
</span><span class="cx"> using WTF::CheckedInt64;
</span><span class="cx"> using WTF::CheckedUint64;
</span><span class="cx"> using WTF::CheckedSize;
</span><ins>+using WTF::ConditionalCrashOnOverflow;
</ins><span class="cx"> using WTF::CrashOnOverflow;
</span><span class="cx"> using WTF::RecordOverflow;
</span><span class="cx"> using WTF::checkedSum;
</span></span></pre></div>
<a id="trunkSourceWTFwtfFastMalloccpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/FastMalloc.cpp (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/FastMalloc.cpp      2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/WTF/wtf/FastMalloc.cpp 2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (c) 2005, 2007, Google Inc. All rights reserved.
</span><del>- * Copyright (C) 2005-2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2005-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="cx">  * are met:
</span><span class="lines">@@ -221,6 +221,12 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+TryMallocReturnValue tryFastRealloc(void* p, size_t n)
+{
+    FAIL_IF_EXCEEDS_LIMIT(n);
+    return realloc(p, n);
+}
+
</ins><span class="cx"> void releaseFastMallocFreeMemory() { }
</span><span class="cx"> void releaseFastMallocFreeMemoryForThisThread() { }
</span><span class="cx">     
</span><span class="lines">@@ -341,6 +347,12 @@
</span><span class="cx">     return tryFastZeroedMalloc(checkedSize.unsafeGet());
</span><span class="cx"> }
</span><span class="cx">     
</span><ins>+TryMallocReturnValue tryFastRealloc(void* object, size_t newSize)
+{
+    FAIL_IF_EXCEEDS_LIMIT(newSize);
+    return bmalloc::api::tryRealloc(object, newSize);
+}
+
</ins><span class="cx"> void releaseFastMallocFreeMemoryForThisThread()
</span><span class="cx"> {
</span><span class="cx">     bmalloc::api::scavengeThisThread();
</span></span></pre></div>
<a id="trunkSourceWTFwtfFastMalloch"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/FastMalloc.h (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/FastMalloc.h        2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/WTF/wtf/FastMalloc.h   2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- *  Copyright (C) 2005-2009, 2015-2016 Apple Inc. All rights reserved.
</del><ins>+ *  Copyright (C) 2005-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  *  This library is free software; you can redistribute it and/or
</span><span class="cx">  *  modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -53,6 +53,7 @@
</span><span class="cx"> WTF_EXPORT_PRIVATE TryMallocReturnValue tryFastMalloc(size_t);
</span><span class="cx"> WTF_EXPORT_PRIVATE TryMallocReturnValue tryFastZeroedMalloc(size_t);
</span><span class="cx"> WTF_EXPORT_PRIVATE TryMallocReturnValue tryFastCalloc(size_t numElements, size_t elementSize);
</span><ins>+WTF_EXPORT_PRIVATE TryMallocReturnValue tryFastRealloc(void*, size_t);
</ins><span class="cx"> 
</span><span class="cx"> WTF_EXPORT_PRIVATE void fastFree(void*);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFwtftextStringBuildercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/StringBuilder.cpp (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/StringBuilder.cpp      2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/WTF/wtf/text/StringBuilder.cpp 2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2010, 2013, 2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2010-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2012 Google Inc. All rights reserved.
</span><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -34,17 +34,20 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><ins>+static constexpr unsigned maxCapacity = String::MaxLength + 1;
+
</ins><span class="cx"> static unsigned expandedCapacity(unsigned capacity, unsigned requiredLength)
</span><span class="cx"> {
</span><span class="cx">     static const unsigned minimumCapacity = 16;
</span><del>-    return std::max(requiredLength, std::max(minimumCapacity, capacity * 2));
</del><ins>+    return std::max(requiredLength, std::max(minimumCapacity, std::min(capacity * 2, maxCapacity)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void StringBuilder::reifyString() const
</span><span class="cx"> {
</span><ins>+    ASSERT(!hasOverflowed());
</ins><span class="cx">     // Check if the string already exists.
</span><span class="cx">     if (!m_string.isNull()) {
</span><del>-        ASSERT(m_string.length() == m_length);
</del><ins>+        ASSERT(m_string.length() == m_length.unsafeGet<unsigned>());
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -55,21 +58,28 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Must be valid in the buffer, take a substring (unless string fills the buffer).
</span><del>-    ASSERT(m_buffer && m_length <= m_buffer->length());
-    if (m_length == m_buffer->length())
</del><ins>+    ASSERT(m_buffer && m_length.unsafeGet<unsigned>() <= m_buffer->length());
+    if (m_length.unsafeGet<unsigned>() == m_buffer->length())
</ins><span class="cx">         m_string = m_buffer.get();
</span><span class="cx">     else
</span><del>-        m_string = StringImpl::createSubstringSharingImpl(*m_buffer, 0, m_length);
</del><ins>+        m_string = StringImpl::createSubstringSharingImpl(*m_buffer, 0, m_length.unsafeGet());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void StringBuilder::resize(unsigned newSize)
</span><span class="cx"> {
</span><ins>+    if (hasOverflowed())
+        return;
+
</ins><span class="cx">     // Check newSize < m_length, hence m_length > 0.
</span><del>-    ASSERT(newSize <= m_length);
-    if (newSize == m_length)
</del><ins>+    unsigned oldLength = m_length.unsafeGet();
+    ASSERT(newSize <= oldLength);
+    if (newSize == oldLength)
</ins><span class="cx">         return;
</span><del>-    ASSERT(m_length);
</del><ins>+    ASSERT(oldLength);
</ins><span class="cx"> 
</span><ins>+    m_length = newSize;
+    ASSERT(!hasOverflowed());
+
</ins><span class="cx">     // If there is a buffer, we only need to duplicate it if it has more than one ref.
</span><span class="cx">     if (m_buffer) {
</span><span class="cx">         m_string = String(); // Clear the string to remove the reference to m_buffer if any before checking the reference count of m_buffer.
</span><span class="lines">@@ -79,16 +89,14 @@
</span><span class="cx">             else
</span><span class="cx">                 allocateBuffer(m_buffer->characters16(), m_buffer->length());
</span><span class="cx">         }
</span><del>-        m_length = newSize;
-        ASSERT(m_buffer->length() >= m_length);
</del><ins>+        ASSERT(hasOverflowed() || m_buffer->length() >= m_length.unsafeGet<unsigned>());
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Since m_length && !m_buffer, the string must be valid in m_string, and m_string.length() > 0.
</span><span class="cx">     ASSERT(!m_string.isEmpty());
</span><del>-    ASSERT(m_length == m_string.length());
</del><ins>+    ASSERT(oldLength == m_string.length());
</ins><span class="cx">     ASSERT(newSize < m_string.length());
</span><del>-    m_length = newSize;
</del><span class="cx">     m_string = StringImpl::createSubstringSharingImpl(*m_string.impl(), 0, newSize);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -96,10 +104,13 @@
</span><span class="cx"> // or m_buffer, neither will be reassigned until the copy has completed).
</span><span class="cx"> void StringBuilder::allocateBuffer(const LChar* currentCharacters, unsigned requiredLength)
</span><span class="cx"> {
</span><ins>+    ASSERT(!hasOverflowed());
</ins><span class="cx">     ASSERT(m_is8Bit);
</span><span class="cx">     // Copy the existing data into a new buffer, set result to point to the end of the existing data.
</span><del>-    auto buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters8);
-    memcpy(m_bufferCharacters8, currentCharacters, static_cast<size_t>(m_length) * sizeof(LChar)); // This can't overflow.
</del><ins>+    auto buffer = StringImpl::tryCreateUninitialized(requiredLength, m_bufferCharacters8);
+    if (UNLIKELY(!buffer))
+        return didOverflow();
+    memcpy(m_bufferCharacters8, currentCharacters, static_cast<size_t>(m_length.unsafeGet()) * sizeof(LChar)); // This can't overflow.
</ins><span class="cx">     
</span><span class="cx">     // Update the builder state.
</span><span class="cx">     m_buffer = WTFMove(buffer);
</span><span class="lines">@@ -111,10 +122,13 @@
</span><span class="cx"> // or m_buffer,  neither will be reassigned until the copy has completed).
</span><span class="cx"> void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requiredLength)
</span><span class="cx"> {
</span><ins>+    ASSERT(!hasOverflowed());
</ins><span class="cx">     ASSERT(!m_is8Bit);
</span><span class="cx">     // Copy the existing data into a new buffer, set result to point to the end of the existing data.
</span><del>-    auto buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters16);
-    memcpy(m_bufferCharacters16, currentCharacters, static_cast<size_t>(m_length) * sizeof(UChar)); // This can't overflow.
</del><ins>+    auto buffer = StringImpl::tryCreateUninitialized(requiredLength, m_bufferCharacters16);
+    if (UNLIKELY(!buffer))
+        return didOverflow();
+    memcpy(m_bufferCharacters16, currentCharacters, static_cast<size_t>(m_length.unsafeGet()) * sizeof(UChar)); // This can't overflow.
</ins><span class="cx">     
</span><span class="cx">     // Update the builder state.
</span><span class="cx">     m_buffer = WTFMove(buffer);
</span><span class="lines">@@ -126,11 +140,15 @@
</span><span class="cx"> // from either m_string or m_buffer, neither will be reassigned until the copy has completed).
</span><span class="cx"> void StringBuilder::allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength)
</span><span class="cx"> {
</span><ins>+    ASSERT(!hasOverflowed());
</ins><span class="cx">     ASSERT(m_is8Bit);
</span><del>-    ASSERT(requiredLength >= m_length);
</del><ins>+    unsigned length = m_length.unsafeGet();
+    ASSERT(requiredLength <= maxCapacity && requiredLength >= length);
</ins><span class="cx">     // Copy the existing data into a new buffer, set result to point to the end of the existing data.
</span><del>-    auto buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters16);
-    for (unsigned i = 0; i < m_length; ++i)
</del><ins>+    auto buffer = StringImpl::tryCreateUninitialized(requiredLength, m_bufferCharacters16);
+    if (UNLIKELY(!buffer))
+        return didOverflow(); // Treat a failure to allcoate as an overflow.
+    for (unsigned i = 0; i < length; ++i)
</ins><span class="cx">         m_bufferCharacters16[i] = currentCharacters[i];
</span><span class="cx">     
</span><span class="cx">     m_is8Bit = false;
</span><span class="lines">@@ -151,11 +169,14 @@
</span><span class="cx">     ASSERT(m_is8Bit);
</span><span class="cx">     ASSERT(m_buffer->is8Bit());
</span><span class="cx">     
</span><del>-    if (m_buffer->hasOneRef())
-        m_buffer = StringImpl::reallocate(m_buffer.releaseNonNull(), requiredLength, m_bufferCharacters8);
-    else
</del><ins>+    if (m_buffer->hasOneRef()) {
+        auto expectedStringImpl = StringImpl::tryReallocate(m_buffer.releaseNonNull(), requiredLength, m_bufferCharacters8);
+        if (UNLIKELY(!expectedStringImpl))
+            return didOverflow();
+        m_buffer = WTFMove(expectedStringImpl.value());
+    } else
</ins><span class="cx">         allocateBuffer(m_buffer->characters8(), requiredLength);
</span><del>-    ASSERT(m_buffer->length() == requiredLength);
</del><ins>+    ASSERT(hasOverflowed() || m_buffer->length() == requiredLength);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template <>
</span><span class="lines">@@ -167,15 +188,21 @@
</span><span class="cx">     
</span><span class="cx">     if (m_buffer->is8Bit())
</span><span class="cx">         allocateBufferUpConvert(m_buffer->characters8(), requiredLength);
</span><del>-    else if (m_buffer->hasOneRef())
-        m_buffer = StringImpl::reallocate(m_buffer.releaseNonNull(), requiredLength, m_bufferCharacters16);
-    else
</del><ins>+    else if (m_buffer->hasOneRef()) {
+        auto expectedStringImpl = StringImpl::tryReallocate(m_buffer.releaseNonNull(), requiredLength, m_bufferCharacters16);
+        if (UNLIKELY(!expectedStringImpl))
+            return didOverflow();
+        m_buffer = WTFMove(expectedStringImpl.value());
+    } else
</ins><span class="cx">         allocateBuffer(m_buffer->characters16(), requiredLength);
</span><del>-    ASSERT(m_buffer->length() == requiredLength);
</del><ins>+    ASSERT(hasOverflowed() || m_buffer->length() == requiredLength);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void StringBuilder::reserveCapacity(unsigned newCapacity)
</span><span class="cx"> {
</span><ins>+    if (hasOverflowed())
+        return;
+    ASSERT(newCapacity <= String::MaxLength);
</ins><span class="cx">     if (m_buffer) {
</span><span class="cx">         // If there is already a buffer, then grow if necessary.
</span><span class="cx">         if (newCapacity > m_buffer->length()) {
</span><span class="lines">@@ -186,8 +213,9 @@
</span><span class="cx">         }
</span><span class="cx">     } else {
</span><span class="cx">         // Grow the string, if necessary.
</span><del>-        if (newCapacity > m_length) {
-            if (!m_length) {
</del><ins>+        unsigned length = m_length.unsafeGet();
+        if (newCapacity > length) {
+            if (!length) {
</ins><span class="cx">                 LChar* nullPlaceholder = 0;
</span><span class="cx">                 allocateBuffer(nullPlaceholder, newCapacity);
</span><span class="cx">             } else if (m_string.is8Bit())
</span><span class="lines">@@ -196,11 +224,12 @@
</span><span class="cx">                 allocateBuffer(m_string.characters16(), newCapacity);
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    ASSERT(!newCapacity || m_buffer->length() >= newCapacity);
</del><ins>+    ASSERT(hasOverflowed() || !newCapacity || m_buffer->length() >= newCapacity);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
</span><span class="cx"> // return a pointer to the newly allocated storage.
</span><ins>+// Returns nullptr if the size of the new builder would have overflowed
</ins><span class="cx"> template <typename CharType>
</span><span class="cx"> ALWAYS_INLINE CharType* StringBuilder::appendUninitialized(unsigned length)
</span><span class="cx"> {
</span><span class="lines">@@ -207,20 +236,22 @@
</span><span class="cx">     ASSERT(length);
</span><span class="cx"> 
</span><span class="cx">     // Calculate the new size of the builder after appending.
</span><del>-    unsigned requiredLength = length + m_length;
-    if (requiredLength < length)
-        CRASH();
</del><ins>+    CheckedInt32 requiredLength = m_length + length;
+    if (requiredLength.hasOverflowed()) {
+        didOverflow();
+        return nullptr;
+    }
</ins><span class="cx"> 
</span><del>-    if ((m_buffer) && (requiredLength <= m_buffer->length())) {
</del><ins>+    if (m_buffer && (requiredLength.unsafeGet<unsigned>() <= m_buffer->length())) {
</ins><span class="cx">         // If the buffer is valid it must be at least as long as the current builder contents!
</span><del>-        ASSERT(m_buffer->length() >= m_length);
-        unsigned currentLength = m_length;
</del><ins>+        ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
+        unsigned currentLength = m_length.unsafeGet();
</ins><span class="cx">         m_string = String();
</span><span class="cx">         m_length = requiredLength;
</span><span class="cx">         return getBufferCharacters<CharType>() + currentLength;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    return appendUninitializedSlow<CharType>(requiredLength);
</del><ins>+    return appendUninitializedSlow<CharType>(requiredLength.unsafeGet());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
</span><span class="lines">@@ -228,27 +259,31 @@
</span><span class="cx"> template <typename CharType>
</span><span class="cx"> CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength)
</span><span class="cx"> {
</span><ins>+    ASSERT(!hasOverflowed());
</ins><span class="cx">     ASSERT(requiredLength);
</span><span class="cx"> 
</span><span class="cx">     if (m_buffer) {
</span><span class="cx">         // If the buffer is valid it must be at least as long as the current builder contents!
</span><del>-        ASSERT(m_buffer->length() >= m_length);
</del><ins>+        ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
</ins><span class="cx">         
</span><span class="cx">         reallocateBuffer<CharType>(expandedCapacity(capacity(), requiredLength));
</span><span class="cx">     } else {
</span><del>-        ASSERT(m_string.length() == m_length);
</del><ins>+        ASSERT(m_string.length() == m_length.unsafeGet<unsigned>());
</ins><span class="cx">         allocateBuffer(m_length ? m_string.characters<CharType>() : 0, expandedCapacity(capacity(), requiredLength));
</span><span class="cx">     }
</span><del>-    
-    CharType* result = getBufferCharacters<CharType>() + m_length;
</del><ins>+    if (UNLIKELY(hasOverflowed()))
+        return nullptr;
+
+    CharType* result = getBufferCharacters<CharType>() + m_length.unsafeGet();
</ins><span class="cx">     m_length = requiredLength;
</span><del>-    ASSERT(m_buffer->length() >= m_length);
</del><ins>+    ASSERT(!hasOverflowed());
+    ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
</ins><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void StringBuilder::append(const UChar* characters, unsigned length)
</span><span class="cx"> {
</span><del>-    if (!length)
</del><ins>+    if (!length || hasOverflowed())
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     ASSERT(characters);
</span><span class="lines">@@ -257,40 +292,50 @@
</span><span class="cx">         if (length == 1 && !(*characters & ~0xff)) {
</span><span class="cx">             // Append as 8 bit character
</span><span class="cx">             LChar lChar = static_cast<LChar>(*characters);
</span><del>-            append(&lChar, 1);
-            return;
</del><ins>+            return append(&lChar, 1);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // Calculate the new size of the builder after appending.
</span><del>-        unsigned requiredLength = length + m_length;
-        if (requiredLength < length)
-            CRASH();
</del><ins>+        CheckedInt32 requiredLength = m_length + length;
+        if (requiredLength.hasOverflowed())
+            return didOverflow();
</ins><span class="cx">         
</span><span class="cx">         if (m_buffer) {
</span><span class="cx">             // If the buffer is valid it must be at least as long as the current builder contents!
</span><del>-            ASSERT(m_buffer->length() >= m_length);
-            
-            allocateBufferUpConvert(m_buffer->characters8(), expandedCapacity(capacity(), requiredLength));
</del><ins>+            ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
+            allocateBufferUpConvert(m_buffer->characters8(), expandedCapacity(capacity(), requiredLength.unsafeGet()));
</ins><span class="cx">         } else {
</span><del>-            ASSERT(m_string.length() == m_length);
-            allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8(), expandedCapacity(capacity(), requiredLength));
</del><ins>+            ASSERT(m_string.length() == m_length.unsafeGet<unsigned>());
+            allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8(), expandedCapacity(capacity(), requiredLength.unsafeGet()));
</ins><span class="cx">         }
</span><ins>+        if (UNLIKELY(hasOverflowed()))
+            return;
</ins><span class="cx"> 
</span><del>-        memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>(length) * sizeof(UChar));
</del><ins>+        memcpy(m_bufferCharacters16 + m_length.unsafeGet<unsigned>(), characters, static_cast<size_t>(length) * sizeof(UChar));
</ins><span class="cx">         m_length = requiredLength;
</span><del>-    } else
-        memcpy(appendUninitialized<UChar>(length), characters, static_cast<size_t>(length) * sizeof(UChar));
-    ASSERT(m_buffer->length() >= m_length);
</del><ins>+    } else {
+        UChar* dest = appendUninitialized<UChar>(length);
+        if (!dest)
+            return;
+        memcpy(dest, characters, static_cast<size_t>(length) * sizeof(UChar));
+    }
+    ASSERT(!hasOverflowed());
+    ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void StringBuilder::append(const LChar* characters, unsigned length)
</span><span class="cx"> {
</span><del>-    if (!length)
</del><ins>+    if (!length || hasOverflowed())
</ins><span class="cx">         return;
</span><ins>+
</ins><span class="cx">     ASSERT(characters);
</span><span class="cx"> 
</span><span class="cx">     if (m_is8Bit) {
</span><span class="cx">         LChar* dest = appendUninitialized<LChar>(length);
</span><ins>+        if (!dest) {
+            ASSERT(hasOverflowed());
+            return;
+        }
</ins><span class="cx">         if (length > 8)
</span><span class="cx">             memcpy(dest, characters, static_cast<size_t>(length) * sizeof(LChar));
</span><span class="cx">         else {
</span><span class="lines">@@ -300,6 +345,10 @@
</span><span class="cx">         }
</span><span class="cx">     } else {
</span><span class="cx">         UChar* dest = appendUninitialized<UChar>(length);
</span><ins>+        if (!dest) {
+            ASSERT(hasOverflowed());
+            return;
+        }
</ins><span class="cx">         const LChar* end = characters + length;
</span><span class="cx">         while (characters < end)
</span><span class="cx">             *(dest++) = *(characters++);
</span><span class="lines">@@ -370,8 +419,11 @@
</span><span class="cx"> 
</span><span class="cx"> bool StringBuilder::canShrink() const
</span><span class="cx"> {
</span><ins>+    if (hasOverflowed())
+        return false;
</ins><span class="cx">     // Only shrink the buffer if it's less than 80% full. Need to tune this heuristic!
</span><del>-    return m_buffer && m_buffer->length() > (m_length + (m_length >> 2));
</del><ins>+    unsigned length = m_length.unsafeGet();
+    return m_buffer && m_buffer->length() > (length + (length >> 2));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void StringBuilder::shrinkToFit()
</span><span class="lines">@@ -378,9 +430,10 @@
</span><span class="cx"> {
</span><span class="cx">     if (canShrink()) {
</span><span class="cx">         if (m_is8Bit)
</span><del>-            reallocateBuffer<LChar>(m_length);
</del><ins>+            reallocateBuffer<LChar>(m_length.unsafeGet());
</ins><span class="cx">         else
</span><del>-            reallocateBuffer<UChar>(m_length);
</del><ins>+            reallocateBuffer<UChar>(m_length.unsafeGet());
+        ASSERT(!hasOverflowed());
</ins><span class="cx">         m_string = WTFMove(m_buffer);
</span><span class="cx">     }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWTFwtftextStringBuilderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/StringBuilder.h (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/StringBuilder.h        2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/WTF/wtf/text/StringBuilder.h   2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2009-2010, 2012-2013, 2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2009-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2012 Google Inc. All rights reserved.
</span><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> 
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><ins>+#include <wtf/CheckedArithmetic.h>
</ins><span class="cx"> #include <wtf/text/AtomicString.h>
</span><span class="cx"> #include <wtf/text/IntegerToStringConversion.h>
</span><span class="cx"> #include <wtf/text/StringView.h>
</span><span class="lines">@@ -33,18 +34,39 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><ins>+// StringBuilder currently uses a Checked<int32_t, ConditionalCrashOnOverflow> for m_length.
+// Ideally, we would want to make StringBuilder a template with an OverflowHandler parameter, and
+// m_length can be instantiated based on that OverflowHandler instead. However, currently, we're
+// not able to get clang to export explicitly instantiated template methods (which would be needed
+// if we templatize StringBuilder). As a workaround, we use the ConditionalCrashOnOverflow handler
+// instead to do a runtime check on whether it should crash on overflows or not.
+//
+// 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.
+
</ins><span class="cx"> class StringBuilder {
</span><span class="cx">     // Disallow copying since it's expensive and we don't want code to do it by accident.
</span><span class="cx">     WTF_MAKE_NONCOPYABLE(StringBuilder);
</span><span class="cx"> 
</span><span class="cx"> public:
</span><del>-    StringBuilder()
</del><ins>+    enum class OverflowHandler {
+        CrashOnOverflow,
+        RecordOverflow
+    };
+
+    StringBuilder(OverflowHandler handler = OverflowHandler::CrashOnOverflow)
</ins><span class="cx">         : m_bufferCharacters8(nullptr)
</span><span class="cx">     {
</span><ins>+        m_length.setShouldCrashOnOverflow(handler == OverflowHandler::CrashOnOverflow);
</ins><span class="cx">     }
</span><span class="cx">     StringBuilder(StringBuilder&&) = default;
</span><span class="cx">     StringBuilder& operator=(StringBuilder&&) = default;
</span><span class="cx"> 
</span><ins>+    ALWAYS_INLINE void didOverflow() { m_length.overflowed(); }
+    ALWAYS_INLINE bool hasOverflowed() const { return m_length.hasOverflowed(); }
+    ALWAYS_INLINE bool crashesOnOverflow() const { return m_length.shouldCrashOnOverflow(); }
+
</ins><span class="cx">     WTF_EXPORT_PRIVATE void append(const UChar*, unsigned);
</span><span class="cx">     WTF_EXPORT_PRIVATE void append(const LChar*, unsigned);
</span><span class="cx"> 
</span><span class="lines">@@ -57,6 +79,9 @@
</span><span class="cx"> 
</span><span class="cx">     void append(const String& string)
</span><span class="cx">     {
</span><ins>+        if (hasOverflowed())
+            return;
+
</ins><span class="cx">         if (!string.length())
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="lines">@@ -77,6 +102,11 @@
</span><span class="cx"> 
</span><span class="cx">     void append(const StringBuilder& other)
</span><span class="cx">     {
</span><ins>+        if (hasOverflowed())
+            return;
+        if (other.hasOverflowed())
+            return didOverflow();
+
</ins><span class="cx">         if (!other.m_length)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="lines">@@ -89,9 +119,9 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (other.is8Bit())
</span><del>-            append(other.characters8(), other.m_length);
</del><ins>+            append(other.characters8(), other.m_length.unsafeGet());
</ins><span class="cx">         else
</span><del>-            append(other.characters16(), other.m_length);
</del><ins>+            append(other.characters16(), other.m_length.unsafeGet());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void append(StringView stringView)
</span><span class="lines">@@ -131,14 +161,19 @@
</span><span class="cx"> 
</span><span class="cx">     void append(UChar c)
</span><span class="cx">     {
</span><del>-        if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) {
</del><ins>+        if (hasOverflowed())
+            return;
+        unsigned length = m_length.unsafeGet<unsigned>();
+        if (m_buffer && length < m_buffer->length() && m_string.isNull()) {
</ins><span class="cx">             if (!m_is8Bit) {
</span><del>-                m_bufferCharacters16[m_length++] = c;
</del><ins>+                m_bufferCharacters16[length] = c;
+                m_length++;
</ins><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             if (!(c & ~0xff)) {
</span><del>-                m_bufferCharacters8[m_length++] = static_cast<LChar>(c);
</del><ins>+                m_bufferCharacters8[length] = static_cast<LChar>(c);
+                m_length++;
</ins><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="lines">@@ -147,11 +182,15 @@
</span><span class="cx"> 
</span><span class="cx">     void append(LChar c)
</span><span class="cx">     {
</span><del>-        if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) {
</del><ins>+        if (hasOverflowed())
+            return;
+        unsigned length = m_length.unsafeGet<unsigned>();
+        if (m_buffer && length < m_buffer->length() && m_string.isNull()) {
</ins><span class="cx">             if (m_is8Bit)
</span><del>-                m_bufferCharacters8[m_length++] = c;
</del><ins>+                m_bufferCharacters8[length] = c;
</ins><span class="cx">             else
</span><del>-                m_bufferCharacters16[m_length++] = c;
</del><ins>+                m_bufferCharacters16[length] = c;
+            m_length++;
</ins><span class="cx">         } else
</span><span class="cx">             append(&c, 1);
</span><span class="cx">     }
</span><span class="lines">@@ -171,7 +210,7 @@
</span><span class="cx">         append(U16_TRAIL(c));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    WTF_EXPORT_PRIVATE bool appendQuotedJSONString(const String&);
</del><ins>+    WTF_EXPORT_PRIVATE void appendQuotedJSONString(const String&);
</ins><span class="cx"> 
</span><span class="cx">     template<unsigned characterCount>
</span><span class="cx">     ALWAYS_INLINE void appendLiteral(const char (&characters)[characterCount]) { append(characters, characterCount - 1); }
</span><span class="lines">@@ -188,6 +227,7 @@
</span><span class="cx"> 
</span><span class="cx">     String toString()
</span><span class="cx">     {
</span><ins>+        RELEASE_ASSERT(!hasOverflowed());
</ins><span class="cx">         shrinkToFit();
</span><span class="cx">         if (m_string.isNull())
</span><span class="cx">             reifyString();
</span><span class="lines">@@ -196,6 +236,7 @@
</span><span class="cx"> 
</span><span class="cx">     const String& toStringPreserveCapacity() const
</span><span class="cx">     {
</span><ins>+        RELEASE_ASSERT(!hasOverflowed());
</ins><span class="cx">         if (m_string.isNull())
</span><span class="cx">             reifyString();
</span><span class="cx">         return m_string;
</span><span class="lines">@@ -203,6 +244,7 @@
</span><span class="cx"> 
</span><span class="cx">     AtomicString toAtomicString() const
</span><span class="cx">     {
</span><ins>+        RELEASE_ASSERT(!hasOverflowed());
</ins><span class="cx">         if (!m_length)
</span><span class="cx">             return emptyAtom();
</span><span class="cx"> 
</span><span class="lines">@@ -217,12 +259,13 @@
</span><span class="cx">             return AtomicString(m_string);
</span><span class="cx"> 
</span><span class="cx">         ASSERT(m_buffer);
</span><del>-        return AtomicString(m_buffer.get(), 0, m_length);
</del><ins>+        return AtomicString(m_buffer.get(), 0, m_length.unsafeGet());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     unsigned length() const
</span><span class="cx">     {
</span><del>-        return m_length;
</del><ins>+        RELEASE_ASSERT(!hasOverflowed());
+        return m_length.unsafeGet();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     bool isEmpty() const { return !m_length; }
</span><span class="lines">@@ -231,7 +274,8 @@
</span><span class="cx"> 
</span><span class="cx">     unsigned capacity() const
</span><span class="cx">     {
</span><del>-        return m_buffer ? m_buffer->length() : m_length;
</del><ins>+        RELEASE_ASSERT(!hasOverflowed());
+        return m_buffer ? m_buffer->length() : m_length.unsafeGet();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     WTF_EXPORT_PRIVATE void resize(unsigned newSize);
</span><span class="lines">@@ -242,7 +286,7 @@
</span><span class="cx"> 
</span><span class="cx">     UChar operator[](unsigned i) const
</span><span class="cx">     {
</span><del>-        ASSERT_WITH_SECURITY_IMPLICATION(i < m_length);
</del><ins>+        RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!hasOverflowed() && i < m_length.unsafeGet<unsigned>());
</ins><span class="cx">         if (m_is8Bit)
</span><span class="cx">             return characters8()[i];
</span><span class="cx">         return characters16()[i];
</span><span class="lines">@@ -288,7 +332,7 @@
</span><span class="cx">         m_buffer.swap(stringBuilder.m_buffer);
</span><span class="cx">         std::swap(m_is8Bit, stringBuilder.m_is8Bit);
</span><span class="cx">         std::swap(m_bufferCharacters8, stringBuilder.m_bufferCharacters8);
</span><del>-        ASSERT(!m_buffer || m_buffer->length() >= m_length);
</del><ins>+        ASSERT(!m_buffer || hasOverflowed() || m_buffer->length() >= m_length.unsafeGet<unsigned>());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="lines">@@ -311,7 +355,8 @@
</span><span class="cx">         LChar* m_bufferCharacters8;
</span><span class="cx">         UChar* m_bufferCharacters16;
</span><span class="cx">     };
</span><del>-    unsigned m_length { 0 };
</del><ins>+    static_assert(String::MaxLength == std::numeric_limits<int32_t>::max(), "");
+    Checked<int32_t, ConditionalCrashOnOverflow> m_length;
</ins><span class="cx">     bool m_is8Bit { true };
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -327,7 +372,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!m_is8Bit);
</span><span class="cx">     return m_bufferCharacters16;
</span><del>-}    
</del><ins>+}
</ins><span class="cx"> 
</span><span class="cx"> template <typename CharType>
</span><span class="cx"> bool equal(const StringBuilder& s, const CharType* buffer, unsigned length)
</span></span></pre></div>
<a id="trunkSourceWTFwtftextStringBuilderJSONcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/StringBuilderJSON.cpp (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/StringBuilderJSON.cpp  2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/WTF/wtf/text/StringBuilderJSON.cpp     2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2010, 2013, 2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2010-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2012 Google Inc. All rights reserved.
</span><span class="cx">  * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>. All rights reserved.
</span><span class="cx">  * Copyright (C) 2017 Mozilla Foundation. All rights reserved.
</span><span class="lines">@@ -74,8 +74,10 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool StringBuilder::appendQuotedJSONString(const String& string)
</del><ins>+void StringBuilder::appendQuotedJSONString(const String& string)
</ins><span class="cx"> {
</span><ins>+    if (hasOverflowed())
+        return;
</ins><span class="cx">     // Make sure we have enough buffer space to append this string without having
</span><span class="cx">     // to worry about reallocating in the middle.
</span><span class="cx">     // The 2 is for the '"' quotes on each end.
</span><span class="lines">@@ -85,7 +87,7 @@
</span><span class="cx">     maximumCapacityRequired += 2 + stringLength * 6;
</span><span class="cx">     unsigned allocationSize;
</span><span class="cx">     if (CheckedState::DidOverflow == maximumCapacityRequired.safeGet(allocationSize))
</span><del>-        return false;
</del><ins>+        return didOverflow();
</ins><span class="cx">     // This max() is here to allow us to allocate sizes between the range [2^31, 2^32 - 2] because roundUpToPowerOfTwo(1<<31 + some int smaller than 1<<31) == 0.
</span><span class="cx">     // FIXME: roundUpToPowerOfTwo should take Checked<unsigned> and abort if it fails to round up.
</span><span class="cx">     // https://bugs.webkit.org/show_bug.cgi?id=176086
</span><span class="lines">@@ -92,24 +94,26 @@
</span><span class="cx">     allocationSize = std::max(allocationSize, roundUpToPowerOfTwo(allocationSize));
</span><span class="cx"> 
</span><span class="cx">     // Allocating this much will definitely fail.
</span><del>-    if (allocationSize >= 0x80000000)
-        return false;
</del><ins>+    if (allocationSize > String::MaxLength)
+        return didOverflow();
</ins><span class="cx"> 
</span><span class="cx">     if (is8Bit() && !string.is8Bit())
</span><span class="cx">         allocateBufferUpConvert(m_bufferCharacters8, allocationSize);
</span><span class="cx">     else
</span><span class="cx">         reserveCapacity(allocationSize);
</span><ins>+    if (UNLIKELY(hasOverflowed()))
+        return;
</ins><span class="cx">     ASSERT(m_buffer->length() >= allocationSize);
</span><span class="cx"> 
</span><span class="cx">     if (is8Bit()) {
</span><span class="cx">         ASSERT(string.is8Bit());
</span><del>-        LChar* output = m_bufferCharacters8 + m_length;
</del><ins>+        LChar* output = m_bufferCharacters8 + m_length.unsafeGet<unsigned>();
</ins><span class="cx">         *output++ = '"';
</span><span class="cx">         appendQuotedJSONStringInternal(output, string.characters8(), string.length());
</span><span class="cx">         *output++ = '"';
</span><span class="cx">         m_length = output - m_bufferCharacters8;
</span><span class="cx">     } else {
</span><del>-        UChar* output = m_bufferCharacters16 + m_length;
</del><ins>+        UChar* output = m_bufferCharacters16 + m_length.unsafeGet<unsigned>();
</ins><span class="cx">         *output++ = '"';
</span><span class="cx">         if (string.is8Bit())
</span><span class="cx">             appendQuotedJSONStringInternal(output, string.characters8(), string.length());
</span><span class="lines">@@ -118,8 +122,8 @@
</span><span class="cx">         *output++ = '"';
</span><span class="cx">         m_length = output - m_bufferCharacters16;
</span><span class="cx">     }
</span><del>-    ASSERT(m_buffer->length() >= m_length);
-    return true;
</del><ins>+    ASSERT(!hasOverflowed());
+    ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WTF
</span></span></pre></div>
<a id="trunkSourceWTFwtftextStringImplcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/StringImpl.cpp (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/StringImpl.cpp 2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/WTF/wtf/text/StringImpl.cpp    2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -2,7 +2,7 @@
</span><span class="cx">  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
</span><span class="cx">  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
</span><span class="cx">  *           (C) 2001 Dirk Mueller ( mueller@kde.org )
</span><del>- * Copyright (C) 2003-2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2003-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
</span><span class="cx">  *
</span><span class="cx">  * This library is free software; you can redistribute it and/or
</span><span class="lines">@@ -211,7 +211,7 @@
</span><span class="cx">     return createUninitializedInternal(length, data);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template<typename CharacterType> inline Ref<StringImpl> StringImpl::reallocateInternal(Ref<StringImpl>&& originalString, unsigned length, CharacterType*& data)
</del><ins>+template<typename CharacterType> inline Expected<Ref<StringImpl>, UTF8ConversionError> StringImpl::reallocateInternal(Ref<StringImpl>&& originalString, unsigned length, CharacterType*& data)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(originalString->hasOneRef());
</span><span class="cx">     ASSERT(originalString->bufferOwnership() == BufferInternal);
</span><span class="lines">@@ -218,15 +218,17 @@
</span><span class="cx"> 
</span><span class="cx">     if (!length) {
</span><span class="cx">         data = 0;
</span><del>-        return *empty();
</del><ins>+        return Ref<StringImpl>(*empty());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Same as createUninitialized() except here we use fastRealloc.
</span><span class="cx">     if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(CharacterType)))
</span><del>-        CRASH();
</del><ins>+        return makeUnexpected(UTF8ConversionError::OutOfMemory);
</ins><span class="cx"> 
</span><span class="cx">     originalString->~StringImpl();
</span><del>-    auto* string = static_cast<StringImpl*>(fastRealloc(&originalString.leakRef(), allocationSize<CharacterType>(length)));
</del><ins>+    StringImpl* string;
+    if (!tryFastRealloc(&originalString.leakRef(), allocationSize<CharacterType>(length)).getValue(string))
+        return makeUnexpected(UTF8ConversionError::OutOfMemory);
</ins><span class="cx"> 
</span><span class="cx">     data = string->tailPointer<CharacterType>();
</span><span class="cx">     return constructInternal<CharacterType>(*string, length);
</span><span class="lines">@@ -234,11 +236,25 @@
</span><span class="cx"> 
</span><span class="cx"> Ref<StringImpl> StringImpl::reallocate(Ref<StringImpl>&& originalString, unsigned length, LChar*& data)
</span><span class="cx"> {
</span><ins>+    auto expectedStringImpl = tryReallocate(WTFMove(originalString), length, data);
+    RELEASE_ASSERT(expectedStringImpl);
+    return WTFMove(expectedStringImpl.value());
+}
+
+Ref<StringImpl> StringImpl::reallocate(Ref<StringImpl>&& originalString, unsigned length, UChar*& data)
+{
+    auto expectedStringImpl = tryReallocate(WTFMove(originalString), length, data);
+    RELEASE_ASSERT(expectedStringImpl);
+    return WTFMove(expectedStringImpl.value());
+}
+
+Expected<Ref<StringImpl>, UTF8ConversionError> StringImpl::tryReallocate(Ref<StringImpl>&& originalString, unsigned length, LChar*& data)
+{
</ins><span class="cx">     ASSERT(originalString->is8Bit());
</span><span class="cx">     return reallocateInternal(WTFMove(originalString), length, data);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Ref<StringImpl> StringImpl::reallocate(Ref<StringImpl>&& originalString, unsigned length, UChar*& data)
</del><ins>+Expected<Ref<StringImpl>, UTF8ConversionError> StringImpl::tryReallocate(Ref<StringImpl>&& originalString, unsigned length, UChar*& data)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!originalString->is8Bit());
</span><span class="cx">     return reallocateInternal(WTFMove(originalString), length, data);
</span></span></pre></div>
<a id="trunkSourceWTFwtftextStringImplh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/StringImpl.h (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/StringImpl.h   2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/WTF/wtf/text/StringImpl.h      2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -254,6 +254,8 @@
</span><span class="cx">     // the originalString can't be used after this function.
</span><span class="cx">     static Ref<StringImpl> reallocate(Ref<StringImpl>&& originalString, unsigned length, LChar*& data);
</span><span class="cx">     static Ref<StringImpl> reallocate(Ref<StringImpl>&& originalString, unsigned length, UChar*& data);
</span><ins>+    static Expected<Ref<StringImpl>, UTF8ConversionError> tryReallocate(Ref<StringImpl>&& originalString, unsigned length, LChar*& data);
+    static Expected<Ref<StringImpl>, UTF8ConversionError> tryReallocate(Ref<StringImpl>&& originalString, unsigned length, UChar*& data);
</ins><span class="cx"> 
</span><span class="cx">     static unsigned flagsOffset() { return OBJECT_OFFSETOF(StringImpl, m_hashAndFlags); }
</span><span class="cx">     static unsigned flagIs8Bit() { return s_hashFlag8BitBuffer; }
</span><span class="lines">@@ -510,7 +512,7 @@
</span><span class="cx">     template<typename CharacterType> static Ref<StringImpl> constructInternal(StringImpl&, unsigned);
</span><span class="cx">     template<typename CharacterType> static Ref<StringImpl> createUninitializedInternal(unsigned, CharacterType*&);
</span><span class="cx">     template<typename CharacterType> static Ref<StringImpl> createUninitializedInternalNonEmpty(unsigned, CharacterType*&);
</span><del>-    template<typename CharacterType> static Ref<StringImpl> reallocateInternal(Ref<StringImpl>&&, unsigned, CharacterType*&);
</del><ins>+    template<typename CharacterType> static Expected<Ref<StringImpl>, UTF8ConversionError> reallocateInternal(Ref<StringImpl>&&, unsigned, CharacterType*&);
</ins><span class="cx">     template<typename CharacterType> static Ref<StringImpl> createInternal(const CharacterType*, unsigned);
</span><span class="cx">     WTF_EXPORT_PRIVATE NEVER_INLINE unsigned hashSlowCase() const;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourcebmallocChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/bmalloc/ChangeLog (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/bmalloc/ChangeLog   2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/bmalloc/ChangeLog      2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,3 +1,24 @@
</span><ins>+2018-10-29  Mark Lam  <mark.lam@apple.com>
+
+        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.
+
+        * 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):
+
</ins><span class="cx"> 2018-10-25  Ross Kirsling  <ross.kirsling@sony.com>
</span><span class="cx"> 
</span><span class="cx">         Cleanup: inline constexpr is redundant as constexpr implies inline
</span></span></pre></div>
<a id="trunkSourcebmallocbmallocAllocatorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/bmalloc/bmalloc/Allocator.cpp (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/bmalloc/bmalloc/Allocator.cpp       2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/bmalloc/bmalloc/Allocator.cpp  2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -95,8 +95,20 @@
</span><span class="cx"> 
</span><span class="cx"> void* Allocator::reallocate(void* object, size_t newSize)
</span><span class="cx"> {
</span><ins>+    bool crashOnFailure = true;
+    return reallocateImpl(object, newSize, crashOnFailure);
+}
+
+void* Allocator::tryReallocate(void* object, size_t newSize)
+{
+    bool crashOnFailure = false;
+    return reallocateImpl(object, newSize, crashOnFailure);
+}
+
+void* Allocator::reallocateImpl(void* object, size_t newSize, bool crashOnFailure)
+{
</ins><span class="cx">     if (m_debugHeap)
</span><del>-        return m_debugHeap->realloc(object, newSize);
</del><ins>+        return m_debugHeap->realloc(object, newSize, crashOnFailure);
</ins><span class="cx"> 
</span><span class="cx">     size_t oldSize = 0;
</span><span class="cx">     switch (objectType(m_heap.kind(), object)) {
</span><span class="lines">@@ -121,7 +133,14 @@
</span><span class="cx">     }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void* result = allocate(newSize);
</del><ins>+    void* result = nullptr;
+    if (crashOnFailure)
+        result = allocate(newSize);
+    else {
+        result = tryAllocate(newSize);
+        if (!result)
+            return nullptr;
+    }
</ins><span class="cx">     size_t copySize = std::min(oldSize, newSize);
</span><span class="cx">     memcpy(result, object, copySize);
</span><span class="cx">     m_deallocator.deallocate(object);
</span></span></pre></div>
<a id="trunkSourcebmallocbmallocAllocatorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/bmalloc/bmalloc/Allocator.h (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/bmalloc/bmalloc/Allocator.h 2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/bmalloc/bmalloc/Allocator.h    2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -47,6 +47,7 @@
</span><span class="cx">     void* allocate(size_t);
</span><span class="cx">     void* tryAllocate(size_t alignment, size_t);
</span><span class="cx">     void* allocate(size_t alignment, size_t);
</span><ins>+    void* tryReallocate(void*, size_t);
</ins><span class="cx">     void* reallocate(void*, size_t);
</span><span class="cx"> 
</span><span class="cx">     void scavenge();
</span><span class="lines">@@ -53,7 +54,8 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     void* allocateImpl(size_t alignment, size_t, bool crashOnFailure);
</span><del>-    
</del><ins>+    void* reallocateImpl(void*, size_t, bool crashOnFailure);
+
</ins><span class="cx">     bool allocateFastCase(size_t, void*&);
</span><span class="cx">     BEXPORT void* allocateSlowCase(size_t);
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourcebmallocbmallocCacheh"></a>
<div class="modfile"><h4>Modified: trunk/Source/bmalloc/bmalloc/Cache.h (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/bmalloc/bmalloc/Cache.h     2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/bmalloc/bmalloc/Cache.h        2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -43,6 +43,7 @@
</span><span class="cx">     static void* tryAllocate(HeapKind, size_t alignment, size_t);
</span><span class="cx">     static void* allocate(HeapKind, size_t alignment, size_t);
</span><span class="cx">     static void deallocate(HeapKind, void*);
</span><ins>+    static void* tryReallocate(HeapKind, void*, size_t);
</ins><span class="cx">     static void* reallocate(HeapKind, void*, size_t);
</span><span class="cx"> 
</span><span class="cx">     static void scavenge(HeapKind);
</span><span class="lines">@@ -103,6 +104,14 @@
</span><span class="cx">     return caches->at(mapToActiveHeapKindAfterEnsuringGigacage(heapKind)).deallocator().deallocate(object);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline void* Cache::tryReallocate(HeapKind heapKind, void* object, size_t newSize)
+{
+    PerHeapKind<Cache>* caches = PerThread<PerHeapKind<Cache>>::getFastCase();
+    if (!caches)
+        return reallocateSlowCaseNullCache(heapKind, object, newSize);
+    return caches->at(mapToActiveHeapKindAfterEnsuringGigacage(heapKind)).allocator().tryReallocate(object, newSize);
+}
+
</ins><span class="cx"> inline void* Cache::reallocate(HeapKind heapKind, void* object, size_t newSize)
</span><span class="cx"> {
</span><span class="cx">     PerHeapKind<Cache>* caches = PerThread<PerHeapKind<Cache>>::getFastCase();
</span></span></pre></div>
<a id="trunkSourcebmallocbmallocDebugHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/bmalloc/bmalloc/DebugHeap.cpp (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/bmalloc/bmalloc/DebugHeap.cpp       2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/bmalloc/bmalloc/DebugHeap.cpp  2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -59,10 +59,10 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void* DebugHeap::realloc(void* object, size_t size)
</del><ins>+void* DebugHeap::realloc(void* object, size_t size, bool crashOnFailure)
</ins><span class="cx"> {
</span><span class="cx">     void* result = malloc_zone_realloc(m_zone, object, size);
</span><del>-    if (!result)
</del><ins>+    if (!result && crashOnFailure)
</ins><span class="cx">         BCRASH();
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="lines">@@ -98,10 +98,10 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void* DebugHeap::realloc(void* object, size_t size)
</del><ins>+void* DebugHeap::realloc(void* object, size_t size, bool crashOnFailure)
</ins><span class="cx"> {
</span><span class="cx">     void* result = ::realloc(object, size);
</span><del>-    if (!result)
</del><ins>+    if (!result && crashOnFailure)
</ins><span class="cx">         BCRASH();
</span><span class="cx">     return result;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourcebmallocbmallocDebugHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/bmalloc/bmalloc/DebugHeap.h (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/bmalloc/bmalloc/DebugHeap.h 2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/bmalloc/bmalloc/DebugHeap.h    2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -41,7 +41,7 @@
</span><span class="cx">     
</span><span class="cx">     void* malloc(size_t);
</span><span class="cx">     void* memalign(size_t alignment, size_t, bool crashOnFailure);
</span><del>-    void* realloc(void*, size_t);
</del><ins>+    void* realloc(void*, size_t, bool crashOnFailure);
</ins><span class="cx">     void free(void*);
</span><span class="cx">     
</span><span class="cx">     void* memalignLarge(size_t alignment, size_t);
</span></span></pre></div>
<a id="trunkSourcebmallocbmallocbmalloch"></a>
<div class="modfile"><h4>Modified: trunk/Source/bmalloc/bmalloc/bmalloc.h (237576 => 237577)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/bmalloc/bmalloc/bmalloc.h   2018-10-30 02:51:23 UTC (rev 237576)
+++ trunk/Source/bmalloc/bmalloc/bmalloc.h      2018-10-30 02:58:51 UTC (rev 237577)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -63,6 +63,12 @@
</span><span class="cx">     return Cache::allocate(kind, alignment, size);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// Returns null on failure.
+inline void* tryRealloc(void* object, size_t newSize, HeapKind kind = HeapKind::Primary)
+{
+    return Cache::tryReallocate(kind, object, newSize);
+}
+
</ins><span class="cx"> // Crashes on failure.
</span><span class="cx"> inline void* realloc(void* object, size_t newSize, HeapKind kind = HeapKind::Primary)
</span><span class="cx"> {
</span></span></pre>
</div>
</div>

</body>
</html>