Diff
Modified: trunk/LayoutTests/ChangeLog (91958 => 91959)
--- trunk/LayoutTests/ChangeLog 2011-07-28 23:43:18 UTC (rev 91958)
+++ trunk/LayoutTests/ChangeLog 2011-07-28 23:56:27 UTC (rev 91959)
@@ -1,3 +1,22 @@
+2011-07-28 Luke Zarko <[email protected]>
+
+ V8 should correctly serialize Boolean, Number and String objects.
+
+ https://bugs.webkit.org/show_bug.cgi?id=65286
+
+ Reviewed by David Levin.
+
+ - Check that Boolean, Number and String objects are correctly serialized.
+ - Check that a native error is not serialized.
+ - Fix an expectation that a native error can be serialized.
+
+ * fast/dom/Window/script-tests/postmessage-clone.js:
+ * fast/dom/Window/script-tests/postmessage-test.js:
+ * fast/dom/Window/window-postmessage-clone-expected.txt:
+ * fast/loader/stateobjects/pushstate-object-types-expected.txt:
+ * fast/loader/stateobjects/pushstate-object-types.html:
+ * platform/chromium/fast/dom/Window/window-postmessage-clone-expected.txt:
+
2011-07-28 Adam Barth <[email protected]>
Old code about empty security origins could use a bath
Modified: trunk/LayoutTests/fast/dom/Window/script-tests/postmessage-clone.js (91958 => 91959)
--- trunk/LayoutTests/fast/dom/Window/script-tests/postmessage-clone.js 2011-07-28 23:43:18 UTC (rev 91958)
+++ trunk/LayoutTests/fast/dom/Window/script-tests/postmessage-clone.js 2011-07-28 23:56:27 UTC (rev 91959)
@@ -20,8 +20,13 @@
tryPostMessage('[1,2,3]');
tryPostMessage('[,,1]');
tryPostMessage('(function(){})', true, null, DOMException.DATA_CLONE_ERR);
+tryPostMessage('var x = 0; try { eval("badref"); } catch(e) { x = e; } x', true, null, DOMException.DATA_CLONE_ERR);
tryPostMessage('new Date(1234567890000)');
tryPostMessage('new ConstructorWithPrototype("foo")', false, '({field:"foo"})');
+tryPostMessage('new Boolean(true)');
+tryPostMessage('new Boolean(false)');
+tryPostMessage('new String("gnirts")');
+tryPostMessage('new Number(42.0)');
cyclicObject={};
cyclicObject.self = cyclicObject;
tryPostMessage('cyclicObject', false, "cyclicObject");
@@ -210,6 +215,61 @@
doPassFail(window.bcalled === undefined, "window.bcalled === undefined");
});
+// Reference equality between Boolean objects must be maintained.
+tryPostMessage(thunk(
+ 'var t1 = new Boolean(true); ' +
+ 'var t2 = new Boolean(true); ' +
+ 'var f1 = new Boolean(false); ' +
+ 'var f2 = new Boolean(false); ' +
+ 'return [t1, t1, t2, f1, f1, f2];'
+ ), false, "evalThunk", function(v) {
+ doPassFail(equal(v[0], new Boolean(true)), "Boolean values correct (0)");
+ doPassFail(equal(v[3], new Boolean(false)), "Boolean values correct (3)");
+ doPassFail(equal(v[1], v[2]), "Boolean values correct (1,2)");
+ doPassFail(equal(v[4], v[5]), "Boolean values correct (4,5)");
+ doPassFail(v[0] === v[1], "References to Booleans correct (0,1)");
+ doPassFail(v[3] === v[4], "References to Booleans correct (3,4)");
+ doPassFail(v[0] !== v[2], "References to Booleans correct (0,2)");
+ doPassFail(v[3] !== v[5], "References to Booleans correct (3,5)");
+ });
+
+// Reference equality between Number objects must be maintained.
+tryPostMessage(thunk(
+ 'var n1 = new Number(42.0); ' +
+ 'var n2 = new Number(42.0); ' +
+ 'return [n1, n1, n2];'
+ ), false, "evalThunk", function(v) {
+ doPassFail(equal(v[0], new Number(42.0)), "Number values correct (0)");
+ doPassFail(equal(v[0], v[2]), "Number values correct (0,2)");
+ doPassFail(v[0] === v[1], "References to numbers correct (0,1)");
+ doPassFail(v[0] !== v[2], "References to numbers correct (0,2)");
+ });
+
+// Reference equality between String objects must be maintained.
+tryPostMessage(thunk(
+ 'var s1 = new String("gnirts"); ' +
+ 'var s2 = new String("gnirts"); ' +
+ 'return [s1, s1, s2];'
+ ), false, "evalThunk", function(v) {
+ doPassFail(equal(v[0], new String("gnirts")), "String values correct (0)");
+ doPassFail(equal(v[0], v[2]), "String values correct (0,2)");
+ doPassFail(v[0] === v[1], "References to strings correct (0,1)");
+ doPassFail(v[0] !== v[2], "References to strings correct (0,2)");
+ });
+
+// Properties added to String, Boolean and Number objects should not be serialized.
+tryPostMessage(thunk(
+ 'var s = new String("gnirts"); ' +
+ 'var n = new Number(42.0); ' +
+ 'var b = new Boolean(true); ' +
+ 's.foo = 1; n.foo = 2; b.foo = 3; ' +
+ 'return [s, n, b];'
+ ), false, "evalThunk", function(v) {
+ doPassFail(v[0].foo == undefined, "String object properties not serialized");
+ doPassFail(v[1].foo == undefined, "Number object properties not serialized");
+ doPassFail(v[2].foo == undefined, "Boolean object properties not serialized");
+ });
+
// Reference equality between dates must be maintained.
tryPostMessage(thunk(
'var d1 = new Date(1,2,3); ' +
Modified: trunk/LayoutTests/fast/dom/Window/script-tests/postmessage-test.js (91958 => 91959)
--- trunk/LayoutTests/fast/dom/Window/script-tests/postmessage-test.js 2011-07-28 23:43:18 UTC (rev 91958)
+++ trunk/LayoutTests/fast/dom/Window/script-tests/postmessage-test.js 2011-07-28 23:56:27 UTC (rev 91959)
@@ -19,6 +19,18 @@
return (expected instanceof Date) && actual.getTime() == expected.getTime();
return false;
}
+ if ((actual instanceof Number) || (expected instanceof Number)) {
+ return (actual instanceof Number) && (expected instanceof Number) &&
+ (expected.valueOf() == actual.valueOf());
+ }
+ if ((actual instanceof Boolean) || (expected instanceof Boolean)) {
+ return (actual instanceof Boolean) && (expected instanceof Boolean) &&
+ (expected.valueOf() == actual.valueOf());
+ }
+ if ((actual instanceof String) || (expected instanceof String)) {
+ return (actual instanceof String) && (expected instanceof String) &&
+ (expected.valueOf() == actual.valueOf());
+ }
if (Array.isArray(actual) || Array.isArray(expected)) {
if (!Array.isArray(actual) || !Array.isArray(expected))
return false;
Modified: trunk/LayoutTests/fast/dom/Window/window-postmessage-clone-expected.txt (91958 => 91959)
--- trunk/LayoutTests/fast/dom/Window/window-postmessage-clone-expected.txt 2011-07-28 23:43:18 UTC (rev 91958)
+++ trunk/LayoutTests/fast/dom/Window/window-postmessage-clone-expected.txt 2011-07-28 23:56:27 UTC (rev 91959)
@@ -1,8 +1,9 @@
-CONSOLE MESSAGE: line 74: TypeError: No default value
-CONSOLE MESSAGE: line 74: TypeError: No default value
+CONSOLE MESSAGE: line 86: TypeError: No default value
+CONSOLE MESSAGE: line 86: TypeError: No default value
Tests that we clone object hierarchies
FAIL: 'postMessage((function(){}))' should throw but didn't
+FAIL: 'postMessage(var x = 0; try { eval("badref"); } catch(e) { x = e; } x)' should throw but didn't
PASS: 'postMessage(window)' threw TypeError: Type error
PASS: 'postMessage(({get a() { throw "x" }}))' threw x
FAIL: 'postMessage(imageData.data)' should throw but didn't
@@ -31,8 +32,13 @@
PASS: eventData is 1,2,3 of type object
PASS: eventData is ,,1 of type object
FAIL: eventData is null should be function () {} of type function
+FAIL: eventData is [object Object] should be ReferenceError: Can't find variable: badref of type object
PASS: eventData is 2009-02-13T23:31:30.000Z of type object
PASS: eventData is [object Object] of type object
+FAIL: eventData is [object Object] should be true of type object
+FAIL: eventData is [object Object] should be false of type object
+FAIL: eventData is [object Object] should be gnirts of type object
+FAIL: eventData is [object Object] should be 42 of type object
PASS: eventData is === to eventData.self
PASS: eventData is === to eventData[0]
PASS: eventData.graph1 is === to eventData.graph2
@@ -86,6 +92,25 @@
PASS: window.pcalled === true
PASS: window.acalled === true
FAIL: window.bcalled === undefined
+FAIL: Boolean values correct (0)
+FAIL: Boolean values correct (3)
+PASS: Boolean values correct (1,2)
+PASS: Boolean values correct (4,5)
+PASS: References to Booleans correct (0,1)
+PASS: References to Booleans correct (3,4)
+PASS: References to Booleans correct (0,2)
+PASS: References to Booleans correct (3,5)
+FAIL: Number values correct (0)
+PASS: Number values correct (0,2)
+PASS: References to numbers correct (0,1)
+PASS: References to numbers correct (0,2)
+FAIL: String values correct (0)
+PASS: String values correct (0,2)
+PASS: References to strings correct (0,1)
+PASS: References to strings correct (0,2)
+FAIL: String object properties not serialized
+FAIL: Number object properties not serialized
+FAIL: Boolean object properties not serialized
PASS: Date values correct (0)
PASS: Date values correct (1)
FAIL: References to dates correct (0)
Modified: trunk/LayoutTests/fast/loader/stateobjects/pushstate-object-types-expected.txt (91958 => 91959)
--- trunk/LayoutTests/fast/loader/stateobjects/pushstate-object-types-expected.txt 2011-07-28 23:43:18 UTC (rev 91958)
+++ trunk/LayoutTests/fast/loader/stateobjects/pushstate-object-types-expected.txt 2011-07-28 23:56:27 UTC (rev 91959)
@@ -2,7 +2,6 @@
State popped - [object ImageData] (type object)
State popped - [object Object] (type object)
-State popped - [object Object] (type object)
State popped - (type object)
State popped - /foo/gi (type object)
State popped - 0 (type object)
Modified: trunk/LayoutTests/fast/loader/stateobjects/pushstate-object-types.html (91958 => 91959)
--- trunk/LayoutTests/fast/loader/stateobjects/pushstate-object-types.html 2011-07-28 23:43:18 UTC (rev 91958)
+++ trunk/LayoutTests/fast/loader/stateobjects/pushstate-object-types.html 2011-07-28 23:56:27 UTC (rev 91959)
@@ -27,7 +27,6 @@
history.pushState(new RegExp("foo", "gi"), "RegExp entry");
history.pushState(new Array, "Array entry");
history.pushState(new Object, "Object entry");
- history.pushState(new Error, "Error entry");
history.pushState(document.createElement("canvas").getContext("2d").createImageData(10,10), "ImageData entry");
/* The following are not yet well enough supported in WebKit to meaningfully test here:
Modified: trunk/LayoutTests/platform/chromium/fast/dom/Window/window-postmessage-clone-expected.txt (91958 => 91959)
--- trunk/LayoutTests/platform/chromium/fast/dom/Window/window-postmessage-clone-expected.txt 2011-07-28 23:43:18 UTC (rev 91958)
+++ trunk/LayoutTests/platform/chromium/fast/dom/Window/window-postmessage-clone-expected.txt 2011-07-28 23:56:27 UTC (rev 91959)
@@ -1,6 +1,7 @@
Tests that we clone object hierarchies
PASS: 'postMessage((function(){}))' threw Error: DATA_CLONE_ERR: DOM Exception 25
+PASS: 'postMessage(var x = 0; try { eval("badref"); } catch(e) { x = e; } x)' threw Error: DATA_CLONE_ERR: DOM Exception 25
PASS: 'postMessage(window)' threw Error: DATA_CLONE_ERR: DOM Exception 25
PASS: 'postMessage(({get a() { throw "x" }}))' threw x
PASS: 'postMessage(imageData.data)' threw Error: DATA_CLONE_ERR: DOM Exception 25
@@ -30,6 +31,10 @@
PASS: eventData is ,,1 of type object
PASS: eventData is 2009-02-13T23:31:30.000Z of type object
PASS: eventData is [object Object] of type object
+PASS: eventData is true of type object
+PASS: eventData is false of type object
+PASS: eventData is gnirts of type object
+PASS: eventData is 42 of type object
PASS: eventData is === to eventData.self
PASS: eventData is === to eventData[0]
PASS: eventData.graph1 is === to eventData.graph2
@@ -83,6 +88,25 @@
PASS: window.pcalled === true
PASS: window.acalled === true
PASS: window.bcalled === undefined
+PASS: Boolean values correct (0)
+PASS: Boolean values correct (3)
+PASS: Boolean values correct (1,2)
+PASS: Boolean values correct (4,5)
+PASS: References to Booleans correct (0,1)
+PASS: References to Booleans correct (3,4)
+PASS: References to Booleans correct (0,2)
+PASS: References to Booleans correct (3,5)
+PASS: Number values correct (0)
+PASS: Number values correct (0,2)
+PASS: References to numbers correct (0,1)
+PASS: References to numbers correct (0,2)
+PASS: String values correct (0)
+PASS: String values correct (0,2)
+PASS: References to strings correct (0,1)
+PASS: References to strings correct (0,2)
+PASS: String object properties not serialized
+PASS: Number object properties not serialized
+PASS: Boolean object properties not serialized
PASS: Date values correct (0)
PASS: Date values correct (1)
PASS: References to dates correct (0)
Modified: trunk/Source/WebCore/ChangeLog (91958 => 91959)
--- trunk/Source/WebCore/ChangeLog 2011-07-28 23:43:18 UTC (rev 91958)
+++ trunk/Source/WebCore/ChangeLog 2011-07-28 23:56:27 UTC (rev 91959)
@@ -1,3 +1,35 @@
+2011-07-28 Luke Zarko <[email protected]>
+
+ V8 should correctly serialize Boolean, Number and String objects.
+
+ https://bugs.webkit.org/show_bug.cgi?id=65286
+
+ Reviewed by David Levin.
+
+ New APIs were exposed to allow V8 to correctly serialize Boolean, Number and String objects, as well as detect certain native errors as required by the HTML5 Structured Clone algorithm (http://www.whatwg.org/specs/web-apps/current-work/multipage/urls.html#safe-passing-of-structured-data). SerializedScriptValue should make use of these APIs.
+
+ - Checks for and serializes Boolean, Number and String objects.
+ - Checks for native errors and aborts should a script attempt to serialize them.
+ - Small name change to clear up the code: m_objectReferenceStack => m_openCompositeReferenceStack
+
+ Tests: fast/dom/Window/window-postmessage-clone.html
+ fast/loader/stateobjects/pushstate-object-types.html
+
+ * bindings/v8/SerializedScriptValue.cpp:
+ (WebCore::V8ObjectMap::Writer::writeBooleanObject):
+ (WebCore::V8ObjectMap::Writer::writeStringObject):
+ (WebCore::V8ObjectMap::Writer::writeNumberObject):
+ (WebCore::V8ObjectMap::Serializer::writeStringObject):
+ (WebCore::V8ObjectMap::Serializer::writeNumberObject):
+ (WebCore::V8ObjectMap::Serializer::writeBooleanObject):
+ (WebCore::V8ObjectMap::Serializer::doSerialize):
+ (WebCore::V8ObjectMap::Reader::read):
+ (WebCore::V8ObjectMap::Reader::readStringObject):
+ (WebCore::V8ObjectMap::Reader::readNumberObject):
+ (WebCore::V8ObjectMap::Deserializer::deserialize):
+ (WebCore::V8ObjectMap::Deserializer::openComposite):
+ (WebCore::V8ObjectMap::Deserializer::closeComposite):
+
2011-07-28 Adam Barth <[email protected]>
Old code about empty security origins could use a bath
Modified: trunk/Source/WebCore/bindings/v8/SerializedScriptValue.cpp (91958 => 91959)
--- trunk/Source/WebCore/bindings/v8/SerializedScriptValue.cpp 2011-07-28 23:43:18 UTC (rev 91958)
+++ trunk/Source/WebCore/bindings/v8/SerializedScriptValue.cpp 2011-07-28 23:56:27 UTC (rev 91959)
@@ -199,6 +199,10 @@
GenerateFreshObjectTag = 'o', // -> empty object allocated an object ID and pushed onto the open stack (ref)
GenerateFreshArrayTag = 'a', // length:uint32_t -> empty array[length] allocated an object ID and pushed onto the open stack (ref)
ReferenceCountTag = '?', // refTableSize:uint32_t -> If the reference table is not refTableSize big, fails.
+ StringObjectTag = 's', // string:RawString -> new String(string) (ref)
+ NumberObjectTag = 'n', // value:double -> new Number(value) (ref)
+ TrueObjectTag = 'y', // new Boolean(true) (ref)
+ FalseObjectTag = 'x', // new Boolean(false) (ref)
VersionTag = 0xFF // version:uint32_t -> Uses this as the file version.
};
@@ -278,6 +282,11 @@
void writeFalse() { append(FalseTag); }
+ void writeBooleanObject(bool value)
+ {
+ append(value ? TrueObjectTag : FalseObjectTag);
+ }
+
void writeString(const char* data, int length)
{
ASSERT(length >= 0);
@@ -285,6 +294,13 @@
doWriteString(data, length);
}
+ void writeStringObject(const char* data, int length)
+ {
+ ASSERT(length >= 0);
+ append(StringObjectTag);
+ doWriteString(data, length);
+ }
+
void writeWebCoreString(const String& string)
{
// Uses UTF8 encoding so we can read it back as either V8 or
@@ -323,6 +339,12 @@
doWriteNumber(number);
}
+ void writeNumberObject(double number)
+ {
+ append(NumberObjectTag);
+ doWriteNumber(number);
+ }
+
void writeBlob(const String& url, const String& type, unsigned long long size)
{
append(BlobTag);
@@ -868,6 +890,25 @@
m_writer.writeString(*stringValue, stringValue.length());
}
+ void writeStringObject(v8::Handle<v8::Value> value)
+ {
+ v8::Handle<v8::StringObject> stringObject = value.As<v8::StringObject>();
+ v8::String::Utf8Value stringValue(stringObject->StringValue());
+ m_writer.writeStringObject(*stringValue, stringValue.length());
+ }
+
+ void writeNumberObject(v8::Handle<v8::Value> value)
+ {
+ v8::Handle<v8::NumberObject> numberObject = value.As<v8::NumberObject>();
+ m_writer.writeNumberObject(numberObject->NumberValue());
+ }
+
+ void writeBooleanObject(v8::Handle<v8::Value> value)
+ {
+ v8::Handle<v8::BooleanObject> booleanObject = value.As<v8::BooleanObject>();
+ m_writer.writeBooleanObject(booleanObject->BooleanValue());
+ }
+
void writeBlob(v8::Handle<v8::Value> value)
{
Blob* blob = V8Blob::toNative(value.As<v8::Object>());
@@ -1013,6 +1054,12 @@
greyObject(jsObject);
if (value->IsDate())
m_writer.writeDate(value->NumberValue());
+ else if (value->IsStringObject())
+ writeStringObject(value);
+ else if (value->IsNumberObject())
+ writeNumberObject(value);
+ else if (value->IsBooleanObject())
+ writeBooleanObject(value);
else if (value->IsArray()) {
m_writer.writeGenerateFreshArray(value.As<v8::Array>()->Length());
return push(newArrayState(value.As<v8::Array>(), next));
@@ -1029,8 +1076,7 @@
else if (V8ArrayBuffer::HasInstance(value))
writeArrayBuffer(value);
else if (value->IsObject()) {
- // FIXME: We need to check if jsObject is a 'native Error' and if so throw a DataCloneError.
- if (isHostObject(jsObject) || jsObject->IsCallable())
+ if (isHostObject(jsObject) || jsObject->IsCallable() || value->IsNativeError())
return handleError(DataCloneError, next);
m_writer.writeGenerateFreshObject();
return push(newObjectState(jsObject, next));
@@ -1106,10 +1152,23 @@
case FalseTag:
*value = v8::False();
break;
+ case TrueObjectTag:
+ *value = v8::BooleanObject::New(true);
+ creator.pushObjectReference(*value);
+ break;
+ case FalseObjectTag:
+ *value = v8::BooleanObject::New(false);
+ creator.pushObjectReference(*value);
+ break;
case StringTag:
if (!readString(value))
return false;
break;
+ case StringObjectTag:
+ if (!readStringObject(value))
+ return false;
+ creator.pushObjectReference(*value);
+ break;
case Int32Tag:
if (!readInt32(value))
return false;
@@ -1127,6 +1186,11 @@
if (!readNumber(value))
return false;
break;
+ case NumberObjectTag:
+ if (!readNumberObject(value))
+ return false;
+ creator.pushObjectReference(*value);
+ break;
case BlobTag:
if (!readBlob(value))
return false;
@@ -1287,6 +1351,15 @@
return true;
}
+ bool readStringObject(v8::Handle<v8::Value>* value)
+ {
+ v8::Handle<v8::Value> stringValue;
+ if (!readString(&stringValue) || !stringValue->IsString())
+ return false;
+ *value = v8::StringObject::New(stringValue.As<v8::String>());
+ return true;
+ }
+
bool readWebCoreString(String* string)
{
uint32_t length;
@@ -1334,6 +1407,15 @@
*value = v8::Number::New(number);
return true;
}
+
+ bool readNumberObject(v8::Handle<v8::Value>* value)
+ {
+ double number;
+ if (!doReadNumber(&number))
+ return false;
+ *value = v8::NumberObject::New(number);
+ return true;
+ }
bool readImageData(v8::Handle<v8::Value>* value)
{
@@ -1585,7 +1667,7 @@
if (!doDeserialize())
return v8::Null();
}
- if (stackDepth() != 1 || m_objectReferenceStack.size())
+ if (stackDepth() != 1 || m_openCompositeReferenceStack.size())
return v8::Null();
v8::Handle<v8::Value> result = scope.Close(element(0));
return result;
@@ -1734,16 +1816,16 @@
void openComposite(const v8::Local<v8::Value>& object)
{
uint32_t newObjectReference = m_objectPool.size();
- m_objectReferenceStack.append(newObjectReference);
+ m_openCompositeReferenceStack.append(newObjectReference);
m_objectPool.append(object);
}
bool closeComposite(v8::Handle<v8::Value>* object)
{
- if (!m_objectReferenceStack.size())
+ if (!m_openCompositeReferenceStack.size())
return false;
- uint32_t objectReference = m_objectReferenceStack[m_objectReferenceStack.size() - 1];
- m_objectReferenceStack.shrink(m_objectReferenceStack.size() - 1);
+ uint32_t objectReference = m_openCompositeReferenceStack[m_openCompositeReferenceStack.size() - 1];
+ m_openCompositeReferenceStack.shrink(m_openCompositeReferenceStack.size() - 1);
if (objectReference >= m_objectPool.size())
return false;
*object = m_objectPool[objectReference];
@@ -1753,7 +1835,7 @@
Reader& m_reader;
Vector<v8::Local<v8::Value> > m_stack;
Vector<v8::Handle<v8::Value> > m_objectPool;
- Vector<uint32_t> m_objectReferenceStack;
+ Vector<uint32_t> m_openCompositeReferenceStack;
uint32_t m_version;
};