Search code examples
javascriptfirefoxfirefox-addonfirefox-addon-restartless

Firefox Bootstrapped Extensions: Namespace


I am looking into bootstrapped extensions. Looking at the code of some of those extensions, I see a lot of variables, constants & functions declarations.

Are they all declared in window object? Isn't there an issue with namespace pollution/clash?

I wrap every single thing in one object/namespace in the overlay extensions that I have done. Are bootstrapped extension different in that regard?

I have noticed that all bootstrapped.js use the same/standard function names. Does that mean that bootstrapped extensions are sandboxed or their scope enclosed?


Solution

  • The bootstrap.js scope

    Are they all declared in window object? Isn't there an issue with namespace pollution/clash?

    ...

    I have noticed that all bootstrapped.js use the same/standard function names. Does that mean that bootstrapped extensions are sandboxed or their scope enclosed?

    To expand on the @paa comment: bootstrap.js does indeed get it's own scope.

    The AddonManager will create a new scope (or "namespace" if you like) per bootstrap.js. Right now the implementation uses Components.utils.Sandbox, but that is an implementation detail.

    This means that there is no window object. bootstrap.js will be loaded once per Firefox process and has no window object. This is very much unlike overlay script which will be loaded once per new window and share a common scope (the window object itself) with Firefox code and overlay scripts from other add-ons.

    That also means bootstrapped add-ons are free to choose whatever names they like in their scope (their personal sand box) without fear of clashing with other add-ons, as long as the names are valid in Javascript in general.

    The only exceptions being

    • the entry point function names the add-on must implement that the Add-on Manager will call and therefore have special meaning (startup, shutdown, install, uninstall),
    • pre-defined stuff that either comes with the Sandbox (Components, and Javascript built-ins like Object, String, Array, Map, etc.)
    • stuff that the AddonManager will inject (like the __SCRIPT_URI_SPEC__, ADDON_*, APP_* constants).

    A full list of pre-defined names, as of Firefox 30:

    Components.utils.reportError(Object.getOwnPropertyNames(this).join(", "));
    
    // Object, Function, eval, Components, XPCNativeWrapper, dump, debug,
    // importFunction, IDBCursor, IDBCursorWithValue, EventTarget, IDBDatabase,
    // IDBFactory, FileHandle, IDBFileHandle, IDBIndex, IDBKeyRange,
    // IDBObjectStore, IDBRequest, IDBOpenDBRequest, IDBTransaction, Event,
    // IDBVersionChangeEvent, indexedDB, APP_STARTUP, APP_SHUTDOWN, ADDON_ENABLE,
    // ADDON_DISABLE, ADDON_INSTALL, ADDON_UNINSTALL, ADDON_UPGRADE,
    // ADDON_DOWNGRADE, Worker, ChromeWorker, __SCRIPT_URI_SPEC__, undefined,
    // Array, Boolean, JSON, Date, Math, isNaN, isFinite, parseFloat, parseInt,
    // NaN, Infinity, Number, String, escape, unescape, uneval, decodeURI,
    // encodeURI, decodeURIComponent, encodeURIComponent, RegExp, Error,
    // InternalError, EvalError, RangeError, ReferenceError, SyntaxError,
    // TypeError, URIError, Iterator, StopIteration, Int8Array, Uint8Array,
    // Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array,
    // Float64Array, Uint8ClampedArray, DataView, ArrayBuffer, Proxy, WeakMap,
    // Map, Set, Intl
    

    Manipulating other scopes

    However, bootstrapped add-on still need to be considerate and avoid clashes when interacting with other scopes, such as windows, JS code modules, other add-on bootstrap scopes and so on. Manipulating other scopes may also cause leaks of the add-on bootstrap scope.

    E.g.

    Cu.import("resource://gre/modules/Services.jsm");
    Services.foo = "bar";
    

    This will add a foo property to the Services object that lives in the shared Services.jsm code module. All other add-ons and the browser code will see Services.foo as well, so it might cause clashes and regular don't pollute the shared namespace-rules apply.

    Also, when your add-on gets shutdown you'd have to delete Services.foo again, or else the Services.jsm scope would keep a reference to it and since the value of foo (the string "bar") lives within your bootstrap compartment, it would keep alive your bootstrap compartment due to that reference and effectively create a memory leak otherwise (called Zombie compartments in mozilla slang).

    Or

    // Get the most recent browser window
    var browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
    browserWindow.doSomething = function() {
      browserWindow.alert("hello world");
    };
    

    This would be equivalent to having an overlay script of:

    function doSomething() {
      alert("hello world");
    }
    

    Both would add a new name doSomething to the browser window scope, hence that name might clash with other add-ons and don't pollute the shared namespace-rules apply. And again, this might leak the same way than the previous example, so a bootstrapped add-on will have to delete the property on shutdown again to avoid that.