Bug 1624266 - Allow the SharedArrayBuffer global constructor property to be optionally omitted from a new global object. r=arai,baku
authorJeff Walden <jwalden@mit.edu>
Fri, 17 Apr 2020 08:20:45 +0000
changeset 524564 7258f2cac07e89a245996fb3054f28cd3cbf28f7
parent 524563 4255bd054e34fcaf2a5e5d2c9b1dba9f2fe4e2d8
child 524565 e1d33e7f9caee671ac40b60cfd0621181fb8f04c
push id37323
push userdluca@mozilla.com
push dateFri, 17 Apr 2020 16:25:55 +0000
treeherdermozilla-central@b4b1d6f91ef0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai, baku
bugs1624266
milestone77.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1624266 - Allow the SharedArrayBuffer global constructor property to be optionally omitted from a new global object. r=arai,baku Differential Revision: https://phabricator.services.mozilla.com/D70990
js/public/RealmOptions.h
js/src/shell/js.cpp
js/src/vm/GlobalObject.cpp
--- a/js/public/RealmOptions.h
+++ b/js/public/RealmOptions.h
@@ -120,25 +120,66 @@ class JS_PUBLIC_API RealmCreationOptions
   }
 
   bool cloneSingletons() const { return cloneSingletons_; }
   RealmCreationOptions& setCloneSingletons(bool flag) {
     cloneSingletons_ = flag;
     return *this;
   }
 
+  // Determines whether 1) the global Atomic property is defined and atomic
+  // operations are supported, and 2) whether shared-memory operations are
+  // supported.
   bool getSharedMemoryAndAtomicsEnabled() const;
   RealmCreationOptions& setSharedMemoryAndAtomicsEnabled(bool flag);
 
-  // When these prefs (COOP and COEP) are not enabled, shared memory objects
-  // (e.g. SAB) are not allowed to be postMessage()'ed. And we want to provide
-  // a clear warning message to users/developer so that they would have an idea
-  // if the implementations of the COOP and COEP headers are finished or not. So
-  // that they would know if they can fix the SAB by deploying the COOP and
-  // COEP headers or not.
+  // Determines (if getSharedMemoryAndAtomicsEnabled() is true) whether the
+  // global SharedArrayBuffer property is defined.  If the property is not
+  // defined, shared array buffer functionality can only be invoked if the
+  // host/embedding specifically acts to expose it.
+  //
+  // This option defaults to true: embeddings unable to tolerate a global
+  // SharedAraryBuffer property must opt out of it.
+  bool defineSharedArrayBufferConstructor() const {
+    return defineSharedArrayBufferConstructor_;
+  }
+  RealmCreationOptions& setDefineSharedArrayBufferConstructor(bool flag) {
+    defineSharedArrayBufferConstructor_ = flag;
+    return *this;
+  }
+
+  // Structured clone operations support the cloning of shared memory objects
+  // (SharedArrayBuffer or or a shared WASM Memory object) *optionally* -- at
+  // the discretion of the embedder code that performs the cloning.  When a
+  // structured clone operation encounters a shared memory object and cloning
+  // shared memory objects has not been enabled, the clone fails and an
+  // error is thrown.
+  //
+  // In the web embedding context, shared memory object cloning is disabled
+  // either because
+  //
+  //   1) *no* way of supporting it is available (because the
+  //      Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy HTTP
+  //      headers are not respected to force the page into its own process), or
+  //   2) the aforementioned HTTP headers don't specify that the page should be
+  //      opened in its own process.
+  //
+  // These two scenarios demand different error messages, and this option can be
+  // used to specify which scenario is in play.
+  //
+  // In the former case, if COOP/COEP support is not enabled, set this option to
+  // false.  (This is the default.)
+  //
+  // In the latter case, if COOP/COEP weren't used to force this page into its
+  // own process, set this option to true.
+  //
+  // (Embeddings that are not the web and do not wish to support structured
+  // cloning of shared memory objects will get a "bad" web-centric error message
+  // no matter what.  At present, SpiderMonkey does not offer a way for such
+  // embeddings to use an embedding-specific error message.)
   bool getCoopAndCoepEnabled() const;
   RealmCreationOptions& setCoopAndCoepEnabled(bool flag);
 
   bool getStreamsEnabled() const { return streams_; }
   RealmCreationOptions& setStreamsEnabled(bool flag) {
     streams_ = flag;
     return *this;
   }
@@ -211,16 +252,17 @@ class JS_PUBLIC_API RealmCreationOptions
     Zone* zone_;
   };
   uint64_t profilerRealmID_ = 0;
   bool invisibleToDebugger_ = false;
   bool mergeable_ = false;
   bool preserveJitCode_ = false;
   bool cloneSingletons_ = false;
   bool sharedMemoryAndAtomics_ = false;
+  bool defineSharedArrayBufferConstructor_ = true;
   bool coopAndCoep_ = false;
   bool streams_ = false;
   bool readableByteStreams_ = false;
   bool byobStreamReaders_ = false;
   bool writableStreams_ = false;
   bool readableStreamPipeTo_ = false;
   bool weakRefs_ = false;
   bool toSource_ = false;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -6632,16 +6632,27 @@ static bool NewGlobal(JSContext* cx, uns
     }
 
     if (!JS_GetProperty(cx, opts, "enableCoopAndCoep", &v)) {
       return false;
     }
     if (v.isBoolean()) {
       creationOptions.setCoopAndCoepEnabled(v.toBoolean());
     }
+
+    // On the web, the SharedArrayBuffer constructor is not installed as a
+    // global property in pages that aren't isolated in a separate process (and
+    // thus can't allow the structured cloning of shared memory).  Specify false
+    // for this option to reproduce this behavior.
+    if (!JS_GetProperty(cx, opts, "defineSharedArrayBufferConstructor", &v)) {
+      return false;
+    }
+    if (v.isBoolean()) {
+      creationOptions.setDefineSharedArrayBufferConstructor(v.toBoolean());
+    }
   }
 
   if (!CheckRealmOptions(cx, options, principals.get())) {
     return false;
   }
 
   RootedObject global(cx, NewGlobalObject(cx, options, principals.get(), kind));
   if (!global) {
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -366,19 +366,41 @@ bool GlobalObject::resolveConstructor(JS
   }
 
   if (!isObjectOrFunction) {
     // Any operations that modifies the global object should be placed
     // after any other fallible operations.
 
     // Fallible operation that modifies the global object.
     if (clasp->specShouldDefineConstructor()) {
-      RootedValue ctorValue(cx, ObjectValue(*ctor));
-      if (!DefineDataProperty(cx, global, id, ctorValue, JSPROP_RESOLVING)) {
-        return false;
+      bool shouldReallyDefine = true;
+
+      // On the web, it isn't presently possible to expose the global
+      // "SharedArrayBuffer" property unless the page is cross-site-isolated.
+      // Only define this constructor if an option on the realm indicates that
+      // it should be defined.
+      if (key == JSProto_SharedArrayBuffer) {
+        const JS::RealmCreationOptions& options =
+            cx->realm()->creationOptions();
+
+        MOZ_ASSERT(options.getSharedMemoryAndAtomicsEnabled(),
+                   "shouldn't be defining SharedArrayBuffer if shared memory "
+                   "is disabled");
+
+        fprintf(stderr, "defineSharedArrayBufferConstructor: %d\n",
+                static_cast<int>(options.defineSharedArrayBufferConstructor()));
+
+        shouldReallyDefine = options.defineSharedArrayBufferConstructor();
+      }
+
+      if (shouldReallyDefine) {
+        RootedValue ctorValue(cx, ObjectValue(*ctor));
+        if (!DefineDataProperty(cx, global, id, ctorValue, JSPROP_RESOLVING)) {
+          return false;
+        }
       }
     }
 
     // Infallible operations that modify the global object.
     global->setConstructor(key, ObjectValue(*ctor));
     if (proto) {
       global->setPrototype(key, ObjectValue(*proto));
     }