Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp

Issue 1414553002: Fix out-of-memory crashes related to ArrayBuffer allocation Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase and applied senorblanco+haraken feedbac Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "config.h" 5 #include "config.h"
6 #include "bindings/core/v8/ScriptValueSerializer.h" 6 #include "bindings/core/v8/ScriptValueSerializer.h"
7 7
8 #include "bindings/core/v8/V8ArrayBuffer.h" 8 #include "bindings/core/v8/V8ArrayBuffer.h"
9 #include "bindings/core/v8/V8ArrayBufferView.h" 9 #include "bindings/core/v8/V8ArrayBufferView.h"
10 #include "bindings/core/v8/V8Blob.h" 10 #include "bindings/core/v8/V8Blob.h"
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 void SerializedScriptValueWriter::writeArrayBuffer(const DOMArrayBuffer& arrayBu ffer) 244 void SerializedScriptValueWriter::writeArrayBuffer(const DOMArrayBuffer& arrayBu ffer)
245 { 245 {
246 append(ArrayBufferTag); 246 append(ArrayBufferTag);
247 doWriteArrayBuffer(arrayBuffer); 247 doWriteArrayBuffer(arrayBuffer);
248 } 248 }
249 249
250 void SerializedScriptValueWriter::writeArrayBufferView(const DOMArrayBufferView& arrayBufferView) 250 void SerializedScriptValueWriter::writeArrayBufferView(const DOMArrayBufferView& arrayBufferView)
251 { 251 {
252 append(ArrayBufferViewTag); 252 append(ArrayBufferViewTag);
253 #if ENABLE(ASSERT) 253 #if ENABLE(ASSERT)
254 ASSERT(static_cast<const uint8_t*>(arrayBufferView.bufferBase()->data()) + a rrayBufferView.byteOffset() == 254 ASSERT(static_cast<const uint8_t*>(arrayBufferView.bufferBaseOrNull()->data( )) + arrayBufferView.byteOffset() ==
haraken 2015/10/29 18:58:37 arrayBufferView.bufferBaseOrNull() can return null
Justin Novosad 2015/11/05 00:17:51 Done.
255 static_cast<const uint8_t*>(arrayBufferView.baseAddress())); 255 static_cast<const uint8_t*>(arrayBufferView.baseAddress()));
256 #endif 256 #endif
257 DOMArrayBufferView::ViewType type = arrayBufferView.type(); 257 DOMArrayBufferView::ViewType type = arrayBufferView.type();
258 258
259 switch (type) { 259 switch (type) {
260 case DOMArrayBufferView::TypeInt8: 260 case DOMArrayBufferView::TypeInt8:
261 append(ByteArrayTag); 261 append(ByteArrayTag);
262 break; 262 break;
263 case DOMArrayBufferView::TypeUint8Clamped: 263 case DOMArrayBufferView::TypeUint8Clamped:
264 append(UnsignedByteClampedArrayTag); 264 append(UnsignedByteClampedArrayTag);
(...skipping 704 matching lines...) Expand 10 before | Expand all | Expand 10 after
969 { 969 {
970 v8::Local<v8::RegExp> regExp = value.As<v8::RegExp>(); 970 v8::Local<v8::RegExp> regExp = value.As<v8::RegExp>();
971 m_writer.writeRegExp(regExp->GetSource(), regExp->GetFlags()); 971 m_writer.writeRegExp(regExp->GetSource(), regExp->GetFlags());
972 } 972 }
973 973
974 ScriptValueSerializer::StateBase* ScriptValueSerializer::writeAndGreyArrayBuffer View(v8::Local<v8::Object> object, ScriptValueSerializer::StateBase* next) 974 ScriptValueSerializer::StateBase* ScriptValueSerializer::writeAndGreyArrayBuffer View(v8::Local<v8::Object> object, ScriptValueSerializer::StateBase* next)
975 { 975 {
976 ASSERT(!object.IsEmpty()); 976 ASSERT(!object.IsEmpty());
977 DOMArrayBufferView* arrayBufferView = V8ArrayBufferView::toImpl(object); 977 DOMArrayBufferView* arrayBufferView = V8ArrayBufferView::toImpl(object);
978 if (!arrayBufferView) 978 if (!arrayBufferView)
979 return 0; 979 return nullptr;
980 if (!arrayBufferView->bufferBase()) 980 if (!arrayBufferView->bufferBaseOrNull())
981 return handleError(DataCloneError, "An ArrayBuffer could not be cloned." , next); 981 return handleError(DataCloneError, "An ArrayBuffer could not be cloned." , next);
982 v8::Local<v8::Value> underlyingBuffer = toV8(arrayBufferView->bufferBase(), m_scriptState->context()->Global(), isolate()); 982 v8::Local<v8::Value> underlyingBuffer = toV8(arrayBufferView->bufferBaseOrNu ll(), m_scriptState->context()->Global(), isolate());
983 if (underlyingBuffer.IsEmpty()) 983 if (underlyingBuffer.IsEmpty())
984 return handleError(DataCloneError, "An ArrayBuffer could not be cloned." , next); 984 return handleError(DataCloneError, "An ArrayBuffer could not be cloned." , next);
985 StateBase* stateOut = doSerializeArrayBuffer(underlyingBuffer, next); 985 StateBase* stateOut = doSerializeArrayBuffer(underlyingBuffer, next);
986 if (stateOut) 986 if (stateOut)
987 return stateOut; 987 return stateOut;
988 m_writer.writeArrayBufferView(*arrayBufferView); 988 m_writer.writeArrayBufferView(*arrayBufferView);
989 // This should be safe: we serialize something that we know to be a wrapper (see 989 // This should be safe: we serialize something that we know to be a wrapper (see
990 // the toV8 call above), so the call to doSerializeArrayBuffer should neithe r 990 // the toV8 call above), so the call to doSerializeArrayBuffer should neithe r
991 // cause the system stack to overflow nor should it have potential to reach 991 // cause the system stack to overflow nor should it have potential to reach
992 // this ArrayBufferView again. 992 // this ArrayBufferView again.
(...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after
1525 uint32_t height; 1525 uint32_t height;
1526 uint32_t pixelDataLength; 1526 uint32_t pixelDataLength;
1527 if (!doReadUint32(&width)) 1527 if (!doReadUint32(&width))
1528 return false; 1528 return false;
1529 if (!doReadUint32(&height)) 1529 if (!doReadUint32(&height))
1530 return false; 1530 return false;
1531 if (!doReadUint32(&pixelDataLength)) 1531 if (!doReadUint32(&pixelDataLength))
1532 return false; 1532 return false;
1533 if (m_position + pixelDataLength > m_length) 1533 if (m_position + pixelDataLength > m_length)
1534 return false; 1534 return false;
1535 ImageData* imageData = ImageData::create(IntSize(width, height)); 1535 // TODO(junov): crbug.com/536816
1536 // Here we use a NonThorwableExceptionState in order to fail silently
1537 // when ImageData allocation fails. It needs to be ascertained whether
1538 // the call sites that depend on value deserialization agree with
1539 // re-throwing a RangeError exception from here, which is what happens
1540 // when the ArrayBuffer encapsulated in the ImageData fails to be
1541 // allocated, as per the ECMAScript spec:
1542 // http://ecma-international.org/ecma-262/6.0/#sec-createbytedatablock
1543 // Before we decide to propagate the exception down to the script
1544 // execution context, all the APIs that depend on this routine would
1545 // need to have specifications stating that exceptions thrown by sub
1546 // routines involved in the deserialization process are re-thrown.
1547 NonThrowableExceptionState exceptionState;
1548 ImageData* imageData = ImageData::create(IntSize(width, height), exceptionSt ate);
1549 if (exceptionState.hadException())
1550 return false;
1536 DOMUint8ClampedArray* pixelArray = imageData->data(); 1551 DOMUint8ClampedArray* pixelArray = imageData->data();
1537 ASSERT(pixelArray); 1552 ASSERT(pixelArray);
1538 ASSERT(pixelArray->length() >= pixelDataLength); 1553 ASSERT(pixelArray->length() >= pixelDataLength);
1539 memcpy(pixelArray->data(), m_buffer + m_position, pixelDataLength); 1554 memcpy(pixelArray->data(), m_buffer + m_position, pixelDataLength);
1540 m_position += pixelDataLength; 1555 m_position += pixelDataLength;
1541 *value = toV8(imageData, m_scriptState->context()->Global(), isolate()); 1556 *value = toV8(imageData, m_scriptState->context()->Global(), isolate());
1542 return !value->IsEmpty(); 1557 return !value->IsEmpty();
1543 } 1558 }
1544 1559
1545 bool SerializedScriptValueReader::readCompositorProxy(v8::Local<v8::Value>* valu e) 1560 bool SerializedScriptValueReader::readCompositorProxy(v8::Local<v8::Value>* valu e)
1546 { 1561 {
1547 uint32_t attributes; 1562 uint32_t attributes;
1548 uint64_t element; 1563 uint64_t element;
1549 if (!doReadUint64(&element)) 1564 if (!doReadUint64(&element))
1550 return false; 1565 return false;
1551 if (!doReadUint32(&attributes)) 1566 if (!doReadUint32(&attributes))
1552 return false; 1567 return false;
1553 1568
1554 CompositorProxy* compositorProxy = CompositorProxy::create(element, attribut es); 1569 CompositorProxy* compositorProxy = CompositorProxy::create(element, attribut es);
1555 *value = toV8(compositorProxy, m_scriptState->context()->Global(), isolate() ); 1570 *value = toV8(compositorProxy, m_scriptState->context()->Global(), isolate() );
1556 return !value->IsEmpty(); 1571 return !value->IsEmpty();
1557 } 1572 }
1558 1573
1559 PassRefPtr<DOMArrayBuffer> SerializedScriptValueReader::doReadArrayBuffer() 1574 PassRefPtr<DOMArrayBuffer> SerializedScriptValueReader::doReadArrayBufferOrNull( )
1560 { 1575 {
1561 uint32_t byteLength; 1576 uint32_t byteLength;
1562 if (!doReadUint32(&byteLength)) 1577 if (!doReadUint32(&byteLength))
1563 return nullptr; 1578 return nullptr;
1564 if (m_position + byteLength > m_length) 1579 if (m_position + byteLength > m_length)
1565 return nullptr; 1580 return nullptr;
1566 const void* bufferStart = m_buffer + m_position; 1581 const void* bufferStart = m_buffer + m_position;
1567 m_position += byteLength; 1582 m_position += byteLength;
1568 return DOMArrayBuffer::create(bufferStart, byteLength); 1583 return DOMArrayBuffer::createOrNull(bufferStart, byteLength);
1569 } 1584 }
1570 1585
1571 bool SerializedScriptValueReader::readArrayBuffer(v8::Local<v8::Value>* value) 1586 bool SerializedScriptValueReader::readArrayBuffer(v8::Local<v8::Value>* value)
1572 { 1587 {
1573 RefPtr<DOMArrayBuffer> arrayBuffer = doReadArrayBuffer(); 1588 RefPtr<DOMArrayBuffer> arrayBuffer = doReadArrayBufferOrNull();
1574 if (!arrayBuffer) 1589 // TODO(junov): crbug.com/536816 Instead of the following assert, we should consider doing:
1575 return false; 1590 // if (!arrayBuffer)
1591 // return false;
1592 // To do that, we need to make sure that call sites would react correctly
1593 // in this case, with the value not having been set.
1594 RELEASE_ASSERT(arrayBuffer); // This is essentially an out of memory crash
haraken 2015/10/29 18:58:37 You've added a bunch of RELEASE_ASSERT(arrayBuffer
Justin Novosad 2015/11/05 00:17:51 Done. Turns out that I made a mistake about this c
1576 *value = toV8(arrayBuffer.release(), m_scriptState->context()->Global(), iso late()); 1595 *value = toV8(arrayBuffer.release(), m_scriptState->context()->Global(), iso late());
1577 return !value->IsEmpty(); 1596 return !value->IsEmpty();
1578 } 1597 }
1579 1598
1580 bool SerializedScriptValueReader::readArrayBufferView(v8::Local<v8::Value>* valu e, ScriptValueCompositeCreator& creator) 1599 bool SerializedScriptValueReader::readArrayBufferView(v8::Local<v8::Value>* valu e, ScriptValueCompositeCreator& creator)
1581 { 1600 {
1582 ArrayBufferViewSubTag subTag; 1601 ArrayBufferViewSubTag subTag;
1583 uint32_t byteOffset; 1602 uint32_t byteOffset;
1584 uint32_t byteLength; 1603 uint32_t byteLength;
1585 RefPtr<DOMArrayBufferBase> arrayBuffer; 1604 RefPtr<DOMArrayBufferBase> arrayBuffer;
(...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after
2157 return false; 2176 return false;
2158 uint32_t objectReference = m_openCompositeReferenceStack[m_openCompositeRefe renceStack.size() - 1]; 2177 uint32_t objectReference = m_openCompositeReferenceStack[m_openCompositeRefe renceStack.size() - 1];
2159 m_openCompositeReferenceStack.shrink(m_openCompositeReferenceStack.size() - 1); 2178 m_openCompositeReferenceStack.shrink(m_openCompositeReferenceStack.size() - 1);
2160 if (objectReference >= m_objectPool.size()) 2179 if (objectReference >= m_objectPool.size())
2161 return false; 2180 return false;
2162 *object = m_objectPool[objectReference]; 2181 *object = m_objectPool[objectReference];
2163 return true; 2182 return true;
2164 } 2183 }
2165 2184
2166 } // namespace blink 2185 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698