20

One of the limitation of JS that bugs me the most is the poor ability to isolate code's execution.

I want to be able to control the context in which the code is executed, Something that achieve a similar effect to what Script.createContext & Script.runInContext in node.js does (node is using binding to the V8 engine, so i can't emulate their implementation).

Here is the some reason why I want to isolate code execution:

  1. Isolate the code from the global namespace (the window object and the also the DOM) , but I however need to be able reference function call on objects exposed in the context which must be executed synchronous which makes it almost impossible using a WebWorker for isolation.
  2. By isolate the execution of code it would possible also be able to deallocate its definitions when no longer needed (memory management).

I know one may achieve partly isolated execution by loading script into a iframe, this approach is however very heavy and uses a lot memory for a second instance of the DOM which isn't needed for what I'm trying to do.

I need to share constructor definition and also definitions of object which are shared between the isolated containers/contexts which both must run on the main UI thread. Mainly i want to use these isolated containers to host plugins/modules (mini-applications) which each presents and dynamically updates a viewport by calling drawing commands on their own Context2D object.

If these containers are not running on the main UI thread it wold be painfully hard to proxy calls such as ctx.measureText() and ctx.drawImage() would be all useless as image objects can't be created in a Worker.

Does someone know of future specification that would make this possible?

Are there any current (hidden) browser-side APIs that could be used to achieve this?

Would it be better utilize a virtual machine like Goggle's Dart VM and also re-implement my current codebase? My current codebase is slightly above 20 000 lines of code.

Would it be better to re-implement the framework in *

Ry-
  • 218,210
  • 55
  • 464
  • 476
Raweden
  • 319
  • 2
  • 5
  • 4
    Do you have an *existing problem* that must be fixed like this? [IIABDFI](http://acronyms.thefreedictionary.com/IIABDFI). – Ry- Apr 29 '12 at 23:01
  • Agree with the comment, but downvote is a bit unnecessary. – Starx Apr 29 '12 at 23:06
  • @minitech I do actually have a problem with the lack of sandoxes (which is a better word for what i described above) in the browser runtime, due to i'm trying to achieve a plugin architecture for my client-side platform, which is written in JavaScript and utilizes the browser runtime for such. The platform is generic and it's main purpose is host the environment for dynamically loading and control plugins/modules/mini-application which provides the platform with additional features. – Raweden Jun 26 '12 at 18:05
  • @Raweden did you find a solution for your problem? I need to make something similar (third party plugins running in main, financial (yeah!) app) for cross platform use. Our top candidate now is ReactNative but the isolation feels like nightmarish impossible. (oh, 4 years later. oops.) – Giszmo Jun 21 '16 at 04:50

5 Answers5

3

You can isolate your code from the global namespace with a simple self executing function object:

(function() {
   // all your code goes here
   // nobody outside of your code can reach your top level variables here
   // your top level variables are not on the window object

   // this is a protected, but top level variable
   var x = 3;

   // if you want anything to be global, you can assign it to the window object.
   window.myGlobal = {};

   function myTopLevelFunction(x,y,z) {
       // code here
   }

})();

If you want to have multiple ones of these execution contexts and be able to share between them, then you will have to rendezvous via one publicly known location, either a truly global variable or a property on a known DOM object or something like that. It is relatively common to declare one global namespace object and use properties off that for any access to things you're sharing among modules. I know it isn't completely perfect, but it works. Here's an example of the rendevous using a single global namespace object:

// module AAA
(function() {
   // module AAA code goes here

   // set up global namespace object and whatever references we want to be global
   window.myModuleTop = window.myModuleTop || {};
   myModuleTop.AAA = {};
   myModuleTop.AAA.myFuncA = function() {};

})();


// module BBB
(function() {
   // module BBB code goes here

   // set up global namespace object and whatever references we want to be global
   window.myModuleTop = window.myModuleTop || {};
   myModuleTop.BBB = {};
   myModuleTop.BBB.myFuncB = function() {};

})();
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • I am not sure if this is the type of isolation OP is asking. _(But I am not sure I understand him too)_ – Starx Apr 29 '12 at 23:07
  • @Matt, I'm not trying to keep the OP's code from getting back to window. That's always easy. I'm trying to keep other people out of the OP's code and keep the OP's code isolated from other people's code. – jfriend00 Apr 29 '12 at 23:08
  • @jfriend00 yeah I think there's some confusion on what the OP is looking for – Matt Apr 29 '12 at 23:10
3

The closest library I've seen for this is Caja.

Basically, in non-strict javascript code, there are many ways to get access to the global object (window in browsers), making true isolation a very hard problem. Caja does some iframing trickery to patch this, but to be honest I'm not exactly sure how it works.

Matt
  • 43,482
  • 6
  • 101
  • 102
  • If you force strict mode, by doing something like evaling a script, can this be much easier? – B T Dec 10 '15 at 06:15
  • @BT `use strict` has certainly improved the situation, but there are still so many things you'd have to patch. It's far from a safe guarantee. For example, invoking setTimeout or similar things can be done on window implicitly, even if you override it: `(function(window) { 'use strict'; setTimeout(function() { console.log(this); }); }({}));` <- this will print the global window despite the lexical override – Matt Dec 10 '15 at 18:29
  • But by the same token, you could lexically override `setTimeout` just like you're doing for window for a more full result. – B T Dec 11 '15 at 23:41
  • @BT yep, but the point is there are so many ways to get global, no amount of lexical overrides should be considered secure. – Matt Dec 12 '15 at 22:38
  • Gotcha, I'm curious if you know where I could look to find all these unscrupulous ways to get to the global object. – B T Dec 12 '15 at 23:31
2

Couldn't you use a closure like other answers mentioned and then use a shadow dom to ensure that the user can't get to the rest of the dom? Something like this:

var containerNode = someDomNode
var root = containerNode.createShadowRoot()
;(function(root){
  var window = null, document = null, history = null,
      screen = null, navigator = null, location = null

  // isolated code goes here

})(root)

Caveats:

  • If you create other global objects outside the context of the isolated code, you need to explicitly shadow the variable like I did with window, document, etc, otherwise the isolated code will be to access it.
  • This won't work in browsers that don't have shadow dom obviously, unless your isolated code doesn't need to interact with the dom at all.
  • You have to be very careful that objects you do give the isolated code access to doesn't contain references to things you don't want it to have access to. Sometimes this is super error prone to do.
  • I'm making this suggestion because its plausible that it works, but I have no idea if there are additional ways to get to things like the window and document objects.
B T
  • 57,525
  • 34
  • 189
  • 207
1

Is "standard" namespacing an option? Like:

var myNamespace = {};

myNamespace.myFunc = function() { return true; }

This approach is the simplest I can think of and may be the solution to many problems. Although not a real sandbox, it can let the code less error prone.

rodrigoalvesvieira
  • 7,895
  • 15
  • 63
  • 84
1

There is a proposal for Realms API, which seems to solve similar problems. It is still under discussion, but there is already a polyfill for it - realms-shim.

Michael Radionov
  • 12,859
  • 1
  • 55
  • 72
  • It's important to note that Realms are not actually meant for running untrusted code. There appears to be another proposal https://github.com/tc39/proposal-compartments, but I'm not really sure to what extend this allows you to run untrusted code in a secure way. – Jespertheend Aug 10 '22 at 22:31