Alternative to Mozilla's eval in a scope

# Andy Chu (15 years ago)

I'm writing a JavaScript program ("server-side") that loads plugins written in JS. I would like to prevent the plugins from messing with my program, and from Googling around I found this:

ejohn.org/blog/eval-kerfuffle

So basically Firefox briefly had a second "scope" argument to eval, until it became clear that it broke some isolation that people were expecting, so it was removed.

Is anything like this being discussed for Harmony? I didn't see anything in ES5 that addresses this, and I think the original motivation was good.

How about something like this instead:

There is a function called "loadCode" for now, that behaves a little bit like eval:

var code = loadCode("var foo=3; var bar = function(a) { fn(a) };", {fn: obj.fn});

// code is now {foo: 3, bar: function(a) ...}

So the second argument is an object that lists all the names available. The return value is an object of names that were defined in the string.

Since obj.fn.a was not accessible in the original context, fn.a is not available in the loadCode'd context.

This is much like Python's eval("a=3", {"builtins": {}, "json": json}), except in JS eval() executes statements. And note in Python you can control builtins, which contains the equivalent of things like Array, Object, etc.

I've been writing code against Narwhal, which implement CommonJS modules. Narwhal uses a nice trick to execute modules in namespaces, but there's still no getting around the fact that "foo = 3;" (forgetting the "var") creates a global. I know ES5 strict mode addressed this, but it would be nice to also have a loadCode() that prevents this even for non-strict code.

With most JS engines (v8, Rhino) I think this is fairly easily to implement, as they all have some notion of execution contexts. But it would be nice to have an engine-dependent way of doing it, by having it in JS itself. Also I think this is fairly similar to what's required to implement web workers.

I just started reading the group and haven't been able to find any related discussion e.g. here: strawman:strawman

thanks, Andy

# ihab.awad at gmail.com (15 years ago)

On Sun, Dec 13, 2009 at 9:49 PM, Andy Chu <andy at chubot.org> wrote:

There is a function called "loadCode" for now, that behaves a little bit like eval:

var code = loadCode("var foo=3; var bar = function(a) { fn(a) };", {fn: obj.fn});

// code is now {foo: 3, bar: function(a) ...}

Where is this loadCode function implemented? Is this something you wrote yourself?

In the Caja project, our "isolated evaluator" is implemented to return the value of the last ExpressionStatement in the code. In other words, the loaded code is more easily able to defend its own integrity since its top-level vars are private to it.

Ihab

# Andy Chu (15 years ago)

On Sun, Dec 13, 2009 at 9:56 PM, <ihab.awad at gmail.com> wrote:

Hi Andy,

On Sun, Dec 13, 2009 at 9:49 PM, Andy Chu <andy at chubot.org> wrote:

There is a function called "loadCode" for now, that behaves a little bit like eval:

var code = loadCode("var foo=3; var bar = function(a) { fn(a) };", {fn: obj.fn});

// code is now {foo: 3, bar: function(a) ...}

Where is this loadCode function implemented? Is this something you wrote yourself?

I was just imagining what I would want the API to look like (after unsatisfactorily hacking the plugins in ES3). I've done similar things in Python, which is fairly close to those semantics. I don't expect that it would be very hard to do a demo of this say in v8.

If Caja has already done something along these lines then awesome -- I'm just asking if there is discussion about standardizing such a thing.

It seems like a pretty useful primitive to have. In a way it's a bit lower level than a module system. You could implement a module system on top of that (I think CommonJS modules), and without knowing too much it looks like part of Web Workers could be defined in those terms (e.g. one context needs to be able to call the onmessage() function in another context).

I'm sure there are all sorts of details, e.g. around primordials, and defining exactly what kind of isolation is the goal (isolating builtins: None in Python is not safe because you can still traverse the object graph of a literal: "{}.class.subclasses" etc.).

In the Caja project, our "isolated evaluator" is implemented to return the value of the last ExpressionStatement in the code. In other words, the loaded code is more easily able to defend its own integrity since its top-level vars are private to it.

Where is this documented? I've looked at the Caja site but don't see it.

I see the point about keeping top level vars private -- that's definitely desirable. Though there are many possible mechanisms for keeping some variables private.

Random thought: It may be interesting to have another argument that specifies what kind of code is allowed:

loadCode("var a...", {}, "es5-strict"); loadCode("var a...", {}, "es3"); loadCode("var a...", {}, "caja");

thanks, Andy

# ihab.awad at gmail.com (15 years ago)

On Sun, Dec 13, 2009 at 10:17 PM, Andy Chu <andy at chubot.org> wrote:

If Caja has already done something along these lines then awesome -- I'm just asking if there is discussion about standardizing such a thing.

Kris Kowal coined the term "hermetic eval" to describe what you are talking about.

You could implement a module system on top of that ...

That's the idea. :)

In the Caja project, our "isolated evaluator" is implemented to return the value of the last ExpressionStatement in the code. In other words, the loaded code is more easily able to defend its own integrity since its top-level vars are private to it.

Where is this documented?  I've looked at the Caja site but don't see it.

Unfortunately, the Caja module system is not well documented right now. We have not deployed it widely yet since none of our immediate customers need it. But I hope we can make it more popular, perhaps on the heels of an ES-Harmony proposal....

# Andy Chu (15 years ago)

On Sun, Dec 13, 2009 at 10:23 PM, <ihab.awad at gmail.com> wrote:

On Sun, Dec 13, 2009 at 10:17 PM, Andy Chu <andy at chubot.org> wrote:

If Caja has already done something along these lines then awesome -- I'm just asking if there is discussion about standardizing such a thing.

Kris Kowal coined the term "hermetic eval" to describe what you are talking about.

Well I fully support that then, except I don't know exactly what is proposed : ) I see some stuff in your slides docs.google.com/present/view?hl=en&id=dcd8d5dk_0cs639jg8 but no definition of hermeticEval.

Found this thread but not much discussion: esdiscuss/2009-September/010009

strawman:modules

You could implement a module system on top of that ...

That's the idea. :)

I like what Kris said in that thread, that just having hermetic eval is the important part. It's mechanism vs. policy -- a module system has a ton of policy, but hermetic eval is the mechanism.

I just want to implement a simple "plugin" system. This is very much like modules but distinct in that there is no "require" -- you don't have the capability to import other modules.

So I think there can be many variations of usage for hermetic eval and it shouldn't be tied to a module system.

thanks, Andy