diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 9be9bd8c1216..b81923f9d46d 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -3447,6 +3447,7 @@ static bool Deserialize(JSContext* cx, unsigned argc, Value* vp) { Rooted obj(cx, &args[0].toObject().as()); + JS::CloneDataPolicy policy; JS::StructuredCloneScope scope = obj->isSynthetic() ? JS::StructuredCloneScope::DifferentProcess : JS::StructuredCloneScope::SameProcessSameThread; @@ -3457,6 +3458,30 @@ static bool Deserialize(JSContext* cx, unsigned argc, Value* vp) { } RootedValue v(cx); + if (!JS_GetProperty(cx, opts, "SharedArrayBuffer", &v)) { + return false; + } + + if (!v.isUndefined()) { + JSString* str = JS::ToString(cx, v); + if (!str) { + return false; + } + JSLinearString* poli = str->ensureLinear(cx); + if (!poli) { + return false; + } + + if (StringEqualsLiteral(poli, "allow")) { + policy.allowSharedMemory(); + } else if (StringEqualsLiteral(poli, "deny")) { + // default + } else { + JS_ReportErrorASCII(cx, "Invalid policy value for 'SharedArrayBuffer'"); + return false; + } + } + if (!JS_GetProperty(cx, opts, "scope", &v)) { return false; } @@ -3498,8 +3523,7 @@ static bool Deserialize(JSContext* cx, unsigned argc, Value* vp) { RootedValue deserialized(cx); if (!JS_ReadStructuredClone(cx, *obj->data(), JS_STRUCTURED_CLONE_VERSION, - scope, &deserialized, JS::CloneDataPolicy(), - nullptr, nullptr)) { + scope, &deserialized, policy, nullptr, nullptr)) { return false; } args.rval().set(deserialized); @@ -6673,8 +6697,11 @@ gc::ZealModeHelpText), JS_FN_HELP("deserialize", Deserialize, 1, 0, "deserialize(clonebuffer[, opts])", -" Deserialize data generated by serialize. 'opts' is an options hash with one\n" -" recognized key 'scope', which limits the clone buffers that are considered\n" +" Deserialize data generated by serialize. 'opts' may be an options hash.\n" +" Valid keys:\n" +" 'SharedArrayBuffer' - either 'allow' or 'deny' (the default)\n" +" to specify whether SharedArrayBuffers may be serialized.\n" +" 'scope', which limits the clone buffers that are considered\n" " valid. Allowed values: 'SameProcessSameThread', 'SameProcessDifferentThread',\n" " 'DifferentProcess', and 'DifferentProcessForIndexedDB'. So for example, a\n" " DifferentProcessForIndexedDB clone buffer may be deserialized in any scope, but\n" diff --git a/js/src/jit-test/tests/wasm/memory-cloning.js b/js/src/jit-test/tests/wasm/memory-cloning.js index 76306caee449..261a0d256e22 100644 --- a/js/src/jit-test/tests/wasm/memory-cloning.js +++ b/js/src/jit-test/tests/wasm/memory-cloning.js @@ -24,7 +24,7 @@ // Serialization and deserialization of shared memories work: - let mem2 = deserialize(serialize(mem1, [], {SharedArrayBuffer: 'allow'})); + let mem2 = deserialize(serialize(mem1, [], {SharedArrayBuffer: 'allow'}), {SharedArrayBuffer: 'allow'}); assertEq(mem2 instanceof WebAssembly.Memory, true); let buf2 = mem2.buffer; assertEq(buf2 instanceof SharedArrayBuffer, true); @@ -81,6 +81,6 @@ let buf = mem.buffer; let clonedbuf = serialize(buf, [], {SharedArrayBuffer: 'allow'}); mem.grow(1); - let buf2 = deserialize(clonedbuf); + let buf2 = deserialize(clonedbuf, {SharedArrayBuffer: 'allow'}); assertEq(buf.byteLength, buf2.byteLength); } diff --git a/js/src/tests/non262/extensions/clone-sab.js b/js/src/tests/non262/extensions/clone-sab.js index 197d140984f5..3b35f90abc8e 100644 --- a/js/src/tests/non262/extensions/clone-sab.js +++ b/js/src/tests/non262/extensions/clone-sab.js @@ -22,7 +22,7 @@ x = null; // deserialization because the memory has become unmapped. for (let i=0 ; i < 50 ; i++ ) { - let obj = deserialize(y); + let obj = deserialize(y, {SharedArrayBuffer: 'allow'}); let z = new Int8Array(obj); z[0] = 0; } diff --git a/js/src/tests/non262/extensions/sharedtypedarray.js b/js/src/tests/non262/extensions/sharedtypedarray.js index 09b4dba2aaee..56187d29f5cc 100644 --- a/js/src/tests/non262/extensions/sharedtypedarray.js +++ b/js/src/tests/non262/extensions/sharedtypedarray.js @@ -170,7 +170,7 @@ function testSharedTypedArrayMethods() { function testClone1() { var sab1 = b; var blob = serialize(sab1, [], {SharedArrayBuffer: 'allow'}); - var sab2 = deserialize(blob); + var sab2 = deserialize(blob, {SharedArrayBuffer: 'allow'}); if (typeof sharedAddress != "undefined") assertEq(sharedAddress(sab1), sharedAddress(sab2)); } @@ -179,7 +179,7 @@ function testClone2() { var sab = b; var ia1 = new Int32Array(sab); var blob = serialize(ia1, [], {SharedArrayBuffer: 'allow'}); - var ia2 = deserialize(blob); + var ia2 = deserialize(blob, {SharedArrayBuffer: 'allow'}); assertEq(ia1.length, ia2.length); assertEq(ia1.buffer instanceof SharedArrayBuffer, true); if (typeof sharedAddress != "undefined") @@ -203,6 +203,19 @@ function testNoClone() { // Ditto - should succeed assertEq(typeof serialize(b, [], {SharedArrayBuffer: 'allow'}), "object"); + + let blob = serialize(b, [], {SharedArrayBuffer: 'allow'}); + // This just tests the API in deserialize() + assertThrowsInstanceOf(() => deserialize(blob, {SharedArrayBuffer: false}), Error); + + // This tests the actual cloning functionality - should fail + assertThrowsInstanceOf(() => deserialize(blob, {SharedArrayBuffer: 'deny'}), TypeError); + + // This tests that cloning a SharedArrayBuffer is not allowed by default + assertThrowsInstanceOf(() => deserialize(blob), TypeError); + + // Ditto - should succeed + assertEq(typeof deserialize(blob, {SharedArrayBuffer: 'allow'}), "object"); } function testRedundantTransfer() {