Array concat operation should check for length overflows.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Mar 2017 23:51:19 +0000 (23:51 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Mar 2017 23:51:19 +0000 (23:51 +0000)
https://bugs.webkit.org/show_bug.cgi?id=169796
<rdar://problem/31095276>

Reviewed by Keith Miller.

* runtime/ArrayPrototype.cpp:
(JSC::concatAppendOne):
(JSC::arrayProtoPrivateFuncConcatMemcpy):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@214079 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/ArrayPrototype.cpp

index 82841f8..d2fef84 100644 (file)
@@ -1,5 +1,17 @@
 2017-03-16  Mark Lam  <mark.lam@apple.com>
 
+        Array concat operation should check for length overflows.
+        https://bugs.webkit.org/show_bug.cgi?id=169796
+        <rdar://problem/31095276>
+
+        Reviewed by Keith Miller.
+
+        * runtime/ArrayPrototype.cpp:
+        (JSC::concatAppendOne):
+        (JSC::arrayProtoPrivateFuncConcatMemcpy):
+
+2017-03-16  Mark Lam  <mark.lam@apple.com>
+
         The new array with spread operation needs to check for length overflows.
         https://bugs.webkit.org/show_bug.cgi?id=169780
         <rdar://problem/31072182>
index 8376fd3..85ff654 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2003, 2007-2009, 2011, 2013, 2015-2017 Apple Inc. All rights reserved.
+ *  Copyright (C) 2003-2017 Apple Inc. All rights reserved.
  *  Copyright (C) 2003 Peter Kelly (pmk@post.com)
  *  Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
  *
@@ -1205,15 +1205,25 @@ static EncodedJSValue concatAppendOne(ExecState* exec, VM& vm, JSArray* first, J
     Butterfly* firstButterfly = first->butterfly();
     unsigned firstArraySize = firstButterfly->publicLength();
 
+    Checked<unsigned, RecordOverflow> checkedResultSize = firstArraySize;
+    checkedResultSize += 1;
+    if (UNLIKELY(checkedResultSize.hasOverflowed())) {
+        throwOutOfMemoryError(exec, scope);
+        return encodedJSValue();
+    }
+
+    unsigned resultSize = checkedResultSize.unsafeGet();
     IndexingType type = first->mergeIndexingTypeForCopying(indexingTypeForValue(second) | IsArray);
     
     if (type == NonArray)
         type = first->indexingType();
 
     Structure* resultStructure = exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(type);
-    JSArray* result = JSArray::create(vm, resultStructure, firstArraySize + 1);
-    if (!result)
-        return JSValue::encode(throwOutOfMemoryError(exec, scope));
+    JSArray* result = JSArray::create(vm, resultStructure, resultSize);
+    if (UNLIKELY(!result)) {
+        throwOutOfMemoryError(exec, scope);
+        return encodedJSValue();
+    }
 
     bool success = result->appendMemcpy(exec, vm, 0, first);
     ASSERT(!success || !scope.exception());
@@ -1266,10 +1276,19 @@ EncodedJSValue JSC_HOST_CALL arrayProtoPrivateFuncConcatMemcpy(ExecState* exec)
     unsigned firstArraySize = firstButterfly->publicLength();
     unsigned secondArraySize = secondButterfly->publicLength();
 
+    Checked<unsigned, RecordOverflow> checkedResultSize = firstArraySize;
+    checkedResultSize += secondArraySize;
+
+    if (UNLIKELY(checkedResultSize.hasOverflowed())) {
+        throwOutOfMemoryError(exec, scope);
+        return encodedJSValue();
+    }
+
+    unsigned resultSize = checkedResultSize.unsafeGet();
     IndexingType secondType = secondArray->indexingType();
     IndexingType type = firstArray->mergeIndexingTypeForCopying(secondType);
-    if (type == NonArray || !firstArray->canFastCopy(vm, secondArray) || firstArraySize + secondArraySize >= MIN_SPARSE_ARRAY_INDEX) {
-        JSArray* result = constructEmptyArray(exec, nullptr, firstArraySize + secondArraySize);
+    if (type == NonArray || !firstArray->canFastCopy(vm, secondArray) || resultSize >= MIN_SPARSE_ARRAY_INDEX) {
+        JSArray* result = constructEmptyArray(exec, nullptr, resultSize);
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
         bool success = moveElements(exec, vm, result, 0, firstArray, firstArraySize);
@@ -1285,9 +1304,11 @@ EncodedJSValue JSC_HOST_CALL arrayProtoPrivateFuncConcatMemcpy(ExecState* exec)
     }
 
     Structure* resultStructure = exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(type);
-    JSArray* result = JSArray::tryCreateForInitializationPrivate(vm, resultStructure, firstArraySize + secondArraySize);
-    if (!result)
-        return JSValue::encode(throwOutOfMemoryError(exec, scope));
+    JSArray* result = JSArray::tryCreateForInitializationPrivate(vm, resultStructure, resultSize);
+    if (UNLIKELY(!result)) {
+        throwOutOfMemoryError(exec, scope);
+        return encodedJSValue();
+    }
     
     if (type == ArrayWithDouble) {
         double* buffer = result->butterfly()->contiguousDouble().data();
@@ -1304,7 +1325,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoPrivateFuncConcatMemcpy(ExecState* exec)
         }
     }
 
-    result->butterfly()->setPublicLength(firstArraySize + secondArraySize);
+    result->butterfly()->setPublicLength(resultSize);
     return JSValue::encode(result);
 }