tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RealmOptions.h (13999B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /*
      8 * Options specified when creating a realm to determine its behavior, immutable
      9 * options determining the behavior of an existing realm, and mutable options on
     10 * an existing realm that may be changed when desired.
     11 */
     12 
     13 #ifndef js_RealmOptions_h
     14 #define js_RealmOptions_h
     15 
     16 #include "mozilla/Assertions.h"  // MOZ_ASSERT
     17 #include "mozilla/Maybe.h"
     18 
     19 #include "jstypes.h"  // JS_PUBLIC_API
     20 
     21 #include "js/Class.h"  // JSTraceOp
     22 #include "js/RefCounted.h"
     23 
     24 struct JS_PUBLIC_API JSContext;
     25 class JS_PUBLIC_API JSObject;
     26 
     27 namespace JS {
     28 
     29 class JS_PUBLIC_API Compartment;
     30 class JS_PUBLIC_API Realm;
     31 class JS_PUBLIC_API Zone;
     32 
     33 }  // namespace JS
     34 
     35 namespace JS {
     36 
     37 /**
     38 * Specification for which compartment/zone a newly created realm should use.
     39 */
     40 enum class CompartmentSpecifier {
     41  // Create a new realm and compartment in the single runtime wide system
     42  // zone. The meaning of this zone is left to the embedder.
     43  NewCompartmentInSystemZone,
     44 
     45  // Create a new realm and compartment in a particular existing zone.
     46  NewCompartmentInExistingZone,
     47 
     48  // Create a new zone/compartment.
     49  NewCompartmentAndZone,
     50 
     51  // Create a new realm in an existing compartment.
     52  ExistingCompartment,
     53 };
     54 
     55 struct LocaleString : js::RefCounted<LocaleString> {
     56  const char* chars_;
     57 
     58  explicit LocaleString(const char* chars) : chars_(chars) {}
     59 
     60  auto* chars() const { return chars_; }
     61 };
     62 
     63 struct TimeZoneString : js::RefCounted<TimeZoneString> {
     64  const char* chars_;
     65 
     66  explicit TimeZoneString(const char* chars) : chars_(chars) {}
     67 
     68  auto* chars() const { return chars_; }
     69 };
     70 
     71 /**
     72 * RealmCreationOptions specifies options relevant to creating a new realm, that
     73 * are either immutable characteristics of that realm or that are discarded
     74 * after the realm has been created.
     75 *
     76 * Access to these options on an existing realm is read-only: if you need
     77 * particular selections, you must make them before you create the realm.
     78 */
     79 class JS_PUBLIC_API RealmCreationOptions {
     80 public:
     81  RealmCreationOptions() : comp_(nullptr) {}
     82 
     83  JSTraceOp getTrace() const { return traceGlobal_; }
     84  RealmCreationOptions& setTrace(JSTraceOp op) {
     85    traceGlobal_ = op;
     86    return *this;
     87  }
     88 
     89  Zone* zone() const {
     90    MOZ_ASSERT(compSpec_ == CompartmentSpecifier::NewCompartmentInExistingZone);
     91    return zone_;
     92  }
     93  Compartment* compartment() const {
     94    MOZ_ASSERT(compSpec_ == CompartmentSpecifier::ExistingCompartment);
     95    return comp_;
     96  }
     97  CompartmentSpecifier compartmentSpecifier() const { return compSpec_; }
     98 
     99  // Set the compartment/zone to use for the realm. See CompartmentSpecifier
    100  // above.
    101  RealmCreationOptions& setNewCompartmentInSystemZone();
    102  RealmCreationOptions& setNewCompartmentInExistingZone(JSObject* obj);
    103  RealmCreationOptions& setNewCompartmentAndZone();
    104  RealmCreationOptions& setExistingCompartment(JSObject* obj);
    105  RealmCreationOptions& setExistingCompartment(Compartment* compartment);
    106 
    107  // Certain compartments are implementation details of the embedding, and
    108  // references to them should never leak out to script. This flag causes this
    109  // realm to skip firing onNewGlobalObject and makes addDebuggee a no-op for
    110  // this global.
    111  //
    112  // Debugger visibility is per-compartment, not per-realm (it's only practical
    113  // to enforce visibility on compartment boundaries), so if a realm is being
    114  // created in an extant compartment, its requested visibility must match that
    115  // of the compartment.
    116  bool invisibleToDebugger() const { return invisibleToDebugger_; }
    117  RealmCreationOptions& setInvisibleToDebugger(bool flag) {
    118    invisibleToDebugger_ = flag;
    119    return *this;
    120  }
    121 
    122  // Determines whether this realm should preserve JIT code on non-shrinking
    123  // GCs.
    124  //
    125  // Useful for embedders who know their code is relatively stable. See
    126  // Bug 1068697 for motivation.
    127  //
    128  // This is a hint not a guarantee and can be overriden by other heuristics in
    129  // the engine.
    130  bool preserveJitCode() const { return preserveJitCode_; }
    131  RealmCreationOptions& setPreserveJitCode(bool flag) {
    132    preserveJitCode_ = flag;
    133    return *this;
    134  }
    135 
    136  // Determines whether 1) the global Atomic property is defined and atomic
    137  // operations are supported, and 2) whether shared-memory operations are
    138  // supported.
    139  bool getSharedMemoryAndAtomicsEnabled() const;
    140  RealmCreationOptions& setSharedMemoryAndAtomicsEnabled(bool flag);
    141 
    142  // Determines (if getSharedMemoryAndAtomicsEnabled() is true) whether the
    143  // global SharedArrayBuffer property is defined.  If the property is not
    144  // defined, shared array buffer functionality can only be invoked if the
    145  // host/embedding specifically acts to expose it.
    146  //
    147  // This option defaults to true: embeddings unable to tolerate a global
    148  // SharedAraryBuffer property must opt out of it.
    149  bool defineSharedArrayBufferConstructor() const {
    150    return defineSharedArrayBufferConstructor_;
    151  }
    152  RealmCreationOptions& setDefineSharedArrayBufferConstructor(bool flag) {
    153    defineSharedArrayBufferConstructor_ = flag;
    154    return *this;
    155  }
    156 
    157  // Structured clone operations support the cloning of shared memory objects
    158  // (SharedArrayBuffer or or a shared WASM Memory object) *optionally* -- at
    159  // the discretion of the embedder code that performs the cloning.  When a
    160  // structured clone operation encounters a shared memory object and cloning
    161  // shared memory objects has not been enabled, the clone fails and an
    162  // error is thrown.
    163  //
    164  // In the web embedding context, shared memory object cloning is disabled
    165  // either because
    166  //
    167  //   1) *no* way of supporting it is available (because the
    168  //      Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy HTTP
    169  //      headers are not respected to force the page into its own process), or
    170  //   2) the aforementioned HTTP headers don't specify that the page should be
    171  //      opened in its own process.
    172  //
    173  // These two scenarios demand different error messages, and this option can be
    174  // used to specify which scenario is in play.
    175  //
    176  // In the former case, if COOP/COEP support is not enabled, set this option to
    177  // false.  (This is the default.)
    178  //
    179  // In the latter case, if COOP/COEP weren't used to force this page into its
    180  // own process, set this option to true.
    181  //
    182  // (Embeddings that are not the web and do not wish to support structured
    183  // cloning of shared memory objects will get a "bad" web-centric error message
    184  // no matter what.  At present, SpiderMonkey does not offer a way for such
    185  // embeddings to use an embedding-specific error message.)
    186  bool getCoopAndCoepEnabled() const;
    187  RealmCreationOptions& setCoopAndCoepEnabled(bool flag);
    188 
    189  bool getToSourceEnabled() const { return toSource_; }
    190  RealmCreationOptions& setToSourceEnabled(bool flag) {
    191    toSource_ = flag;
    192    return *this;
    193  }
    194 
    195  // This flag doesn't affect JS engine behavior.  It is used by Gecko to
    196  // mark whether content windows and workers are "Secure Context"s. See
    197  // https://w3c.github.io/webappsec-secure-contexts/
    198  // https://bugzilla.mozilla.org/show_bug.cgi?id=1162772#c34
    199  bool secureContext() const { return secureContext_; }
    200  RealmCreationOptions& setSecureContext(bool flag) {
    201    secureContext_ = flag;
    202    return *this;
    203  }
    204 
    205  // Non-standard option to freeze certain builtin constructors and seal their
    206  // prototypes. Also defines these constructors on the global as non-writable
    207  // and non-configurable.
    208  bool freezeBuiltins() const { return freezeBuiltins_; }
    209  RealmCreationOptions& setFreezeBuiltins(bool flag) {
    210    freezeBuiltins_ = flag;
    211    return *this;
    212  }
    213 
    214  // Always use the fdlibm implementation of math functions instead of the
    215  // platform native libc implementations. Useful for fingerprinting protection
    216  // and cross-platform consistency.
    217  bool alwaysUseFdlibm() const { return alwaysUseFdlibm_; }
    218  RealmCreationOptions& setAlwaysUseFdlibm(bool flag) {
    219    alwaysUseFdlibm_ = flag;
    220    return *this;
    221  }
    222 
    223  uint64_t profilerRealmID() const { return profilerRealmID_; }
    224  RealmCreationOptions& setProfilerRealmID(uint64_t id) {
    225    profilerRealmID_ = id;
    226    return *this;
    227  }
    228 
    229 private:
    230  JSTraceOp traceGlobal_ = nullptr;
    231  CompartmentSpecifier compSpec_ = CompartmentSpecifier::NewCompartmentAndZone;
    232  union {
    233    Compartment* comp_;
    234    Zone* zone_;
    235  };
    236  uint64_t profilerRealmID_ = 0;
    237  bool invisibleToDebugger_ = false;
    238  bool preserveJitCode_ = false;
    239  bool sharedMemoryAndAtomics_ = false;
    240  bool defineSharedArrayBufferConstructor_ = true;
    241  bool coopAndCoep_ = false;
    242  bool toSource_ = false;
    243 
    244  bool secureContext_ = false;
    245  bool freezeBuiltins_ = false;
    246  bool alwaysUseFdlibm_ = false;
    247 };
    248 
    249 // This is a wrapper for mozilla::RTPCallerType, that can't easily
    250 // be exposed to the JS engine for layering reasons.
    251 struct RTPCallerTypeToken {
    252  uint8_t value;
    253 };
    254 
    255 /**
    256 * RealmBehaviors specifies behaviors of a realm that can be changed after the
    257 * realm's been created.
    258 */
    259 class JS_PUBLIC_API RealmBehaviors {
    260 public:
    261  RealmBehaviors() = default;
    262 
    263  // When a JS::ReduceMicrosecondTimePrecisionCallback callback is defined via
    264  // JS::SetReduceMicrosecondTimePrecisionCallback, a JS::RTPCallerTypeToken (a
    265  // wrapper for mozilla::RTPCallerType) needs to be set for every Realm.
    266  mozilla::Maybe<RTPCallerTypeToken> reduceTimerPrecisionCallerType() const {
    267    return rtpCallerType;
    268  }
    269  RealmBehaviors& setReduceTimerPrecisionCallerType(RTPCallerTypeToken type) {
    270    rtpCallerType = mozilla::Some(type);
    271    return *this;
    272  }
    273 
    274  // For certain globals, we know enough about the code that will run in them
    275  // that we can discard script source entirely.
    276  bool discardSource() const { return discardSource_; }
    277  RealmBehaviors& setDiscardSource(bool flag) {
    278    discardSource_ = flag;
    279    return *this;
    280  }
    281 
    282  bool clampAndJitterTime() const { return clampAndJitterTime_; }
    283  RealmBehaviors& setClampAndJitterTime(bool flag) {
    284    clampAndJitterTime_ = flag;
    285    return *this;
    286  }
    287 
    288  // A Realm can stop being "live" in all the ways that matter before its global
    289  // is actually GCed.  Consumers that tear down parts of a Realm or its global
    290  // before that point should set isNonLive accordingly.
    291  bool isNonLive() const { return isNonLive_; }
    292  RealmBehaviors& setNonLive() {
    293    isNonLive_ = true;
    294    return *this;
    295  }
    296 
    297  // Change the realm's current locale to a different value than the system
    298  // default locale. The locale must be a valid BCP-47 locale identifier which
    299  // is supported by ICU otherwise this option will be ignored and the
    300  // last-ditch locale "en-GB" will be used!
    301  //
    302  // Any Unicode extension sequences are ignored.
    303  //
    304  // https://w3c.github.io/webdriver-bidi/#command-emulation-setLocaleOverride
    305  RefPtr<LocaleString> localeOverride() const { return localeOverride_; }
    306  RealmBehaviors& setLocaleOverride(const char* locale);
    307 
    308  // Change the realm's current time zone to a different value than the system
    309  // default time zone. The time zone must be a valid IANA time zone identifier,
    310  // otherwise this option will be ignored and the system default time zone will
    311  // be used!
    312  //
    313  // https://w3c.github.io/webdriver-bidi/#command-emulation-setTimezoneOverride
    314  RefPtr<TimeZoneString> timeZoneOverride() const { return timeZoneOverride_; }
    315  RealmBehaviors& setTimeZoneOverride(const char* timeZone);
    316 
    317 private:
    318  RefPtr<LocaleString> localeOverride_;
    319  RefPtr<TimeZoneString> timeZoneOverride_;
    320  mozilla::Maybe<RTPCallerTypeToken> rtpCallerType;
    321  bool discardSource_ = false;
    322  bool clampAndJitterTime_ = true;
    323  bool isNonLive_ = false;
    324 };
    325 
    326 /**
    327 * RealmOptions specifies realm characteristics: both those that can't be
    328 * changed on a realm once it's been created (RealmCreationOptions), and those
    329 * that can be changed on an existing realm (RealmBehaviors).
    330 */
    331 class JS_PUBLIC_API RealmOptions {
    332 public:
    333  explicit RealmOptions() : creationOptions_(), behaviors_() {}
    334 
    335  RealmOptions(const RealmCreationOptions& realmCreation,
    336               const RealmBehaviors& realmBehaviors)
    337      : creationOptions_(realmCreation), behaviors_(realmBehaviors) {}
    338 
    339  // RealmCreationOptions specify fundamental realm characteristics that must
    340  // be specified when the realm is created, that can't be changed after the
    341  // realm is created.
    342  RealmCreationOptions& creationOptions() { return creationOptions_; }
    343  const RealmCreationOptions& creationOptions() const {
    344    return creationOptions_;
    345  }
    346 
    347  // RealmBehaviors specify realm characteristics that can be changed after
    348  // the realm is created.
    349  RealmBehaviors& behaviors() { return behaviors_; }
    350  const RealmBehaviors& behaviors() const { return behaviors_; }
    351 
    352 private:
    353  RealmCreationOptions creationOptions_;
    354  RealmBehaviors behaviors_;
    355 };
    356 
    357 extern JS_PUBLIC_API const RealmCreationOptions& RealmCreationOptionsRef(
    358    Realm* realm);
    359 
    360 extern JS_PUBLIC_API const RealmCreationOptions& RealmCreationOptionsRef(
    361    JSContext* cx);
    362 
    363 extern JS_PUBLIC_API const RealmBehaviors& RealmBehaviorsRef(Realm* realm);
    364 
    365 extern JS_PUBLIC_API const RealmBehaviors& RealmBehaviorsRef(JSContext* cx);
    366 
    367 extern JS_PUBLIC_API void SetRealmLocaleOverride(Realm* realm,
    368                                                 const char* locale);
    369 
    370 extern JS_PUBLIC_API void SetRealmTimezoneOverride(Realm* realm,
    371                                                   const char* timezone);
    372 
    373 extern JS_PUBLIC_API void SetRealmNonLive(Realm* realm);
    374 
    375 // This behaves like RealmBehaviors::setReduceTimerPrecisionCallerType, but
    376 // can be used even after the Realm has already been created.
    377 extern JS_PUBLIC_API void SetRealmReduceTimerPrecisionCallerType(
    378    Realm* realm, RTPCallerTypeToken type);
    379 
    380 }  // namespace JS
    381 
    382 #endif  // js_RealmOptions_h