[JSC] SerializedScriptValue::create() should throw a DataCloneError if input is an unsupported object
https://bugs.webkit.org/show_bug.cgi?id=94493

Patch by Christophe Dumez <christophe.dumez@intel.com> on 2012-08-20
Reviewed by Oliver Hunt.

Source/WebCore:

Update JSC implementation for SerializedScriptValue::create() so that
a DataCloneError is thrown when the input value is an unsupported
object. The previous implementation was not throwing any error.

This change is according to the structured clone specification at:
http://www.w3.org/TR/html5/common-dom-interfaces.html#structured-clone

This also matches the corresponding V8 implementation.

Test: fast/events/message-port-multi.html.

* bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneSerializer::dumpIfTerminal):
(WebCore::CloneSerializer::serialize):
(WebCore::SerializedScriptValue::maybeThrowExceptionIfSerializationFailed):
* bindings/js/SerializedScriptValue.h:

LayoutTests:

Add checks for Function, Error and host objects arguments to
MessagePort.postMessage() in fast/events/message-port-multi.html.

According to the structured clone specification, we should throw
a DataCloneError for such input types.

* fast/dom/Window/anonymous-slot-with-changes-expected.txt:
* fast/dom/Window/anonymous-slot-with-changes.html: Update test to expect
an exception when passing a function to postMessage().
* fast/events/message-port-multi-expected.txt: Update expected result
accordingly.
* fast/events/resources/message-port-multi.js:
(testTransfers.try.f1):
* platform/chromium/fast/events/message-port-multi-expected.txt: Removed.
Now identical to global expectation.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@126067 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/bindings/js/SerializedScriptValue.cpp b/Source/WebCore/bindings/js/SerializedScriptValue.cpp
index 2b47d4b..9d5ca65 100644
--- a/Source/WebCore/bindings/js/SerializedScriptValue.cpp
+++ b/Source/WebCore/bindings/js/SerializedScriptValue.cpp
@@ -582,13 +582,6 @@
 
         if (isArray(value))
             return false;
-           
-        // Object cannot be serialized because the act of walking the object creates new objects
-        if (value.isObject() && asObject(value)->inherits(&JSNavigator::s_info)) {
-            fail();
-            write(NullTag);
-            return true; 
-        }
 
         if (value.isObject()) {
             JSObject* obj = asObject(value);
@@ -677,9 +670,7 @@
                 return success;
             }
 
-            CallData unusedData;
-            if (getCallData(value, unusedData) == CallTypeNone)
-                return false;
+            return false;
         }
         // Any other types are expected to serialize as null.
         write(NullTag);
@@ -898,6 +889,12 @@
                 JSObject* inObject = asObject(inValue);
                 if (!startObject(inObject))
                     break;
+                // At this point, all supported objects other than Object
+                // objects have been handled. If we reach this point and
+                // the input is not an Object object then we should throw
+                // a DataCloneError.
+                if (inObject->classInfo() != &JSFinalObject::s_info)
+                    return DataCloneError;
                 inputObjectStack.append(inObject);
                 indexStack.append(0);
                 propertyStack.append(PropertyNameArray(m_exec));
@@ -1920,6 +1917,9 @@
     case ValidationError:
         throwError(exec, createTypeError(exec, "Unable to deserialize data."));
         break;
+    case DataCloneError:
+        setDOMException(exec, DATA_CLONE_ERR);
+        break;
     case ExistingExceptionError:
         break;
     case UnspecifiedError: